xref: /linux/arch/arc/mm/cache.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28362c389SVineet Gupta /*
38ea2ddffSVineet Gupta  * ARC Cache Management
48362c389SVineet Gupta  *
58ea2ddffSVineet Gupta  * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
68362c389SVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
78362c389SVineet Gupta  */
88362c389SVineet Gupta 
98362c389SVineet Gupta #include <linux/module.h>
108362c389SVineet Gupta #include <linux/mm.h>
118362c389SVineet Gupta #include <linux/sched.h>
128362c389SVineet Gupta #include <linux/cache.h>
138362c389SVineet Gupta #include <linux/mmu_context.h>
148362c389SVineet Gupta #include <linux/syscalls.h>
158362c389SVineet Gupta #include <linux/uaccess.h>
168362c389SVineet Gupta #include <linux/pagemap.h>
178362c389SVineet Gupta #include <asm/cacheflush.h>
188362c389SVineet Gupta #include <asm/cachectl.h>
198362c389SVineet Gupta #include <asm/setup.h>
208362c389SVineet Gupta 
210d77117fSVineet Gupta #ifdef CONFIG_ISA_ARCV2
220d77117fSVineet Gupta #define USE_RGN_FLSH	1
230d77117fSVineet Gupta #endif
240d77117fSVineet Gupta 
25795f4558SVineet Gupta static int l2_line_sz;
26cf986d47SVineet Gupta static int ioc_exists;
27d0e73e2aSVineet Gupta int slc_enable = 1, ioc_enable = 1;
28deaf7565SVineet Gupta unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */
2926c01c49SVineet Gupta unsigned long perip_end = 0xFFFFFFFF; /* legacy value */
30795f4558SVineet Gupta 
3117a5ed56SVineet Gupta static struct cpuinfo_arc_cache {
3217a5ed56SVineet Gupta 	unsigned int sz_k, line_len, colors;
3317a5ed56SVineet Gupta } ic_info, dc_info, slc_info;
3417a5ed56SVineet Gupta 
3528b4af72SVineet Gupta void (*_cache_line_loop_ic_fn)(phys_addr_t paddr, unsigned long vaddr,
367d3d162bSVineet Gupta 			       unsigned long sz, const int op, const int full_page);
37bcc4d65aSVineet Gupta 
38f5db19e9SVineet Gupta void (*__dma_cache_wback_inv)(phys_addr_t start, unsigned long sz);
39f5db19e9SVineet Gupta void (*__dma_cache_inv)(phys_addr_t start, unsigned long sz);
40f5db19e9SVineet Gupta void (*__dma_cache_wback)(phys_addr_t start, unsigned long sz);
41f2b0b25aSAlexey Brodkin 
read_decode_cache_bcr_arcv2(int c,char * buf,int len)42fad84e39SVineet Gupta static int read_decode_cache_bcr_arcv2(int c, char *buf, int len)
438362c389SVineet Gupta {
4417a5ed56SVineet Gupta 	struct cpuinfo_arc_cache *p_slc = &slc_info;
4517a5ed56SVineet Gupta 	struct bcr_identity ident;
46d1f317d8SVineet Gupta 	struct bcr_generic sbcr;
4717a5ed56SVineet Gupta 	struct bcr_clust_cfg cbcr;
4817a5ed56SVineet Gupta 	struct bcr_volatile vol;
4917a5ed56SVineet Gupta 	int n = 0;
5026c01c49SVineet Gupta 
51fd0881a2SVineet Gupta 	READ_BCR(ARC_REG_SLC_BCR, sbcr);
52fd0881a2SVineet Gupta 	if (sbcr.ver) {
5317a5ed56SVineet Gupta 		struct bcr_slc_cfg  slc_cfg;
54fd0881a2SVineet Gupta 		READ_BCR(ARC_REG_SLC_CFG, slc_cfg);
55fd0881a2SVineet Gupta 		p_slc->sz_k = 128 << slc_cfg.sz;
56fd0881a2SVineet Gupta 		l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64;
5717a5ed56SVineet Gupta 		n += scnprintf(buf + n, len - n,
5817a5ed56SVineet Gupta 			       "SLC\t\t: %uK, %uB Line%s\n",
5917a5ed56SVineet Gupta 			       p_slc->sz_k, p_slc->line_len, IS_USED_RUN(slc_enable));
60fd0881a2SVineet Gupta 	}
61fd0881a2SVineet Gupta 
62fd0881a2SVineet Gupta 	READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
6399bd5fccSVineet Gupta 	if (cbcr.c) {
64fd0881a2SVineet Gupta 		ioc_exists = 1;
6599bd5fccSVineet Gupta 
6699bd5fccSVineet Gupta 		/*
6799bd5fccSVineet Gupta 		 * As for today we don't support both IOC and ZONE_HIGHMEM enabled
6899bd5fccSVineet Gupta 		 * simultaneously. This happens because as of today IOC aperture covers
6999bd5fccSVineet Gupta 		 * only ZONE_NORMAL (low mem) and any dma transactions outside this
7099bd5fccSVineet Gupta 		 * region won't be HW coherent.
7199bd5fccSVineet Gupta 		 * If we want to use both IOC and ZONE_HIGHMEM we can use
7299bd5fccSVineet Gupta 		 * bounce_buffer to handle dma transactions to HIGHMEM.
7399bd5fccSVineet Gupta 		 * Also it is possible to modify dma_direct cache ops or increase IOC
7499bd5fccSVineet Gupta 		 * aperture size if we are planning to use HIGHMEM without PAE.
7599bd5fccSVineet Gupta 		 */
7699bd5fccSVineet Gupta 		if (IS_ENABLED(CONFIG_HIGHMEM) || is_pae40_enabled())
77cf986d47SVineet Gupta 			ioc_enable = 0;
7899bd5fccSVineet Gupta 	} else {
7999bd5fccSVineet Gupta 		ioc_enable = 0;
8099bd5fccSVineet Gupta 	}
81deaf7565SVineet Gupta 
8217a5ed56SVineet Gupta 	READ_BCR(AUX_IDENTITY, ident);
8317a5ed56SVineet Gupta 
8426c01c49SVineet Gupta 	/* HS 2.0 didn't have AUX_VOL */
8517a5ed56SVineet Gupta 	if (ident.family > 0x51) {
8626c01c49SVineet Gupta 		READ_BCR(AUX_VOL, vol);
8726c01c49SVineet Gupta 		perip_base = vol.start << 28;
8826c01c49SVineet Gupta 		/* HS 3.0 has limit and strict-ordering fields */
8917a5ed56SVineet Gupta 		if (ident.family > 0x52)
9026c01c49SVineet Gupta 			perip_end = (vol.limit << 28) - 1;
9126c01c49SVineet Gupta 	}
9217a5ed56SVineet Gupta 
9317a5ed56SVineet Gupta 	n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
9417a5ed56SVineet Gupta 		       perip_base,
9517a5ed56SVineet Gupta 		       IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency (per-device) "));
9617a5ed56SVineet Gupta 
97fad84e39SVineet Gupta 	return n;
98fd0881a2SVineet Gupta }
99fd0881a2SVineet Gupta 
arc_cache_mumbojumbo(int c,char * buf,int len)100fad84e39SVineet Gupta int arc_cache_mumbojumbo(int c, char *buf, int len)
101fd0881a2SVineet Gupta {
10217a5ed56SVineet Gupta 	struct cpuinfo_arc_cache *p_ic = &ic_info, *p_dc = &dc_info;
10317a5ed56SVineet Gupta 	struct bcr_cache ibcr, dbcr;
10417a5ed56SVineet Gupta 	int vipt, assoc;
10517a5ed56SVineet Gupta 	int n = 0;
106fd0881a2SVineet Gupta 
1078362c389SVineet Gupta 	READ_BCR(ARC_REG_IC_BCR, ibcr);
1088362c389SVineet Gupta 	if (!ibcr.ver)
1098362c389SVineet Gupta 		goto dc_chk;
1108362c389SVineet Gupta 
11117a5ed56SVineet Gupta 	if (is_isa_arcompact() && (ibcr.ver <= 3)) {
1128362c389SVineet Gupta 		BUG_ON(ibcr.config != 3);
11317a5ed56SVineet Gupta 		assoc = 2;		/* Fixed to 2w set assoc */
11417a5ed56SVineet Gupta 	} else if (is_isa_arcv2() && (ibcr.ver >= 4)) {
11517a5ed56SVineet Gupta 		assoc = 1 << ibcr.config;	/* 1,2,4,8 */
116d1f317d8SVineet Gupta 	}
117d1f317d8SVineet Gupta 
1188362c389SVineet Gupta 	p_ic->line_len = 8 << ibcr.line_len;
1198362c389SVineet Gupta 	p_ic->sz_k = 1 << (ibcr.sz - 1);
12017a5ed56SVineet Gupta 	p_ic->colors = p_ic->sz_k/assoc/TO_KB(PAGE_SIZE);
12117a5ed56SVineet Gupta 
12217a5ed56SVineet Gupta 	n += scnprintf(buf + n, len - n,
12317a5ed56SVineet Gupta 			"I-Cache\t\t: %uK, %dway/set, %uB Line, VIPT%s%s\n",
12417a5ed56SVineet Gupta 			p_ic->sz_k, assoc, p_ic->line_len,
12517a5ed56SVineet Gupta 			p_ic->colors > 1 ? " aliasing" : "",
12617a5ed56SVineet Gupta 			IS_USED_CFG(CONFIG_ARC_HAS_ICACHE));
1278362c389SVineet Gupta 
1288362c389SVineet Gupta dc_chk:
1298362c389SVineet Gupta 	READ_BCR(ARC_REG_DC_BCR, dbcr);
1308362c389SVineet Gupta 	if (!dbcr.ver)
131d1f317d8SVineet Gupta 		goto slc_chk;
1328362c389SVineet Gupta 
13317a5ed56SVineet Gupta 	if (is_isa_arcompact() && (dbcr.ver <= 3)) {
1348362c389SVineet Gupta 		BUG_ON(dbcr.config != 2);
13517a5ed56SVineet Gupta 		vipt = 1;
13617a5ed56SVineet Gupta 		assoc = 4;		/* Fixed to 4w set assoc */
13717a5ed56SVineet Gupta 		p_dc->colors = p_dc->sz_k/assoc/TO_KB(PAGE_SIZE);
13817a5ed56SVineet Gupta 	} else if (is_isa_arcv2() && (dbcr.ver >= 4)) {
13917a5ed56SVineet Gupta 		vipt = 0;
14017a5ed56SVineet Gupta 		assoc = 1 << dbcr.config;	/* 1,2,4,8 */
14117a5ed56SVineet Gupta 		p_dc->colors = 1;		/* PIPT so can't VIPT alias */
142d1f317d8SVineet Gupta 	}
143d1f317d8SVineet Gupta 
1448362c389SVineet Gupta 	p_dc->line_len = 16 << dbcr.line_len;
1458362c389SVineet Gupta 	p_dc->sz_k = 1 << (dbcr.sz - 1);
146d1f317d8SVineet Gupta 
14717a5ed56SVineet Gupta 	n += scnprintf(buf + n, len - n,
148*6732c0e4SVineet Gupta 			"D-Cache\t\t: %uK, %dway/set, %uB Line, %s%s\n",
14917a5ed56SVineet Gupta 			p_dc->sz_k, assoc, p_dc->line_len,
15017a5ed56SVineet Gupta 			vipt ? "VIPT" : "PIPT",
15117a5ed56SVineet Gupta 			IS_USED_CFG(CONFIG_ARC_HAS_DCACHE));
15217a5ed56SVineet Gupta 
153d1f317d8SVineet Gupta slc_chk:
154fd0881a2SVineet Gupta 	if (is_isa_arcv2())
155fad84e39SVineet Gupta 		n += read_decode_cache_bcr_arcv2(c, buf + n, len - n);
15617a5ed56SVineet Gupta 
157fad84e39SVineet Gupta 	return n;
1588362c389SVineet Gupta }
1598362c389SVineet Gupta 
1608362c389SVineet Gupta /*
1618ea2ddffSVineet Gupta  * Line Operation on {I,D}-Cache
1628362c389SVineet Gupta  */
1638362c389SVineet Gupta 
1648362c389SVineet Gupta #define OP_INV		0x1
1658362c389SVineet Gupta #define OP_FLUSH	0x2
1668362c389SVineet Gupta #define OP_FLUSH_N_INV	0x3
1678362c389SVineet Gupta #define OP_INV_IC	0x4
1688362c389SVineet Gupta 
1698362c389SVineet Gupta /*
170288ff7deSVineet Gupta  * Cache Flush programming model
1718ea2ddffSVineet Gupta  *
172288ff7deSVineet Gupta  * ARC700 MMUv3 I$ and D$ are both VIPT and can potentially alias.
173288ff7deSVineet Gupta  * Programming model requires both paddr and vaddr irrespecive of aliasing
174288ff7deSVineet Gupta  * considerations:
175288ff7deSVineet Gupta  *  - vaddr in {I,D}C_IV?L
176288ff7deSVineet Gupta  *  - paddr in {I,D}C_PTAG
1778ea2ddffSVineet Gupta  *
178288ff7deSVineet Gupta  * In HS38x (MMUv4), D$ is PIPT, I$ is VIPT and can still alias.
179288ff7deSVineet Gupta  * Programming model is different for aliasing vs. non-aliasing I$
180288ff7deSVineet Gupta  *  - D$ / Non-aliasing I$: only paddr in {I,D}C_IV?L
181288ff7deSVineet Gupta  *  - Aliasing I$: same as ARC700 above (so MMUv3 routine used for MMUv4 I$)
1828ea2ddffSVineet Gupta  *
183288ff7deSVineet Gupta  *  - If PAE40 is enabled, independent of aliasing considerations, the higher
184288ff7deSVineet Gupta  *    bits needs to be written into PTAG_HI
1858362c389SVineet Gupta  */
1868ea2ddffSVineet Gupta 
18711e14896SVineet Gupta static inline
__cache_line_loop_v3(phys_addr_t paddr,unsigned long vaddr,unsigned long sz,const int op,const int full_page)18828b4af72SVineet Gupta void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr,
1897d3d162bSVineet Gupta 			  unsigned long sz, const int op, const int full_page)
19011e14896SVineet Gupta {
19111e14896SVineet Gupta 	unsigned int aux_cmd, aux_tag;
19211e14896SVineet Gupta 	int num_lines;
19311e14896SVineet Gupta 
19411e14896SVineet Gupta 	if (op == OP_INV_IC) {
19511e14896SVineet Gupta 		aux_cmd = ARC_REG_IC_IVIL;
19611e14896SVineet Gupta 		aux_tag = ARC_REG_IC_PTAG;
19711e14896SVineet Gupta 	} else {
19811e14896SVineet Gupta 		aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
19911e14896SVineet Gupta 		aux_tag = ARC_REG_DC_PTAG;
20011e14896SVineet Gupta 	}
20111e14896SVineet Gupta 
20211e14896SVineet Gupta 	/* Ensure we properly floor/ceil the non-line aligned/sized requests
20311e14896SVineet Gupta 	 * and have @paddr - aligned to cache line and integral @num_lines.
20411e14896SVineet Gupta 	 * This however can be avoided for page sized since:
20511e14896SVineet Gupta 	 *  -@paddr will be cache-line aligned already (being page aligned)
20611e14896SVineet Gupta 	 *  -@sz will be integral multiple of line size (being page sized).
20711e14896SVineet Gupta 	 */
20811e14896SVineet Gupta 	if (!full_page) {
20911e14896SVineet Gupta 		sz += paddr & ~CACHE_LINE_MASK;
21011e14896SVineet Gupta 		paddr &= CACHE_LINE_MASK;
21111e14896SVineet Gupta 		vaddr &= CACHE_LINE_MASK;
21211e14896SVineet Gupta 	}
21311e14896SVineet Gupta 	num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);
21411e14896SVineet Gupta 
21511e14896SVineet Gupta 	/*
21611e14896SVineet Gupta 	 * MMUv3, cache ops require paddr in PTAG reg
21711e14896SVineet Gupta 	 * if V-P const for loop, PTAG can be written once outside loop
21811e14896SVineet Gupta 	 */
21911e14896SVineet Gupta 	if (full_page)
22011e14896SVineet Gupta 		write_aux_reg(aux_tag, paddr);
22111e14896SVineet Gupta 
2225a364c2aSVineet Gupta 	/*
2235a364c2aSVineet Gupta 	 * This is technically for MMU v4, using the MMU v3 programming model
2242547476aSAndrea Gelmini 	 * Special work for HS38 aliasing I-cache configuration with PAE40
2255a364c2aSVineet Gupta 	 *   - upper 8 bits of paddr need to be written into PTAG_HI
2265a364c2aSVineet Gupta 	 *   - (and needs to be written before the lower 32 bits)
2275a364c2aSVineet Gupta 	 * Note that PTAG_HI is hoisted outside the line loop
2285a364c2aSVineet Gupta 	 */
2295a364c2aSVineet Gupta 	if (is_pae40_enabled() && op == OP_INV_IC)
2305a364c2aSVineet Gupta 		write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
2315a364c2aSVineet Gupta 
23211e14896SVineet Gupta 	while (num_lines-- > 0) {
23311e14896SVineet Gupta 		if (!full_page) {
2348362c389SVineet Gupta 			write_aux_reg(aux_tag, paddr);
2358362c389SVineet Gupta 			paddr += L1_CACHE_BYTES;
2368362c389SVineet Gupta 		}
2378362c389SVineet Gupta 
2388362c389SVineet Gupta 		write_aux_reg(aux_cmd, vaddr);
2398362c389SVineet Gupta 		vaddr += L1_CACHE_BYTES;
24011e14896SVineet Gupta 	}
24111e14896SVineet Gupta }
24211e14896SVineet Gupta 
2430d77117fSVineet Gupta #ifndef USE_RGN_FLSH
2440d77117fSVineet Gupta 
245d1f317d8SVineet Gupta /*
246d1f317d8SVineet Gupta  */
247d1f317d8SVineet Gupta static inline
__cache_line_loop_v4(phys_addr_t paddr,unsigned long vaddr,unsigned long sz,const int op,const int full_page)24828b4af72SVineet Gupta void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr,
2497d3d162bSVineet Gupta 			  unsigned long sz, const int op, const int full_page)
250d1f317d8SVineet Gupta {
251d1f317d8SVineet Gupta 	unsigned int aux_cmd;
252d1f317d8SVineet Gupta 	int num_lines;
253d1f317d8SVineet Gupta 
2547d3d162bSVineet Gupta 	if (op == OP_INV_IC) {
255d1f317d8SVineet Gupta 		aux_cmd = ARC_REG_IC_IVIL;
256d1f317d8SVineet Gupta 	} else {
257d1f317d8SVineet Gupta 		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
2587d3d162bSVineet Gupta 		aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
259d1f317d8SVineet Gupta 	}
260d1f317d8SVineet Gupta 
261d1f317d8SVineet Gupta 	/* Ensure we properly floor/ceil the non-line aligned/sized requests
262d1f317d8SVineet Gupta 	 * and have @paddr - aligned to cache line and integral @num_lines.
263d1f317d8SVineet Gupta 	 * This however can be avoided for page sized since:
264d1f317d8SVineet Gupta 	 *  -@paddr will be cache-line aligned already (being page aligned)
265d1f317d8SVineet Gupta 	 *  -@sz will be integral multiple of line size (being page sized).
266d1f317d8SVineet Gupta 	 */
2677d3d162bSVineet Gupta 	if (!full_page) {
268d1f317d8SVineet Gupta 		sz += paddr & ~CACHE_LINE_MASK;
269d1f317d8SVineet Gupta 		paddr &= CACHE_LINE_MASK;
270d1f317d8SVineet Gupta 	}
271d1f317d8SVineet Gupta 
272d1f317d8SVineet Gupta 	num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);
273d1f317d8SVineet Gupta 
2745a364c2aSVineet Gupta 	/*
2755a364c2aSVineet Gupta 	 * For HS38 PAE40 configuration
2765a364c2aSVineet Gupta 	 *   - upper 8 bits of paddr need to be written into PTAG_HI
2775a364c2aSVineet Gupta 	 *   - (and needs to be written before the lower 32 bits)
2785a364c2aSVineet Gupta 	 */
2795a364c2aSVineet Gupta 	if (is_pae40_enabled()) {
2807d3d162bSVineet Gupta 		if (op == OP_INV_IC)
2815a364c2aSVineet Gupta 			/*
2825a364c2aSVineet Gupta 			 * Non aliasing I-cache in HS38,
2835a364c2aSVineet Gupta 			 * aliasing I-cache handled in __cache_line_loop_v3()
2845a364c2aSVineet Gupta 			 */
2855a364c2aSVineet Gupta 			write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
2865a364c2aSVineet Gupta 		else
2875a364c2aSVineet Gupta 			write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32);
2885a364c2aSVineet Gupta 	}
2895a364c2aSVineet Gupta 
290d1f317d8SVineet Gupta 	while (num_lines-- > 0) {
291d1f317d8SVineet Gupta 		write_aux_reg(aux_cmd, paddr);
292d1f317d8SVineet Gupta 		paddr += L1_CACHE_BYTES;
293d1f317d8SVineet Gupta 	}
294d1f317d8SVineet Gupta }
295d1f317d8SVineet Gupta 
2960d77117fSVineet Gupta #else
2970d77117fSVineet Gupta 
2980d77117fSVineet Gupta /*
2990d77117fSVineet Gupta  * optimized flush operation which takes a region as opposed to iterating per line
3000d77117fSVineet Gupta  */
3010d77117fSVineet Gupta static inline
__cache_line_loop_v4(phys_addr_t paddr,unsigned long vaddr,unsigned long sz,const int op,const int full_page)3020d77117fSVineet Gupta void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr,
3030d77117fSVineet Gupta 			  unsigned long sz, const int op, const int full_page)
3040d77117fSVineet Gupta {
305ee40bd1eSVineet Gupta 	unsigned int s, e;
3060d77117fSVineet Gupta 
3070d77117fSVineet Gupta 	/* Only for Non aliasing I-cache in HS38 */
3080d77117fSVineet Gupta 	if (op == OP_INV_IC) {
3090d77117fSVineet Gupta 		s = ARC_REG_IC_IVIR;
3100d77117fSVineet Gupta 		e = ARC_REG_IC_ENDR;
3110d77117fSVineet Gupta 	} else {
3120d77117fSVineet Gupta 		s = ARC_REG_DC_STARTR;
3130d77117fSVineet Gupta 		e = ARC_REG_DC_ENDR;
3140d77117fSVineet Gupta 	}
3150d77117fSVineet Gupta 
3160d77117fSVineet Gupta 	if (!full_page) {
3170d77117fSVineet Gupta 		/* for any leading gap between @paddr and start of cache line */
3180d77117fSVineet Gupta 		sz += paddr & ~CACHE_LINE_MASK;
3190d77117fSVineet Gupta 		paddr &= CACHE_LINE_MASK;
3200d77117fSVineet Gupta 
3210d77117fSVineet Gupta 		/*
3220d77117fSVineet Gupta 		 *  account for any trailing gap to end of cache line
3230d77117fSVineet Gupta 		 *  this is equivalent to DIV_ROUND_UP() in line ops above
3240d77117fSVineet Gupta 		 */
3250d77117fSVineet Gupta 		sz += L1_CACHE_BYTES - 1;
3260d77117fSVineet Gupta 	}
3270d77117fSVineet Gupta 
3280d77117fSVineet Gupta 	if (is_pae40_enabled()) {
3290d77117fSVineet Gupta 		/* TBD: check if crossing 4TB boundary */
3300d77117fSVineet Gupta 		if (op == OP_INV_IC)
3310d77117fSVineet Gupta 			write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
3320d77117fSVineet Gupta 		else
3330d77117fSVineet Gupta 			write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32);
3340d77117fSVineet Gupta 	}
3350d77117fSVineet Gupta 
3360d77117fSVineet Gupta 	/* ENDR needs to be set ahead of START */
3370d77117fSVineet Gupta 	write_aux_reg(e, paddr + sz);	/* ENDR is exclusive */
3380d77117fSVineet Gupta 	write_aux_reg(s, paddr);
3390d77117fSVineet Gupta 
3400d77117fSVineet Gupta 	/* caller waits on DC_CTRL.FS */
3410d77117fSVineet Gupta }
3420d77117fSVineet Gupta 
3430d77117fSVineet Gupta #endif
3440d77117fSVineet Gupta 
345288ff7deSVineet Gupta #ifdef CONFIG_ARC_MMU_V3
34611e14896SVineet Gupta #define __cache_line_loop	__cache_line_loop_v3
347288ff7deSVineet Gupta #else
348d1f317d8SVineet Gupta #define __cache_line_loop	__cache_line_loop_v4
3498362c389SVineet Gupta #endif
3508362c389SVineet Gupta 
3518362c389SVineet Gupta #ifdef CONFIG_ARC_HAS_DCACHE
3528362c389SVineet Gupta 
3538362c389SVineet Gupta /***************************************************************
3548362c389SVineet Gupta  * Machine specific helpers for Entire D-Cache or Per Line ops
3558362c389SVineet Gupta  */
3568362c389SVineet Gupta 
357ee40bd1eSVineet Gupta #ifndef USE_RGN_FLSH
358ee40bd1eSVineet Gupta /*
359ee40bd1eSVineet Gupta  * this version avoids extra read/write of DC_CTRL for flush or invalid ops
360ee40bd1eSVineet Gupta  * in the non region flush regime (such as for ARCompact)
361ee40bd1eSVineet Gupta  */
__before_dc_op(const int op)3626c310681SVineet Gupta static inline void __before_dc_op(const int op)
3638362c389SVineet Gupta {
3648362c389SVineet Gupta 	if (op == OP_FLUSH_N_INV) {
3658362c389SVineet Gupta 		/* Dcache provides 2 cmd: FLUSH or INV
3668362c389SVineet Gupta 		 * INV in turn has sub-modes: DISCARD or FLUSH-BEFORE
3678362c389SVineet Gupta 		 * flush-n-inv is achieved by INV cmd but with IM=1
3688362c389SVineet Gupta 		 * So toggle INV sub-mode depending on op request and default
3698362c389SVineet Gupta 		 */
3706c310681SVineet Gupta 		const unsigned int ctl = ARC_REG_DC_CTRL;
3716c310681SVineet Gupta 		write_aux_reg(ctl, read_aux_reg(ctl) | DC_CTRL_INV_MODE_FLUSH);
3726c310681SVineet Gupta 	}
3738362c389SVineet Gupta }
3748362c389SVineet Gupta 
375ee40bd1eSVineet Gupta #else
376ee40bd1eSVineet Gupta 
__before_dc_op(const int op)377ee40bd1eSVineet Gupta static inline void __before_dc_op(const int op)
378ee40bd1eSVineet Gupta {
379ee40bd1eSVineet Gupta 	const unsigned int ctl = ARC_REG_DC_CTRL;
380ee40bd1eSVineet Gupta 	unsigned int val = read_aux_reg(ctl);
381ee40bd1eSVineet Gupta 
382ee40bd1eSVineet Gupta 	if (op == OP_FLUSH_N_INV) {
383ee40bd1eSVineet Gupta 		val |= DC_CTRL_INV_MODE_FLUSH;
384ee40bd1eSVineet Gupta 	}
385ee40bd1eSVineet Gupta 
386ee40bd1eSVineet Gupta 	if (op != OP_INV_IC) {
387ee40bd1eSVineet Gupta 		/*
388ee40bd1eSVineet Gupta 		 * Flush / Invalidate is provided by DC_CTRL.RNG_OP 0 or 1
389ee40bd1eSVineet Gupta 		 * combined Flush-n-invalidate uses DC_CTRL.IM = 1 set above
390ee40bd1eSVineet Gupta 		 */
391ee40bd1eSVineet Gupta 		val &= ~DC_CTRL_RGN_OP_MSK;
392ee40bd1eSVineet Gupta 		if (op & OP_INV)
393ee40bd1eSVineet Gupta 			val |= DC_CTRL_RGN_OP_INV;
394ee40bd1eSVineet Gupta 	}
395ee40bd1eSVineet Gupta 	write_aux_reg(ctl, val);
396ee40bd1eSVineet Gupta }
397ee40bd1eSVineet Gupta 
398ee40bd1eSVineet Gupta #endif
399ee40bd1eSVineet Gupta 
400ee40bd1eSVineet Gupta 
__after_dc_op(const int op)4016c310681SVineet Gupta static inline void __after_dc_op(const int op)
4028362c389SVineet Gupta {
4036c310681SVineet Gupta 	if (op & OP_FLUSH) {
4046c310681SVineet Gupta 		const unsigned int ctl = ARC_REG_DC_CTRL;
4056c310681SVineet Gupta 		unsigned int reg;
4066c310681SVineet Gupta 
4076c310681SVineet Gupta 		/* flush / flush-n-inv both wait */
4086c310681SVineet Gupta 		while ((reg = read_aux_reg(ctl)) & DC_CTRL_FLUSH_STATUS)
4096c310681SVineet Gupta 			;
4108362c389SVineet Gupta 
4118362c389SVineet Gupta 		/* Switch back to default Invalidate mode */
4128362c389SVineet Gupta 		if (op == OP_FLUSH_N_INV)
4136c310681SVineet Gupta 			write_aux_reg(ctl, reg & ~DC_CTRL_INV_MODE_FLUSH);
4146c310681SVineet Gupta 	}
4158362c389SVineet Gupta }
4168362c389SVineet Gupta 
4178362c389SVineet Gupta /*
4188362c389SVineet Gupta  * Operation on Entire D-Cache
4198ea2ddffSVineet Gupta  * @op = {OP_INV, OP_FLUSH, OP_FLUSH_N_INV}
4208362c389SVineet Gupta  * Note that constant propagation ensures all the checks are gone
4218362c389SVineet Gupta  * in generated code
4228362c389SVineet Gupta  */
__dc_entire_op(const int op)4238ea2ddffSVineet Gupta static inline void __dc_entire_op(const int op)
4248362c389SVineet Gupta {
4258362c389SVineet Gupta 	int aux;
4268362c389SVineet Gupta 
4276c310681SVineet Gupta 	__before_dc_op(op);
4288362c389SVineet Gupta 
4298ea2ddffSVineet Gupta 	if (op & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
4308362c389SVineet Gupta 		aux = ARC_REG_DC_IVDC;
4318362c389SVineet Gupta 	else
4328362c389SVineet Gupta 		aux = ARC_REG_DC_FLSH;
4338362c389SVineet Gupta 
4348362c389SVineet Gupta 	write_aux_reg(aux, 0x1);
4358362c389SVineet Gupta 
4366c310681SVineet Gupta 	__after_dc_op(op);
4378362c389SVineet Gupta }
4388362c389SVineet Gupta 
__dc_disable(void)4398c47f83bSVineet Gupta static inline void __dc_disable(void)
4408c47f83bSVineet Gupta {
4418c47f83bSVineet Gupta 	const int r = ARC_REG_DC_CTRL;
4428c47f83bSVineet Gupta 
4438c47f83bSVineet Gupta 	__dc_entire_op(OP_FLUSH_N_INV);
4448c47f83bSVineet Gupta 	write_aux_reg(r, read_aux_reg(r) | DC_CTRL_DIS);
4458c47f83bSVineet Gupta }
4468c47f83bSVineet Gupta 
__dc_enable(void)4478c47f83bSVineet Gupta static void __dc_enable(void)
4488c47f83bSVineet Gupta {
4498c47f83bSVineet Gupta 	const int r = ARC_REG_DC_CTRL;
4508c47f83bSVineet Gupta 
4518c47f83bSVineet Gupta 	write_aux_reg(r, read_aux_reg(r) & ~DC_CTRL_DIS);
4528c47f83bSVineet Gupta }
4538c47f83bSVineet Gupta 
4548362c389SVineet Gupta /* For kernel mappings cache operation: index is same as paddr */
4558362c389SVineet Gupta #define __dc_line_op_k(p, sz, op)	__dc_line_op(p, p, sz, op)
4568362c389SVineet Gupta 
4578362c389SVineet Gupta /*
4588ea2ddffSVineet Gupta  * D-Cache Line ops: Per Line INV (discard or wback+discard) or FLUSH (wback)
4598362c389SVineet Gupta  */
__dc_line_op(phys_addr_t paddr,unsigned long vaddr,unsigned long sz,const int op)46028b4af72SVineet Gupta static inline void __dc_line_op(phys_addr_t paddr, unsigned long vaddr,
4618ea2ddffSVineet Gupta 				unsigned long sz, const int op)
4628362c389SVineet Gupta {
4637d3d162bSVineet Gupta 	const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;
4648362c389SVineet Gupta 	unsigned long flags;
4658362c389SVineet Gupta 
4668362c389SVineet Gupta 	local_irq_save(flags);
4678362c389SVineet Gupta 
4686c310681SVineet Gupta 	__before_dc_op(op);
4698362c389SVineet Gupta 
4707d3d162bSVineet Gupta 	__cache_line_loop(paddr, vaddr, sz, op, full_page);
4718362c389SVineet Gupta 
4726c310681SVineet Gupta 	__after_dc_op(op);
4738362c389SVineet Gupta 
4748362c389SVineet Gupta 	local_irq_restore(flags);
4758362c389SVineet Gupta }
4768362c389SVineet Gupta 
4778362c389SVineet Gupta #else
4788362c389SVineet Gupta 
4798ea2ddffSVineet Gupta #define __dc_entire_op(op)
4808c47f83bSVineet Gupta #define __dc_disable()
4818c47f83bSVineet Gupta #define __dc_enable()
4828ea2ddffSVineet Gupta #define __dc_line_op(paddr, vaddr, sz, op)
4838ea2ddffSVineet Gupta #define __dc_line_op_k(paddr, sz, op)
4848362c389SVineet Gupta 
4858362c389SVineet Gupta #endif /* CONFIG_ARC_HAS_DCACHE */
4868362c389SVineet Gupta 
4878362c389SVineet Gupta #ifdef CONFIG_ARC_HAS_ICACHE
4888362c389SVineet Gupta 
__ic_entire_inv(void)4898362c389SVineet Gupta static inline void __ic_entire_inv(void)
4908362c389SVineet Gupta {
4918362c389SVineet Gupta 	write_aux_reg(ARC_REG_IC_IVIC, 1);
4928362c389SVineet Gupta 	read_aux_reg(ARC_REG_IC_CTRL);	/* blocks */
4938362c389SVineet Gupta }
4948362c389SVineet Gupta 
4958362c389SVineet Gupta static inline void
__ic_line_inv_vaddr_local(phys_addr_t paddr,unsigned long vaddr,unsigned long sz)49628b4af72SVineet Gupta __ic_line_inv_vaddr_local(phys_addr_t paddr, unsigned long vaddr,
4978362c389SVineet Gupta 			  unsigned long sz)
4988362c389SVineet Gupta {
4997d3d162bSVineet Gupta 	const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;
5008362c389SVineet Gupta 	unsigned long flags;
5018362c389SVineet Gupta 
5028362c389SVineet Gupta 	local_irq_save(flags);
5037d3d162bSVineet Gupta 	(*_cache_line_loop_ic_fn)(paddr, vaddr, sz, OP_INV_IC, full_page);
5048362c389SVineet Gupta 	local_irq_restore(flags);
5058362c389SVineet Gupta }
5068362c389SVineet Gupta 
5078362c389SVineet Gupta #ifndef CONFIG_SMP
5088362c389SVineet Gupta 
5098362c389SVineet Gupta #define __ic_line_inv_vaddr(p, v, s)	__ic_line_inv_vaddr_local(p, v, s)
5108362c389SVineet Gupta 
5118362c389SVineet Gupta #else
5128362c389SVineet Gupta 
5138362c389SVineet Gupta struct ic_inv_args {
51428b4af72SVineet Gupta 	phys_addr_t paddr, vaddr;
5158362c389SVineet Gupta 	int sz;
5168362c389SVineet Gupta };
5178362c389SVineet Gupta 
__ic_line_inv_vaddr_helper(void * info)5188362c389SVineet Gupta static void __ic_line_inv_vaddr_helper(void *info)
5198362c389SVineet Gupta {
5208362c389SVineet Gupta         struct ic_inv_args *ic_inv = info;
5218362c389SVineet Gupta 
5228362c389SVineet Gupta         __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz);
5238362c389SVineet Gupta }
5248362c389SVineet Gupta 
__ic_line_inv_vaddr(phys_addr_t paddr,unsigned long vaddr,unsigned long sz)52528b4af72SVineet Gupta static void __ic_line_inv_vaddr(phys_addr_t paddr, unsigned long vaddr,
5268362c389SVineet Gupta 				unsigned long sz)
5278362c389SVineet Gupta {
5288362c389SVineet Gupta 	struct ic_inv_args ic_inv = {
5298362c389SVineet Gupta 		.paddr = paddr,
5308362c389SVineet Gupta 		.vaddr = vaddr,
5318362c389SVineet Gupta 		.sz    = sz
5328362c389SVineet Gupta 	};
5338362c389SVineet Gupta 
5348362c389SVineet Gupta 	on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1);
5358362c389SVineet Gupta }
5368362c389SVineet Gupta 
5378362c389SVineet Gupta #endif	/* CONFIG_SMP */
5388362c389SVineet Gupta 
5398362c389SVineet Gupta #else	/* !CONFIG_ARC_HAS_ICACHE */
5408362c389SVineet Gupta 
5418362c389SVineet Gupta #define __ic_entire_inv()
5428362c389SVineet Gupta #define __ic_line_inv_vaddr(pstart, vstart, sz)
5438362c389SVineet Gupta 
5448362c389SVineet Gupta #endif /* CONFIG_ARC_HAS_ICACHE */
5458362c389SVineet Gupta 
slc_op_rgn(phys_addr_t paddr,unsigned long sz,const int op)5464d369680SVineet Gupta static noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op)
547795f4558SVineet Gupta {
548795f4558SVineet Gupta #ifdef CONFIG_ISA_ARCV2
549b607edddSAlexey Brodkin 	/*
550b607edddSAlexey Brodkin 	 * SLC is shared between all cores and concurrent aux operations from
551b607edddSAlexey Brodkin 	 * multiple cores need to be serialized using a spinlock
552b607edddSAlexey Brodkin 	 * A concurrent operation can be silently ignored and/or the old/new
553b607edddSAlexey Brodkin 	 * operation can remain incomplete forever (lockup in SLC_CTRL_BUSY loop
554b607edddSAlexey Brodkin 	 * below)
555b607edddSAlexey Brodkin 	 */
556b607edddSAlexey Brodkin 	static DEFINE_SPINLOCK(lock);
557795f4558SVineet Gupta 	unsigned long flags;
558795f4558SVineet Gupta 	unsigned int ctrl;
5597d79cee2SAlexey Brodkin 	phys_addr_t end;
560795f4558SVineet Gupta 
561b607edddSAlexey Brodkin 	spin_lock_irqsave(&lock, flags);
562795f4558SVineet Gupta 
563795f4558SVineet Gupta 	/*
564795f4558SVineet Gupta 	 * The Region Flush operation is specified by CTRL.RGN_OP[11..9]
565795f4558SVineet Gupta 	 *  - b'000 (default) is Flush,
566795f4558SVineet Gupta 	 *  - b'001 is Invalidate if CTRL.IM == 0
567795f4558SVineet Gupta 	 *  - b'001 is Flush-n-Invalidate if CTRL.IM == 1
568795f4558SVineet Gupta 	 */
569795f4558SVineet Gupta 	ctrl = read_aux_reg(ARC_REG_SLC_CTRL);
570795f4558SVineet Gupta 
571795f4558SVineet Gupta 	/* Don't rely on default value of IM bit */
572795f4558SVineet Gupta 	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
573795f4558SVineet Gupta 		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
574795f4558SVineet Gupta 	else
575795f4558SVineet Gupta 		ctrl |= SLC_CTRL_IM;
576795f4558SVineet Gupta 
577795f4558SVineet Gupta 	if (op & OP_INV)
578795f4558SVineet Gupta 		ctrl |= SLC_CTRL_RGN_OP_INV;	/* Inv or flush-n-inv */
579795f4558SVineet Gupta 	else
580795f4558SVineet Gupta 		ctrl &= ~SLC_CTRL_RGN_OP_INV;
581795f4558SVineet Gupta 
582795f4558SVineet Gupta 	write_aux_reg(ARC_REG_SLC_CTRL, ctrl);
583795f4558SVineet Gupta 
584795f4558SVineet Gupta 	/*
585795f4558SVineet Gupta 	 * Lower bits are ignored, no need to clip
586795f4558SVineet Gupta 	 * END needs to be setup before START (latter triggers the operation)
587795f4558SVineet Gupta 	 * END can't be same as START, so add (l2_line_sz - 1) to sz
588795f4558SVineet Gupta 	 */
5897d79cee2SAlexey Brodkin 	end = paddr + sz + l2_line_sz - 1;
5907d79cee2SAlexey Brodkin 	if (is_pae40_enabled())
5917d79cee2SAlexey Brodkin 		write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end));
5927d79cee2SAlexey Brodkin 
5937d79cee2SAlexey Brodkin 	write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end));
5947d79cee2SAlexey Brodkin 
5957d79cee2SAlexey Brodkin 	if (is_pae40_enabled())
5967d79cee2SAlexey Brodkin 		write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr));
5977d79cee2SAlexey Brodkin 
5987d79cee2SAlexey Brodkin 	write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr));
599795f4558SVineet Gupta 
600b37174d9SAlexey Brodkin 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
601b37174d9SAlexey Brodkin 	read_aux_reg(ARC_REG_SLC_CTRL);
602b37174d9SAlexey Brodkin 
603795f4558SVineet Gupta 	while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
604795f4558SVineet Gupta 
605b607edddSAlexey Brodkin 	spin_unlock_irqrestore(&lock, flags);
606795f4558SVineet Gupta #endif
607795f4558SVineet Gupta }
608795f4558SVineet Gupta 
slc_op_line(phys_addr_t paddr,unsigned long sz,const int op)6094d369680SVineet Gupta static __maybe_unused noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op)
610ae0b63d9SVineet Gupta {
611ae0b63d9SVineet Gupta #ifdef CONFIG_ISA_ARCV2
612ae0b63d9SVineet Gupta 	/*
613ae0b63d9SVineet Gupta 	 * SLC is shared between all cores and concurrent aux operations from
614ae0b63d9SVineet Gupta 	 * multiple cores need to be serialized using a spinlock
615ae0b63d9SVineet Gupta 	 * A concurrent operation can be silently ignored and/or the old/new
616ae0b63d9SVineet Gupta 	 * operation can remain incomplete forever (lockup in SLC_CTRL_BUSY loop
617ae0b63d9SVineet Gupta 	 * below)
618ae0b63d9SVineet Gupta 	 */
619ae0b63d9SVineet Gupta 	static DEFINE_SPINLOCK(lock);
620ae0b63d9SVineet Gupta 
621ae0b63d9SVineet Gupta 	const unsigned long SLC_LINE_MASK = ~(l2_line_sz - 1);
622ae0b63d9SVineet Gupta 	unsigned int ctrl, cmd;
623ae0b63d9SVineet Gupta 	unsigned long flags;
624ae0b63d9SVineet Gupta 	int num_lines;
625ae0b63d9SVineet Gupta 
626ae0b63d9SVineet Gupta 	spin_lock_irqsave(&lock, flags);
627ae0b63d9SVineet Gupta 
628ae0b63d9SVineet Gupta 	ctrl = read_aux_reg(ARC_REG_SLC_CTRL);
629ae0b63d9SVineet Gupta 
630ae0b63d9SVineet Gupta 	/* Don't rely on default value of IM bit */
631ae0b63d9SVineet Gupta 	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
632ae0b63d9SVineet Gupta 		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
633ae0b63d9SVineet Gupta 	else
634ae0b63d9SVineet Gupta 		ctrl |= SLC_CTRL_IM;
635ae0b63d9SVineet Gupta 
636ae0b63d9SVineet Gupta 	write_aux_reg(ARC_REG_SLC_CTRL, ctrl);
637ae0b63d9SVineet Gupta 
638ae0b63d9SVineet Gupta 	cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
639ae0b63d9SVineet Gupta 
640ae0b63d9SVineet Gupta 	sz += paddr & ~SLC_LINE_MASK;
641ae0b63d9SVineet Gupta 	paddr &= SLC_LINE_MASK;
642ae0b63d9SVineet Gupta 
643ae0b63d9SVineet Gupta 	num_lines = DIV_ROUND_UP(sz, l2_line_sz);
644ae0b63d9SVineet Gupta 
645ae0b63d9SVineet Gupta 	while (num_lines-- > 0) {
646ae0b63d9SVineet Gupta 		write_aux_reg(cmd, paddr);
647ae0b63d9SVineet Gupta 		paddr += l2_line_sz;
648ae0b63d9SVineet Gupta 	}
649ae0b63d9SVineet Gupta 
650ae0b63d9SVineet Gupta 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
651ae0b63d9SVineet Gupta 	read_aux_reg(ARC_REG_SLC_CTRL);
652ae0b63d9SVineet Gupta 
653ae0b63d9SVineet Gupta 	while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
654ae0b63d9SVineet Gupta 
655ae0b63d9SVineet Gupta 	spin_unlock_irqrestore(&lock, flags);
656ae0b63d9SVineet Gupta #endif
657ae0b63d9SVineet Gupta }
658ae0b63d9SVineet Gupta 
659ae0b63d9SVineet Gupta #define slc_op(paddr, sz, op)	slc_op_rgn(paddr, sz, op)
660ae0b63d9SVineet Gupta 
slc_entire_op(const int op)661d4911cddSVineet Gupta noinline static void slc_entire_op(const int op)
662d4911cddSVineet Gupta {
663d4911cddSVineet Gupta 	unsigned int ctrl, r = ARC_REG_SLC_CTRL;
664d4911cddSVineet Gupta 
665d4911cddSVineet Gupta 	ctrl = read_aux_reg(r);
666d4911cddSVineet Gupta 
667d4911cddSVineet Gupta 	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
668d4911cddSVineet Gupta 		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
669d4911cddSVineet Gupta 	else
670d4911cddSVineet Gupta 		ctrl |= SLC_CTRL_IM;
671d4911cddSVineet Gupta 
672d4911cddSVineet Gupta 	write_aux_reg(r, ctrl);
673d4911cddSVineet Gupta 
6748bbfbc2dSEugeniy Paltsev 	if (op & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
6758bbfbc2dSEugeniy Paltsev 		write_aux_reg(ARC_REG_SLC_INVALIDATE, 0x1);
6768bbfbc2dSEugeniy Paltsev 	else
6778bbfbc2dSEugeniy Paltsev 		write_aux_reg(ARC_REG_SLC_FLUSH, 0x1);
678d4911cddSVineet Gupta 
679c70c4733SAlexey Brodkin 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
680c70c4733SAlexey Brodkin 	read_aux_reg(r);
681c70c4733SAlexey Brodkin 
682d4911cddSVineet Gupta 	/* Important to wait for flush to complete */
683d4911cddSVineet Gupta 	while (read_aux_reg(r) & SLC_CTRL_BUSY);
684d4911cddSVineet Gupta }
685d4911cddSVineet Gupta 
arc_slc_disable(void)686d4911cddSVineet Gupta static inline void arc_slc_disable(void)
687d4911cddSVineet Gupta {
688d4911cddSVineet Gupta 	const int r = ARC_REG_SLC_CTRL;
689d4911cddSVineet Gupta 
690d4911cddSVineet Gupta 	slc_entire_op(OP_FLUSH_N_INV);
691d4911cddSVineet Gupta 	write_aux_reg(r, read_aux_reg(r) | SLC_CTRL_DIS);
692d4911cddSVineet Gupta }
693d4911cddSVineet Gupta 
arc_slc_enable(void)694d4911cddSVineet Gupta static inline void arc_slc_enable(void)
695d4911cddSVineet Gupta {
696d4911cddSVineet Gupta 	const int r = ARC_REG_SLC_CTRL;
697d4911cddSVineet Gupta 
698d4911cddSVineet Gupta 	write_aux_reg(r, read_aux_reg(r) & ~SLC_CTRL_DIS);
699d4911cddSVineet Gupta }
700d4911cddSVineet Gupta 
7018362c389SVineet Gupta /***********************************************************
7028362c389SVineet Gupta  * Exported APIs
7038362c389SVineet Gupta  */
7048362c389SVineet Gupta 
flush_dcache_folio(struct folio * folio)705ac4cfaccSMatthew Wilcox (Oracle) void flush_dcache_folio(struct folio *folio)
7068362c389SVineet Gupta {
707ac4cfaccSMatthew Wilcox (Oracle) 	clear_bit(PG_dc_clean, &folio->flags);
7088362c389SVineet Gupta 	return;
7098362c389SVineet Gupta }
710ac4cfaccSMatthew Wilcox (Oracle) EXPORT_SYMBOL(flush_dcache_folio);
711ac4cfaccSMatthew Wilcox (Oracle) 
flush_dcache_page(struct page * page)712ac4cfaccSMatthew Wilcox (Oracle) void flush_dcache_page(struct page *page)
713ac4cfaccSMatthew Wilcox (Oracle) {
714ac4cfaccSMatthew Wilcox (Oracle) 	return flush_dcache_folio(page_folio(page));
715ac4cfaccSMatthew Wilcox (Oracle) }
7168362c389SVineet Gupta EXPORT_SYMBOL(flush_dcache_page);
7178362c389SVineet Gupta 
718f2b0b25aSAlexey Brodkin /*
719f2b0b25aSAlexey Brodkin  * DMA ops for systems with L1 cache only
720f2b0b25aSAlexey Brodkin  * Make memory coherent with L1 cache by flushing/invalidating L1 lines
721f2b0b25aSAlexey Brodkin  */
__dma_cache_wback_inv_l1(phys_addr_t start,unsigned long sz)722f5db19e9SVineet Gupta static void __dma_cache_wback_inv_l1(phys_addr_t start, unsigned long sz)
7238362c389SVineet Gupta {
7248362c389SVineet Gupta 	__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
725f2b0b25aSAlexey Brodkin }
726795f4558SVineet Gupta 
__dma_cache_inv_l1(phys_addr_t start,unsigned long sz)727f5db19e9SVineet Gupta static void __dma_cache_inv_l1(phys_addr_t start, unsigned long sz)
728f2b0b25aSAlexey Brodkin {
729f2b0b25aSAlexey Brodkin 	__dc_line_op_k(start, sz, OP_INV);
730f2b0b25aSAlexey Brodkin }
731f2b0b25aSAlexey Brodkin 
__dma_cache_wback_l1(phys_addr_t start,unsigned long sz)732f5db19e9SVineet Gupta static void __dma_cache_wback_l1(phys_addr_t start, unsigned long sz)
733f2b0b25aSAlexey Brodkin {
734f2b0b25aSAlexey Brodkin 	__dc_line_op_k(start, sz, OP_FLUSH);
735f2b0b25aSAlexey Brodkin }
736f2b0b25aSAlexey Brodkin 
737f2b0b25aSAlexey Brodkin /*
738f2b0b25aSAlexey Brodkin  * DMA ops for systems with both L1 and L2 caches, but without IOC
7397423cc0cSAdam Buchbinder  * Both L1 and L2 lines need to be explicitly flushed/invalidated
740f2b0b25aSAlexey Brodkin  */
__dma_cache_wback_inv_slc(phys_addr_t start,unsigned long sz)741f5db19e9SVineet Gupta static void __dma_cache_wback_inv_slc(phys_addr_t start, unsigned long sz)
742f2b0b25aSAlexey Brodkin {
743f2b0b25aSAlexey Brodkin 	__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
744795f4558SVineet Gupta 	slc_op(start, sz, OP_FLUSH_N_INV);
7458362c389SVineet Gupta }
746f2b0b25aSAlexey Brodkin 
__dma_cache_inv_slc(phys_addr_t start,unsigned long sz)747f5db19e9SVineet Gupta static void __dma_cache_inv_slc(phys_addr_t start, unsigned long sz)
748f2b0b25aSAlexey Brodkin {
749f2b0b25aSAlexey Brodkin 	__dc_line_op_k(start, sz, OP_INV);
750f2b0b25aSAlexey Brodkin 	slc_op(start, sz, OP_INV);
751f2b0b25aSAlexey Brodkin }
752f2b0b25aSAlexey Brodkin 
__dma_cache_wback_slc(phys_addr_t start,unsigned long sz)753f5db19e9SVineet Gupta static void __dma_cache_wback_slc(phys_addr_t start, unsigned long sz)
754f2b0b25aSAlexey Brodkin {
755f2b0b25aSAlexey Brodkin 	__dc_line_op_k(start, sz, OP_FLUSH);
756f2b0b25aSAlexey Brodkin 	slc_op(start, sz, OP_FLUSH);
757f2b0b25aSAlexey Brodkin }
758f2b0b25aSAlexey Brodkin 
759f2b0b25aSAlexey Brodkin /*
760f2b0b25aSAlexey Brodkin  * Exported DMA API
761f2b0b25aSAlexey Brodkin  */
dma_cache_wback_inv(phys_addr_t start,unsigned long sz)762f5db19e9SVineet Gupta void dma_cache_wback_inv(phys_addr_t start, unsigned long sz)
763f2b0b25aSAlexey Brodkin {
764f2b0b25aSAlexey Brodkin 	__dma_cache_wback_inv(start, sz);
765f2b0b25aSAlexey Brodkin }
7668362c389SVineet Gupta EXPORT_SYMBOL(dma_cache_wback_inv);
7678362c389SVineet Gupta 
dma_cache_inv(phys_addr_t start,unsigned long sz)768f5db19e9SVineet Gupta void dma_cache_inv(phys_addr_t start, unsigned long sz)
7698362c389SVineet Gupta {
770f2b0b25aSAlexey Brodkin 	__dma_cache_inv(start, sz);
7718362c389SVineet Gupta }
7728362c389SVineet Gupta EXPORT_SYMBOL(dma_cache_inv);
7738362c389SVineet Gupta 
dma_cache_wback(phys_addr_t start,unsigned long sz)774f5db19e9SVineet Gupta void dma_cache_wback(phys_addr_t start, unsigned long sz)
7758362c389SVineet Gupta {
776f2b0b25aSAlexey Brodkin 	__dma_cache_wback(start, sz);
7778362c389SVineet Gupta }
7788362c389SVineet Gupta EXPORT_SYMBOL(dma_cache_wback);
7798362c389SVineet Gupta 
7808362c389SVineet Gupta /*
7818362c389SVineet Gupta  * This is API for making I/D Caches consistent when modifying
7828362c389SVineet Gupta  * kernel code (loadable modules, kprobes, kgdb...)
7838362c389SVineet Gupta  * This is called on insmod, with kernel virtual address for CODE of
7848362c389SVineet Gupta  * the module. ARC cache maintenance ops require PHY address thus we
7858362c389SVineet Gupta  * need to convert vmalloc addr to PHY addr
7868362c389SVineet Gupta  */
flush_icache_range(unsigned long kstart,unsigned long kend)7878362c389SVineet Gupta void flush_icache_range(unsigned long kstart, unsigned long kend)
7888362c389SVineet Gupta {
7898362c389SVineet Gupta 	unsigned int tot_sz;
7908362c389SVineet Gupta 
7918362c389SVineet Gupta 	WARN(kstart < TASK_SIZE, "%s() can't handle user vaddr", __func__);
7928362c389SVineet Gupta 
7938362c389SVineet Gupta 	/* Shortcut for bigger flush ranges.
7948362c389SVineet Gupta 	 * Here we don't care if this was kernel virtual or phy addr
7958362c389SVineet Gupta 	 */
7968362c389SVineet Gupta 	tot_sz = kend - kstart;
7978362c389SVineet Gupta 	if (tot_sz > PAGE_SIZE) {
7988362c389SVineet Gupta 		flush_cache_all();
7998362c389SVineet Gupta 		return;
8008362c389SVineet Gupta 	}
8018362c389SVineet Gupta 
8028362c389SVineet Gupta 	/* Case: Kernel Phy addr (0x8000_0000 onwards) */
8038362c389SVineet Gupta 	if (likely(kstart > PAGE_OFFSET)) {
8048362c389SVineet Gupta 		/*
8058362c389SVineet Gupta 		 * The 2nd arg despite being paddr will be used to index icache
8068362c389SVineet Gupta 		 * This is OK since no alternate virtual mappings will exist
8078362c389SVineet Gupta 		 * given the callers for this case: kprobe/kgdb in built-in
8088362c389SVineet Gupta 		 * kernel code only.
8098362c389SVineet Gupta 		 */
8108362c389SVineet Gupta 		__sync_icache_dcache(kstart, kstart, kend - kstart);
8118362c389SVineet Gupta 		return;
8128362c389SVineet Gupta 	}
8138362c389SVineet Gupta 
8148362c389SVineet Gupta 	/*
8158362c389SVineet Gupta 	 * Case: Kernel Vaddr (0x7000_0000 to 0x7fff_ffff)
8168362c389SVineet Gupta 	 * (1) ARC Cache Maintenance ops only take Phy addr, hence special
8178362c389SVineet Gupta 	 *     handling of kernel vaddr.
8188362c389SVineet Gupta 	 *
8198362c389SVineet Gupta 	 * (2) Despite @tot_sz being < PAGE_SIZE (bigger cases handled already),
8208362c389SVineet Gupta 	 *     it still needs to handle  a 2 page scenario, where the range
8218362c389SVineet Gupta 	 *     straddles across 2 virtual pages and hence need for loop
8228362c389SVineet Gupta 	 */
8238362c389SVineet Gupta 	while (tot_sz > 0) {
8248362c389SVineet Gupta 		unsigned int off, sz;
8258362c389SVineet Gupta 		unsigned long phy, pfn;
8268362c389SVineet Gupta 
8278362c389SVineet Gupta 		off = kstart % PAGE_SIZE;
8288362c389SVineet Gupta 		pfn = vmalloc_to_pfn((void *)kstart);
8298362c389SVineet Gupta 		phy = (pfn << PAGE_SHIFT) + off;
8308362c389SVineet Gupta 		sz = min_t(unsigned int, tot_sz, PAGE_SIZE - off);
8318362c389SVineet Gupta 		__sync_icache_dcache(phy, kstart, sz);
8328362c389SVineet Gupta 		kstart += sz;
8338362c389SVineet Gupta 		tot_sz -= sz;
8348362c389SVineet Gupta 	}
8358362c389SVineet Gupta }
8368362c389SVineet Gupta EXPORT_SYMBOL(flush_icache_range);
8378362c389SVineet Gupta 
8388362c389SVineet Gupta /*
8398362c389SVineet Gupta  * General purpose helper to make I and D cache lines consistent.
8408362c389SVineet Gupta  * @paddr is phy addr of region
8418362c389SVineet Gupta  * @vaddr is typically user vaddr (breakpoint) or kernel vaddr (vmalloc)
8428362c389SVineet Gupta  *    However in one instance, when called by kprobe (for a breakpt in
8438362c389SVineet Gupta  *    builtin kernel code) @vaddr will be paddr only, meaning CDU operation will
84463d1dfd0SJilin Yuan  *    use a paddr to index the cache (despite VIPT). This is fine since a
8458362c389SVineet Gupta  *    builtin kernel page will not have any virtual mappings.
8468362c389SVineet Gupta  *    kprobe on loadable module will be kernel vaddr.
8478362c389SVineet Gupta  */
__sync_icache_dcache(phys_addr_t paddr,unsigned long vaddr,int len)84828b4af72SVineet Gupta void __sync_icache_dcache(phys_addr_t paddr, unsigned long vaddr, int len)
8498362c389SVineet Gupta {
8508362c389SVineet Gupta 	__dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV);
8518362c389SVineet Gupta 	__ic_line_inv_vaddr(paddr, vaddr, len);
8528362c389SVineet Gupta }
8538362c389SVineet Gupta 
8548362c389SVineet Gupta /* wrapper to compile time eliminate alignment checks in flush loop */
__inv_icache_pages(phys_addr_t paddr,unsigned long vaddr,unsigned nr)855ac4cfaccSMatthew Wilcox (Oracle) void __inv_icache_pages(phys_addr_t paddr, unsigned long vaddr, unsigned nr)
8568362c389SVineet Gupta {
857ac4cfaccSMatthew Wilcox (Oracle) 	__ic_line_inv_vaddr(paddr, vaddr, nr * PAGE_SIZE);
8588362c389SVineet Gupta }
8598362c389SVineet Gupta 
8608362c389SVineet Gupta /*
8618362c389SVineet Gupta  * wrapper to clearout kernel or userspace mappings of a page
8628362c389SVineet Gupta  * For kernel mappings @vaddr == @paddr
8638362c389SVineet Gupta  */
__flush_dcache_pages(phys_addr_t paddr,unsigned long vaddr,unsigned nr)864ac4cfaccSMatthew Wilcox (Oracle) void __flush_dcache_pages(phys_addr_t paddr, unsigned long vaddr, unsigned nr)
8658362c389SVineet Gupta {
866ac4cfaccSMatthew Wilcox (Oracle) 	__dc_line_op(paddr, vaddr & PAGE_MASK, nr * PAGE_SIZE, OP_FLUSH_N_INV);
8678362c389SVineet Gupta }
8688362c389SVineet Gupta 
flush_cache_all(void)8698362c389SVineet Gupta noinline void flush_cache_all(void)
8708362c389SVineet Gupta {
8718362c389SVineet Gupta 	unsigned long flags;
8728362c389SVineet Gupta 
8738362c389SVineet Gupta 	local_irq_save(flags);
8748362c389SVineet Gupta 
8758362c389SVineet Gupta 	__ic_entire_inv();
8768362c389SVineet Gupta 	__dc_entire_op(OP_FLUSH_N_INV);
8778362c389SVineet Gupta 
8788362c389SVineet Gupta 	local_irq_restore(flags);
8798362c389SVineet Gupta 
8808362c389SVineet Gupta }
8818362c389SVineet Gupta 
copy_user_highpage(struct page * to,struct page * from,unsigned long u_vaddr,struct vm_area_struct * vma)8828362c389SVineet Gupta void copy_user_highpage(struct page *to, struct page *from,
8838362c389SVineet Gupta 	unsigned long u_vaddr, struct vm_area_struct *vma)
8848362c389SVineet Gupta {
885ac4cfaccSMatthew Wilcox (Oracle) 	struct folio *src = page_folio(from);
886ac4cfaccSMatthew Wilcox (Oracle) 	struct folio *dst = page_folio(to);
887336e2136SVineet Gupta 	void *kfrom = kmap_atomic(from);
888336e2136SVineet Gupta 	void *kto = kmap_atomic(to);
8898362c389SVineet Gupta 
890336e2136SVineet Gupta 	copy_page(kto, kfrom);
8918362c389SVineet Gupta 
892ac4cfaccSMatthew Wilcox (Oracle) 	clear_bit(PG_dc_clean, &dst->flags);
893ac4cfaccSMatthew Wilcox (Oracle) 	clear_bit(PG_dc_clean, &src->flags);
894336e2136SVineet Gupta 
895336e2136SVineet Gupta 	kunmap_atomic(kto);
896336e2136SVineet Gupta 	kunmap_atomic(kfrom);
8978362c389SVineet Gupta }
8988362c389SVineet Gupta 
clear_user_page(void * to,unsigned long u_vaddr,struct page * page)8998362c389SVineet Gupta void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
9008362c389SVineet Gupta {
901ac4cfaccSMatthew Wilcox (Oracle) 	struct folio *folio = page_folio(page);
9028362c389SVineet Gupta 	clear_page(to);
903ac4cfaccSMatthew Wilcox (Oracle) 	clear_bit(PG_dc_clean, &folio->flags);
9048362c389SVineet Gupta }
9056b5ff040SRandy Dunlap EXPORT_SYMBOL(clear_user_page);
9068362c389SVineet Gupta 
9078362c389SVineet Gupta /**********************************************************************
9088362c389SVineet Gupta  * Explicit Cache flush request from user space via syscall
9098362c389SVineet Gupta  * Needed for JITs which generate code on the fly
9108362c389SVineet Gupta  */
SYSCALL_DEFINE3(cacheflush,uint32_t,start,uint32_t,sz,uint32_t,flags)9118362c389SVineet Gupta SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags)
9128362c389SVineet Gupta {
9138362c389SVineet Gupta 	/* TBD: optimize this */
9148362c389SVineet Gupta 	flush_cache_all();
9158362c389SVineet Gupta 	return 0;
9168362c389SVineet Gupta }
9178ea2ddffSVineet Gupta 
9188c47f83bSVineet Gupta /*
9198c47f83bSVineet Gupta  * IO-Coherency (IOC) setup rules:
9208c47f83bSVineet Gupta  *
9218c47f83bSVineet Gupta  * 1. Needs to be at system level, so only once by Master core
9228c47f83bSVineet Gupta  *    Non-Masters need not be accessing caches at that time
9238c47f83bSVineet Gupta  *    - They are either HALT_ON_RESET and kick started much later or
9248c47f83bSVineet Gupta  *    - if run on reset, need to ensure that arc_platform_smp_wait_to_boot()
9258c47f83bSVineet Gupta  *      doesn't perturb caches or coherency unit
9268c47f83bSVineet Gupta  *
9278c47f83bSVineet Gupta  * 2. caches (L1 and SLC) need to be purged (flush+inv) before setting up IOC,
9288c47f83bSVineet Gupta  *    otherwise any straggler data might behave strangely post IOC enabling
9298c47f83bSVineet Gupta  *
9308c47f83bSVineet Gupta  * 3. All Caches need to be disabled when setting up IOC to elide any in-flight
9318c47f83bSVineet Gupta  *    Coherency transactions
9328c47f83bSVineet Gupta  */
arc_ioc_setup(void)9334d369680SVineet Gupta static noinline void __init arc_ioc_setup(void)
934d4911cddSVineet Gupta {
935bee91c3aSEugeniy Paltsev 	unsigned int ioc_base, mem_sz;
936e497c8e5SVineet Gupta 
9372b720e99SEugeniy Paltsev 	/*
9383624379dSEugeniy Paltsev 	 * If IOC was already enabled (due to bootloader) it technically needs to
9393624379dSEugeniy Paltsev 	 * be reconfigured with aperture base,size corresponding to Linux memory map
9403624379dSEugeniy Paltsev 	 * which will certainly be different than uboot's. But disabling and
9413624379dSEugeniy Paltsev 	 * reenabling IOC when DMA might be potentially active is tricky business.
9423624379dSEugeniy Paltsev 	 * To avoid random memory issues later, just panic here and ask user to
9433624379dSEugeniy Paltsev 	 * upgrade bootloader to one which doesn't enable IOC
9443624379dSEugeniy Paltsev 	 */
9453624379dSEugeniy Paltsev 	if (read_aux_reg(ARC_REG_IO_COH_ENABLE) & ARC_IO_COH_ENABLE_BIT)
9463624379dSEugeniy Paltsev 		panic("IOC already enabled, please upgrade bootloader!\n");
9473624379dSEugeniy Paltsev 
9483624379dSEugeniy Paltsev 	if (!ioc_enable)
9493624379dSEugeniy Paltsev 		return;
9503624379dSEugeniy Paltsev 
9518c47f83bSVineet Gupta 	/* Flush + invalidate + disable L1 dcache */
9528c47f83bSVineet Gupta 	__dc_disable();
9538c47f83bSVineet Gupta 
9548c47f83bSVineet Gupta 	/* Flush + invalidate SLC */
9558c47f83bSVineet Gupta 	if (read_aux_reg(ARC_REG_SLC_BCR))
9568c47f83bSVineet Gupta 		slc_entire_op(OP_FLUSH_N_INV);
9578c47f83bSVineet Gupta 
958e497c8e5SVineet Gupta 	/*
959bee91c3aSEugeniy Paltsev 	 * currently IOC Aperture covers entire DDR
960e497c8e5SVineet Gupta 	 * TBD: fix for PGU + 1GB of low mem
961e497c8e5SVineet Gupta 	 * TBD: fix for PAE
962e497c8e5SVineet Gupta 	 */
963bee91c3aSEugeniy Paltsev 	mem_sz = arc_get_mem_sz();
9648c47f83bSVineet Gupta 
965bee91c3aSEugeniy Paltsev 	if (!is_power_of_2(mem_sz) || mem_sz < 4096)
966bee91c3aSEugeniy Paltsev 		panic("IOC Aperture size must be power of 2 larger than 4KB");
967bee91c3aSEugeniy Paltsev 
968bee91c3aSEugeniy Paltsev 	/*
969bee91c3aSEugeniy Paltsev 	 * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
970bee91c3aSEugeniy Paltsev 	 * so setting 0x11 implies 512MB, 0x12 implies 1GB...
971bee91c3aSEugeniy Paltsev 	 */
972bee91c3aSEugeniy Paltsev 	write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, order_base_2(mem_sz >> 10) - 2);
973bee91c3aSEugeniy Paltsev 
974bee91c3aSEugeniy Paltsev 	/* for now assume kernel base is start of IOC aperture */
9759ed68785SEugeniy Paltsev 	ioc_base = CONFIG_LINUX_RAM_BASE;
976bee91c3aSEugeniy Paltsev 
977bee91c3aSEugeniy Paltsev 	if (ioc_base % mem_sz != 0)
978bee91c3aSEugeniy Paltsev 		panic("IOC Aperture start must be aligned to the size of the aperture");
979bee91c3aSEugeniy Paltsev 
980bee91c3aSEugeniy Paltsev 	write_aux_reg(ARC_REG_IO_COH_AP0_BASE, ioc_base >> 12);
9813624379dSEugeniy Paltsev 	write_aux_reg(ARC_REG_IO_COH_PARTIAL, ARC_IO_COH_PARTIAL_BIT);
9823624379dSEugeniy Paltsev 	write_aux_reg(ARC_REG_IO_COH_ENABLE, ARC_IO_COH_ENABLE_BIT);
9838c47f83bSVineet Gupta 
9848c47f83bSVineet Gupta 	/* Re-enable L1 dcache */
9858c47f83bSVineet Gupta 	__dc_enable();
986d4911cddSVineet Gupta }
987d4911cddSVineet Gupta 
988b5ddb6d5SVineet Gupta /*
989b5ddb6d5SVineet Gupta  * Cache related boot time checks/setups only needed on master CPU:
990b5ddb6d5SVineet Gupta  *  - Geometry checks (kernel build and hardware agree: e.g. L1_CACHE_BYTES)
991b5ddb6d5SVineet Gupta  *    Assume SMP only, so all cores will have same cache config. A check on
992b5ddb6d5SVineet Gupta  *    one core suffices for all
993b5ddb6d5SVineet Gupta  *  - IOC setup / dma callbacks only need to be done once
994b5ddb6d5SVineet Gupta  */
arc_cache_init_master(void)9954d369680SVineet Gupta static noinline void __init arc_cache_init_master(void)
9968ea2ddffSVineet Gupta {
9978ea2ddffSVineet Gupta 	if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
99817a5ed56SVineet Gupta 		struct cpuinfo_arc_cache *ic = &ic_info;
9998ea2ddffSVineet Gupta 
1000f64915beSVineet Gupta 		if (!ic->line_len)
10018ea2ddffSVineet Gupta 			panic("cache support enabled but non-existent cache\n");
10028ea2ddffSVineet Gupta 
10038ea2ddffSVineet Gupta 		if (ic->line_len != L1_CACHE_BYTES)
10048ea2ddffSVineet Gupta 			panic("ICache line [%d] != kernel Config [%d]",
10058ea2ddffSVineet Gupta 			      ic->line_len, L1_CACHE_BYTES);
10068ea2ddffSVineet Gupta 
1007bcc4d65aSVineet Gupta 		/*
10082547476aSAndrea Gelmini 		 * In MMU v4 (HS38x) the aliasing icache config uses IVIL/PTAG
1009bcc4d65aSVineet Gupta 		 * pair to provide vaddr/paddr respectively, just as in MMU v3
1010bcc4d65aSVineet Gupta 		 */
101117a5ed56SVineet Gupta 		if (is_isa_arcv2() && ic->colors > 1)
1012bcc4d65aSVineet Gupta 			_cache_line_loop_ic_fn = __cache_line_loop_v3;
1013bcc4d65aSVineet Gupta 		else
1014bcc4d65aSVineet Gupta 			_cache_line_loop_ic_fn = __cache_line_loop;
10158ea2ddffSVineet Gupta 	}
10168ea2ddffSVineet Gupta 
10178ea2ddffSVineet Gupta 	if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) {
101817a5ed56SVineet Gupta 		struct cpuinfo_arc_cache *dc = &dc_info;
10198ea2ddffSVineet Gupta 
1020f64915beSVineet Gupta 		if (!dc->line_len)
10218ea2ddffSVineet Gupta 			panic("cache support enabled but non-existent cache\n");
10228ea2ddffSVineet Gupta 
10238ea2ddffSVineet Gupta 		if (dc->line_len != L1_CACHE_BYTES)
10248ea2ddffSVineet Gupta 			panic("DCache line [%d] != kernel Config [%d]",
10258ea2ddffSVineet Gupta 			      dc->line_len, L1_CACHE_BYTES);
10268ea2ddffSVineet Gupta 
1027d1f317d8SVineet Gupta 		/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
1028*6732c0e4SVineet Gupta 		if (is_isa_arcompact() && dc->colors > 1) {
1029*6732c0e4SVineet Gupta 			panic("Aliasing VIPT cache not supported\n");
10308ea2ddffSVineet Gupta 		}
103108fe0079SVineet Gupta 	}
1032f2b0b25aSAlexey Brodkin 
1033386177daSEugeniy Paltsev 	/*
1034386177daSEugeniy Paltsev 	 * Check that SMP_CACHE_BYTES (and hence ARCH_DMA_MINALIGN) is larger
1035386177daSEugeniy Paltsev 	 * or equal to any cache line length.
1036386177daSEugeniy Paltsev 	 */
1037386177daSEugeniy Paltsev 	BUILD_BUG_ON_MSG(L1_CACHE_BYTES > SMP_CACHE_BYTES,
1038386177daSEugeniy Paltsev 			 "SMP_CACHE_BYTES must be >= any cache line length");
1039386177daSEugeniy Paltsev 	if (is_isa_arcv2() && (l2_line_sz > SMP_CACHE_BYTES))
1040386177daSEugeniy Paltsev 		panic("L2 Cache line [%d] > kernel Config [%d]\n",
1041386177daSEugeniy Paltsev 		      l2_line_sz, SMP_CACHE_BYTES);
1042386177daSEugeniy Paltsev 
1043d4911cddSVineet Gupta 	/* Note that SLC disable not formally supported till HS 3.0 */
1044d4911cddSVineet Gupta 	if (is_isa_arcv2() && l2_line_sz && !slc_enable)
1045d4911cddSVineet Gupta 		arc_slc_disable();
104679335a2cSVineet Gupta 
10473624379dSEugeniy Paltsev 	if (is_isa_arcv2() && ioc_exists)
1048d4911cddSVineet Gupta 		arc_ioc_setup();
104979335a2cSVineet Gupta 
10502820a708SEugeniy Paltsev 	if (is_isa_arcv2() && l2_line_sz && slc_enable) {
1051f2b0b25aSAlexey Brodkin 		__dma_cache_wback_inv = __dma_cache_wback_inv_slc;
1052f2b0b25aSAlexey Brodkin 		__dma_cache_inv = __dma_cache_inv_slc;
1053f2b0b25aSAlexey Brodkin 		__dma_cache_wback = __dma_cache_wback_slc;
1054f2b0b25aSAlexey Brodkin 	} else {
1055f2b0b25aSAlexey Brodkin 		__dma_cache_wback_inv = __dma_cache_wback_inv_l1;
1056f2b0b25aSAlexey Brodkin 		__dma_cache_inv = __dma_cache_inv_l1;
1057f2b0b25aSAlexey Brodkin 		__dma_cache_wback = __dma_cache_wback_l1;
1058f2b0b25aSAlexey Brodkin 	}
10592820a708SEugeniy Paltsev 	/*
10602820a708SEugeniy Paltsev 	 * In case of IOC (say IOC+SLC case), pointers above could still be set
10612820a708SEugeniy Paltsev 	 * but end up not being relevant as the first function in chain is not
1062356da6d0SChristoph Hellwig 	 * called at all for devices using coherent DMA.
10632820a708SEugeniy Paltsev 	 *     arch_sync_dma_for_cpu() -> dma_cache_*() -> __dma_cache_*()
10642820a708SEugeniy Paltsev 	 */
1065d1f317d8SVineet Gupta }
106676894a72SVineet Gupta 
arc_cache_init(void)106776894a72SVineet Gupta void __ref arc_cache_init(void)
106876894a72SVineet Gupta {
106976894a72SVineet Gupta 	unsigned int __maybe_unused cpu = smp_processor_id();
107076894a72SVineet Gupta 
107176894a72SVineet Gupta 	if (!cpu)
107276894a72SVineet Gupta 		arc_cache_init_master();
1073b5ddb6d5SVineet Gupta 
1074b5ddb6d5SVineet Gupta 	/*
1075b5ddb6d5SVineet Gupta 	 * In PAE regime, TLB and cache maintenance ops take wider addresses
1076b5ddb6d5SVineet Gupta 	 * And even if PAE is not enabled in kernel, the upper 32-bits still need
1077b5ddb6d5SVineet Gupta 	 * to be zeroed to keep the ops sane.
1078b5ddb6d5SVineet Gupta 	 * As an optimization for more common !PAE enabled case, zero them out
1079b5ddb6d5SVineet Gupta 	 * once at init, rather than checking/setting to 0 for every runtime op
1080b5ddb6d5SVineet Gupta 	 */
1081b5ddb6d5SVineet Gupta 	if (is_isa_arcv2() && pae40_exist_but_not_enab()) {
1082b5ddb6d5SVineet Gupta 
1083b5ddb6d5SVineet Gupta 		if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE))
1084b5ddb6d5SVineet Gupta 			write_aux_reg(ARC_REG_IC_PTAG_HI, 0);
1085b5ddb6d5SVineet Gupta 
1086b5ddb6d5SVineet Gupta 		if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE))
1087b5ddb6d5SVineet Gupta 			write_aux_reg(ARC_REG_DC_PTAG_HI, 0);
1088b5ddb6d5SVineet Gupta 
1089b5ddb6d5SVineet Gupta 		if (l2_line_sz) {
1090b5ddb6d5SVineet Gupta 			write_aux_reg(ARC_REG_SLC_RGN_END1, 0);
1091b5ddb6d5SVineet Gupta 			write_aux_reg(ARC_REG_SLC_RGN_START1, 0);
1092b5ddb6d5SVineet Gupta 		}
1093b5ddb6d5SVineet Gupta 	}
109476894a72SVineet Gupta }
1095