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