162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cache maintenance 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001 Deep Blue Solutions Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/linkage.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <asm/assembler.h> 1362306a36Sopenharmony_ci#include <asm/cpufeature.h> 1462306a36Sopenharmony_ci#include <asm/alternative.h> 1562306a36Sopenharmony_ci#include <asm/asm-uaccess.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * caches_clean_inval_pou_macro(start,end) [fixup] 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Ensure that the I and D caches are coherent within specified region. 2162306a36Sopenharmony_ci * This is typically used when code has been written to a memory region, 2262306a36Sopenharmony_ci * and will be executed. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * - start - virtual start address of region 2562306a36Sopenharmony_ci * - end - virtual end address of region 2662306a36Sopenharmony_ci * - fixup - optional label to branch to on user fault 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci.macro caches_clean_inval_pou_macro, fixup 2962306a36Sopenharmony_cialternative_if ARM64_HAS_CACHE_IDC 3062306a36Sopenharmony_ci dsb ishst 3162306a36Sopenharmony_ci b .Ldc_skip_\@ 3262306a36Sopenharmony_cialternative_else_nop_endif 3362306a36Sopenharmony_ci mov x2, x0 3462306a36Sopenharmony_ci mov x3, x1 3562306a36Sopenharmony_ci dcache_by_line_op cvau, ish, x2, x3, x4, x5, \fixup 3662306a36Sopenharmony_ci.Ldc_skip_\@: 3762306a36Sopenharmony_cialternative_if ARM64_HAS_CACHE_DIC 3862306a36Sopenharmony_ci isb 3962306a36Sopenharmony_ci b .Lic_skip_\@ 4062306a36Sopenharmony_cialternative_else_nop_endif 4162306a36Sopenharmony_ci invalidate_icache_by_line x0, x1, x2, x3, \fixup 4262306a36Sopenharmony_ci.Lic_skip_\@: 4362306a36Sopenharmony_ci.endm 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * caches_clean_inval_pou(start,end) 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Ensure that the I and D caches are coherent within specified region. 4962306a36Sopenharmony_ci * This is typically used when code has been written to a memory region, 5062306a36Sopenharmony_ci * and will be executed. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * - start - virtual start address of region 5362306a36Sopenharmony_ci * - end - virtual end address of region 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ciSYM_FUNC_START(caches_clean_inval_pou) 5662306a36Sopenharmony_ci caches_clean_inval_pou_macro 5762306a36Sopenharmony_ci ret 5862306a36Sopenharmony_ciSYM_FUNC_END(caches_clean_inval_pou) 5962306a36Sopenharmony_ciSYM_FUNC_ALIAS(__pi_caches_clean_inval_pou, caches_clean_inval_pou) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * caches_clean_inval_user_pou(start,end) 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * Ensure that the I and D caches are coherent within specified region. 6562306a36Sopenharmony_ci * This is typically used when code has been written to a memory region, 6662306a36Sopenharmony_ci * and will be executed. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * - start - virtual start address of region 6962306a36Sopenharmony_ci * - end - virtual end address of region 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ciSYM_FUNC_START(caches_clean_inval_user_pou) 7262306a36Sopenharmony_ci uaccess_ttbr0_enable x2, x3, x4 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci caches_clean_inval_pou_macro 2f 7562306a36Sopenharmony_ci mov x0, xzr 7662306a36Sopenharmony_ci1: 7762306a36Sopenharmony_ci uaccess_ttbr0_disable x1, x2 7862306a36Sopenharmony_ci ret 7962306a36Sopenharmony_ci2: 8062306a36Sopenharmony_ci mov x0, #-EFAULT 8162306a36Sopenharmony_ci b 1b 8262306a36Sopenharmony_ciSYM_FUNC_END(caches_clean_inval_user_pou) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * icache_inval_pou(start,end) 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * Ensure that the I cache is invalid within specified region. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * - start - virtual start address of region 9062306a36Sopenharmony_ci * - end - virtual end address of region 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ciSYM_FUNC_START(icache_inval_pou) 9362306a36Sopenharmony_cialternative_if ARM64_HAS_CACHE_DIC 9462306a36Sopenharmony_ci isb 9562306a36Sopenharmony_ci ret 9662306a36Sopenharmony_cialternative_else_nop_endif 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci invalidate_icache_by_line x0, x1, x2, x3 9962306a36Sopenharmony_ci ret 10062306a36Sopenharmony_ciSYM_FUNC_END(icache_inval_pou) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * dcache_clean_inval_poc(start, end) 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Ensure that any D-cache lines for the interval [start, end) 10662306a36Sopenharmony_ci * are cleaned and invalidated to the PoC. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * - start - virtual start address of region 10962306a36Sopenharmony_ci * - end - virtual end address of region 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ciSYM_FUNC_START(__pi_dcache_clean_inval_poc) 11262306a36Sopenharmony_ci dcache_by_line_op civac, sy, x0, x1, x2, x3 11362306a36Sopenharmony_ci ret 11462306a36Sopenharmony_ciSYM_FUNC_END(__pi_dcache_clean_inval_poc) 11562306a36Sopenharmony_ciSYM_FUNC_ALIAS(dcache_clean_inval_poc, __pi_dcache_clean_inval_poc) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * dcache_clean_pou(start, end) 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Ensure that any D-cache lines for the interval [start, end) 12162306a36Sopenharmony_ci * are cleaned to the PoU. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * - start - virtual start address of region 12462306a36Sopenharmony_ci * - end - virtual end address of region 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ciSYM_FUNC_START(dcache_clean_pou) 12762306a36Sopenharmony_cialternative_if ARM64_HAS_CACHE_IDC 12862306a36Sopenharmony_ci dsb ishst 12962306a36Sopenharmony_ci ret 13062306a36Sopenharmony_cialternative_else_nop_endif 13162306a36Sopenharmony_ci dcache_by_line_op cvau, ish, x0, x1, x2, x3 13262306a36Sopenharmony_ci ret 13362306a36Sopenharmony_ciSYM_FUNC_END(dcache_clean_pou) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * dcache_inval_poc(start, end) 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Ensure that any D-cache lines for the interval [start, end) 13962306a36Sopenharmony_ci * are invalidated. Any partial lines at the ends of the interval are 14062306a36Sopenharmony_ci * also cleaned to PoC to prevent data loss. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * - start - kernel start address of region 14362306a36Sopenharmony_ci * - end - kernel end address of region 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ciSYM_FUNC_START(__pi_dcache_inval_poc) 14662306a36Sopenharmony_ci dcache_line_size x2, x3 14762306a36Sopenharmony_ci sub x3, x2, #1 14862306a36Sopenharmony_ci tst x1, x3 // end cache line aligned? 14962306a36Sopenharmony_ci bic x1, x1, x3 15062306a36Sopenharmony_ci b.eq 1f 15162306a36Sopenharmony_ci dc civac, x1 // clean & invalidate D / U line 15262306a36Sopenharmony_ci1: tst x0, x3 // start cache line aligned? 15362306a36Sopenharmony_ci bic x0, x0, x3 15462306a36Sopenharmony_ci b.eq 2f 15562306a36Sopenharmony_ci dc civac, x0 // clean & invalidate D / U line 15662306a36Sopenharmony_ci b 3f 15762306a36Sopenharmony_ci2: dc ivac, x0 // invalidate D / U line 15862306a36Sopenharmony_ci3: add x0, x0, x2 15962306a36Sopenharmony_ci cmp x0, x1 16062306a36Sopenharmony_ci b.lo 2b 16162306a36Sopenharmony_ci dsb sy 16262306a36Sopenharmony_ci ret 16362306a36Sopenharmony_ciSYM_FUNC_END(__pi_dcache_inval_poc) 16462306a36Sopenharmony_ciSYM_FUNC_ALIAS(dcache_inval_poc, __pi_dcache_inval_poc) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * dcache_clean_poc(start, end) 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Ensure that any D-cache lines for the interval [start, end) 17062306a36Sopenharmony_ci * are cleaned to the PoC. 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * - start - virtual start address of region 17362306a36Sopenharmony_ci * - end - virtual end address of region 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ciSYM_FUNC_START(__pi_dcache_clean_poc) 17662306a36Sopenharmony_ci dcache_by_line_op cvac, sy, x0, x1, x2, x3 17762306a36Sopenharmony_ci ret 17862306a36Sopenharmony_ciSYM_FUNC_END(__pi_dcache_clean_poc) 17962306a36Sopenharmony_ciSYM_FUNC_ALIAS(dcache_clean_poc, __pi_dcache_clean_poc) 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* 18262306a36Sopenharmony_ci * dcache_clean_pop(start, end) 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Ensure that any D-cache lines for the interval [start, end) 18562306a36Sopenharmony_ci * are cleaned to the PoP. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * - start - virtual start address of region 18862306a36Sopenharmony_ci * - end - virtual end address of region 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ciSYM_FUNC_START(__pi_dcache_clean_pop) 19162306a36Sopenharmony_ci alternative_if_not ARM64_HAS_DCPOP 19262306a36Sopenharmony_ci b dcache_clean_poc 19362306a36Sopenharmony_ci alternative_else_nop_endif 19462306a36Sopenharmony_ci dcache_by_line_op cvap, sy, x0, x1, x2, x3 19562306a36Sopenharmony_ci ret 19662306a36Sopenharmony_ciSYM_FUNC_END(__pi_dcache_clean_pop) 19762306a36Sopenharmony_ciSYM_FUNC_ALIAS(dcache_clean_pop, __pi_dcache_clean_pop) 198