162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/include/asm/tlbflush.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1999-2003 Russell King 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#ifndef _ASMARM_TLBFLUSH_H 862306a36Sopenharmony_ci#define _ASMARM_TLBFLUSH_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 1162306a36Sopenharmony_ci# include <linux/mm_types.h> 1262306a36Sopenharmony_ci#endif 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#ifdef CONFIG_MMU 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/glue.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define TLB_V4_U_PAGE (1 << 1) 1962306a36Sopenharmony_ci#define TLB_V4_D_PAGE (1 << 2) 2062306a36Sopenharmony_ci#define TLB_V4_I_PAGE (1 << 3) 2162306a36Sopenharmony_ci#define TLB_V6_U_PAGE (1 << 4) 2262306a36Sopenharmony_ci#define TLB_V6_D_PAGE (1 << 5) 2362306a36Sopenharmony_ci#define TLB_V6_I_PAGE (1 << 6) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define TLB_V4_U_FULL (1 << 9) 2662306a36Sopenharmony_ci#define TLB_V4_D_FULL (1 << 10) 2762306a36Sopenharmony_ci#define TLB_V4_I_FULL (1 << 11) 2862306a36Sopenharmony_ci#define TLB_V6_U_FULL (1 << 12) 2962306a36Sopenharmony_ci#define TLB_V6_D_FULL (1 << 13) 3062306a36Sopenharmony_ci#define TLB_V6_I_FULL (1 << 14) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define TLB_V6_U_ASID (1 << 16) 3362306a36Sopenharmony_ci#define TLB_V6_D_ASID (1 << 17) 3462306a36Sopenharmony_ci#define TLB_V6_I_ASID (1 << 18) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define TLB_V6_BP (1 << 19) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ 3962306a36Sopenharmony_ci#define TLB_V7_UIS_PAGE (1 << 20) 4062306a36Sopenharmony_ci#define TLB_V7_UIS_FULL (1 << 21) 4162306a36Sopenharmony_ci#define TLB_V7_UIS_ASID (1 << 22) 4262306a36Sopenharmony_ci#define TLB_V7_UIS_BP (1 << 23) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define TLB_BARRIER (1 << 28) 4562306a36Sopenharmony_ci#define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ 4662306a36Sopenharmony_ci#define TLB_DCLEAN (1 << 30) 4762306a36Sopenharmony_ci#define TLB_WB (1 << 31) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * MMU TLB Model 5162306a36Sopenharmony_ci * ============= 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * We have the following to choose from: 5462306a36Sopenharmony_ci * v4 - ARMv4 without write buffer 5562306a36Sopenharmony_ci * v4wb - ARMv4 with write buffer without I TLB flush entry instruction 5662306a36Sopenharmony_ci * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction 5762306a36Sopenharmony_ci * fr - Feroceon (v4wbi with non-outer-cacheable page table walks) 5862306a36Sopenharmony_ci * fa - Faraday (v4 with write buffer with UTLB) 5962306a36Sopenharmony_ci * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction 6062306a36Sopenharmony_ci * v7wbi - identical to v6wbi 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci#undef _TLB 6362306a36Sopenharmony_ci#undef MULTI_TLB 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#ifdef CONFIG_SMP_ON_UP 6662306a36Sopenharmony_ci#define MULTI_TLB 1 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_V4WT 7262306a36Sopenharmony_ci# define v4_possible_flags v4_tlb_flags 7362306a36Sopenharmony_ci# define v4_always_flags v4_tlb_flags 7462306a36Sopenharmony_ci# ifdef _TLB 7562306a36Sopenharmony_ci# define MULTI_TLB 1 7662306a36Sopenharmony_ci# else 7762306a36Sopenharmony_ci# define _TLB v4 7862306a36Sopenharmony_ci# endif 7962306a36Sopenharmony_ci#else 8062306a36Sopenharmony_ci# define v4_possible_flags 0 8162306a36Sopenharmony_ci# define v4_always_flags (-1UL) 8262306a36Sopenharmony_ci#endif 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ 8562306a36Sopenharmony_ci TLB_V4_U_FULL | TLB_V4_U_PAGE) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_FA 8862306a36Sopenharmony_ci# define fa_possible_flags fa_tlb_flags 8962306a36Sopenharmony_ci# define fa_always_flags fa_tlb_flags 9062306a36Sopenharmony_ci# ifdef _TLB 9162306a36Sopenharmony_ci# define MULTI_TLB 1 9262306a36Sopenharmony_ci# else 9362306a36Sopenharmony_ci# define _TLB fa 9462306a36Sopenharmony_ci# endif 9562306a36Sopenharmony_ci#else 9662306a36Sopenharmony_ci# define fa_possible_flags 0 9762306a36Sopenharmony_ci# define fa_always_flags (-1UL) 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define v4wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \ 10162306a36Sopenharmony_ci TLB_V4_I_FULL | TLB_V4_D_FULL | \ 10262306a36Sopenharmony_ci TLB_V4_I_PAGE | TLB_V4_D_PAGE) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_V4WBI 10562306a36Sopenharmony_ci# define v4wbi_possible_flags v4wbi_tlb_flags 10662306a36Sopenharmony_ci# define v4wbi_always_flags v4wbi_tlb_flags 10762306a36Sopenharmony_ci# ifdef _TLB 10862306a36Sopenharmony_ci# define MULTI_TLB 1 10962306a36Sopenharmony_ci# else 11062306a36Sopenharmony_ci# define _TLB v4wbi 11162306a36Sopenharmony_ci# endif 11262306a36Sopenharmony_ci#else 11362306a36Sopenharmony_ci# define v4wbi_possible_flags 0 11462306a36Sopenharmony_ci# define v4wbi_always_flags (-1UL) 11562306a36Sopenharmony_ci#endif 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define fr_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_L2CLEAN_FR | \ 11862306a36Sopenharmony_ci TLB_V4_I_FULL | TLB_V4_D_FULL | \ 11962306a36Sopenharmony_ci TLB_V4_I_PAGE | TLB_V4_D_PAGE) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_FEROCEON 12262306a36Sopenharmony_ci# define fr_possible_flags fr_tlb_flags 12362306a36Sopenharmony_ci# define fr_always_flags fr_tlb_flags 12462306a36Sopenharmony_ci# ifdef _TLB 12562306a36Sopenharmony_ci# define MULTI_TLB 1 12662306a36Sopenharmony_ci# else 12762306a36Sopenharmony_ci# define _TLB v4wbi 12862306a36Sopenharmony_ci# endif 12962306a36Sopenharmony_ci#else 13062306a36Sopenharmony_ci# define fr_possible_flags 0 13162306a36Sopenharmony_ci# define fr_always_flags (-1UL) 13262306a36Sopenharmony_ci#endif 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define v4wb_tlb_flags (TLB_WB | TLB_DCLEAN | \ 13562306a36Sopenharmony_ci TLB_V4_I_FULL | TLB_V4_D_FULL | \ 13662306a36Sopenharmony_ci TLB_V4_D_PAGE) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_V4WB 13962306a36Sopenharmony_ci# define v4wb_possible_flags v4wb_tlb_flags 14062306a36Sopenharmony_ci# define v4wb_always_flags v4wb_tlb_flags 14162306a36Sopenharmony_ci# ifdef _TLB 14262306a36Sopenharmony_ci# define MULTI_TLB 1 14362306a36Sopenharmony_ci# else 14462306a36Sopenharmony_ci# define _TLB v4wb 14562306a36Sopenharmony_ci# endif 14662306a36Sopenharmony_ci#else 14762306a36Sopenharmony_ci# define v4wb_possible_flags 0 14862306a36Sopenharmony_ci# define v4wb_always_flags (-1UL) 14962306a36Sopenharmony_ci#endif 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ 15262306a36Sopenharmony_ci TLB_V6_I_FULL | TLB_V6_D_FULL | \ 15362306a36Sopenharmony_ci TLB_V6_I_PAGE | TLB_V6_D_PAGE | \ 15462306a36Sopenharmony_ci TLB_V6_I_ASID | TLB_V6_D_ASID | \ 15562306a36Sopenharmony_ci TLB_V6_BP) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_V6 15862306a36Sopenharmony_ci# define v6wbi_possible_flags v6wbi_tlb_flags 15962306a36Sopenharmony_ci# define v6wbi_always_flags v6wbi_tlb_flags 16062306a36Sopenharmony_ci# ifdef _TLB 16162306a36Sopenharmony_ci# define MULTI_TLB 1 16262306a36Sopenharmony_ci# else 16362306a36Sopenharmony_ci# define _TLB v6wbi 16462306a36Sopenharmony_ci# endif 16562306a36Sopenharmony_ci#else 16662306a36Sopenharmony_ci# define v6wbi_possible_flags 0 16762306a36Sopenharmony_ci# define v6wbi_always_flags (-1UL) 16862306a36Sopenharmony_ci#endif 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define v7wbi_tlb_flags_smp (TLB_WB | TLB_BARRIER | \ 17162306a36Sopenharmony_ci TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | \ 17262306a36Sopenharmony_ci TLB_V7_UIS_ASID | TLB_V7_UIS_BP) 17362306a36Sopenharmony_ci#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ 17462306a36Sopenharmony_ci TLB_V6_U_FULL | TLB_V6_U_PAGE | \ 17562306a36Sopenharmony_ci TLB_V6_U_ASID | TLB_V6_BP) 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci#ifdef CONFIG_CPU_TLB_V7 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci# ifdef CONFIG_SMP_ON_UP 18062306a36Sopenharmony_ci# define v7wbi_possible_flags (v7wbi_tlb_flags_smp | v7wbi_tlb_flags_up) 18162306a36Sopenharmony_ci# define v7wbi_always_flags (v7wbi_tlb_flags_smp & v7wbi_tlb_flags_up) 18262306a36Sopenharmony_ci# elif defined(CONFIG_SMP) 18362306a36Sopenharmony_ci# define v7wbi_possible_flags v7wbi_tlb_flags_smp 18462306a36Sopenharmony_ci# define v7wbi_always_flags v7wbi_tlb_flags_smp 18562306a36Sopenharmony_ci# else 18662306a36Sopenharmony_ci# define v7wbi_possible_flags v7wbi_tlb_flags_up 18762306a36Sopenharmony_ci# define v7wbi_always_flags v7wbi_tlb_flags_up 18862306a36Sopenharmony_ci# endif 18962306a36Sopenharmony_ci# ifdef _TLB 19062306a36Sopenharmony_ci# define MULTI_TLB 1 19162306a36Sopenharmony_ci# else 19262306a36Sopenharmony_ci# define _TLB v7wbi 19362306a36Sopenharmony_ci# endif 19462306a36Sopenharmony_ci#else 19562306a36Sopenharmony_ci# define v7wbi_possible_flags 0 19662306a36Sopenharmony_ci# define v7wbi_always_flags (-1UL) 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#ifndef _TLB 20062306a36Sopenharmony_ci#error Unknown TLB model 20162306a36Sopenharmony_ci#endif 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#include <linux/sched.h> 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistruct cpu_tlb_fns { 20862306a36Sopenharmony_ci void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *); 20962306a36Sopenharmony_ci void (*flush_kern_range)(unsigned long, unsigned long); 21062306a36Sopenharmony_ci unsigned long tlb_flags; 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * Select the calling method 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci#ifdef MULTI_TLB 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range 21962306a36Sopenharmony_ci#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#else 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range) 22462306a36Sopenharmony_ci#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range) 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciextern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *); 22762306a36Sopenharmony_ciextern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#endif 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciextern struct cpu_tlb_fns cpu_tlb; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci#define __cpu_tlb_flags cpu_tlb.tlb_flags 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* 23662306a36Sopenharmony_ci * TLB Management 23762306a36Sopenharmony_ci * ============== 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * The arch/arm/mm/tlb-*.S files implement these methods. 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * The TLB specific code is expected to perform whatever tests it 24262306a36Sopenharmony_ci * needs to determine if it should invalidate the TLB for each 24362306a36Sopenharmony_ci * call. Start addresses are inclusive and end addresses are 24462306a36Sopenharmony_ci * exclusive; it is safe to round these addresses down. 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * flush_tlb_all() 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Invalidate the entire TLB. 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * flush_tlb_mm(mm) 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * Invalidate all TLB entries in a particular address 25362306a36Sopenharmony_ci * space. 25462306a36Sopenharmony_ci * - mm - mm_struct describing address space 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * flush_tlb_range(vma,start,end) 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * Invalidate a range of TLB entries in the specified 25962306a36Sopenharmony_ci * address space. 26062306a36Sopenharmony_ci * - mm - mm_struct describing address space 26162306a36Sopenharmony_ci * - start - start address (may not be aligned) 26262306a36Sopenharmony_ci * - end - end address (exclusive, may not be aligned) 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * flush_tlb_page(vma, uaddr) 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Invalidate the specified page in the specified address range. 26762306a36Sopenharmony_ci * - vma - vm_area_struct describing address range 26862306a36Sopenharmony_ci * - vaddr - virtual address (may not be aligned) 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * We optimise the code below by: 27362306a36Sopenharmony_ci * - building a set of TLB flags that might be set in __cpu_tlb_flags 27462306a36Sopenharmony_ci * - building a set of TLB flags that will always be set in __cpu_tlb_flags 27562306a36Sopenharmony_ci * - if we're going to need __cpu_tlb_flags, access it once and only once 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * This allows us to build optimal assembly for the single-CPU type case, 27862306a36Sopenharmony_ci * and as close to optimal given the compiler constrants for multi-CPU 27962306a36Sopenharmony_ci * case. We could do better for the multi-CPU case if the compiler 28062306a36Sopenharmony_ci * implemented the "%?" method, but this has been discontinued due to too 28162306a36Sopenharmony_ci * many people getting it wrong. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci#define possible_tlb_flags (v4_possible_flags | \ 28462306a36Sopenharmony_ci v4wbi_possible_flags | \ 28562306a36Sopenharmony_ci fr_possible_flags | \ 28662306a36Sopenharmony_ci v4wb_possible_flags | \ 28762306a36Sopenharmony_ci fa_possible_flags | \ 28862306a36Sopenharmony_ci v6wbi_possible_flags | \ 28962306a36Sopenharmony_ci v7wbi_possible_flags) 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#define always_tlb_flags (v4_always_flags & \ 29262306a36Sopenharmony_ci v4wbi_always_flags & \ 29362306a36Sopenharmony_ci fr_always_flags & \ 29462306a36Sopenharmony_ci v4wb_always_flags & \ 29562306a36Sopenharmony_ci fa_always_flags & \ 29662306a36Sopenharmony_ci v6wbi_always_flags & \ 29762306a36Sopenharmony_ci v7wbi_always_flags) 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f))) 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#define __tlb_op(f, insnarg, arg) \ 30262306a36Sopenharmony_ci do { \ 30362306a36Sopenharmony_ci if (always_tlb_flags & (f)) \ 30462306a36Sopenharmony_ci asm("mcr " insnarg \ 30562306a36Sopenharmony_ci : : "r" (arg) : "cc"); \ 30662306a36Sopenharmony_ci else if (possible_tlb_flags & (f)) \ 30762306a36Sopenharmony_ci asm("tst %1, %2\n\t" \ 30862306a36Sopenharmony_ci "mcrne " insnarg \ 30962306a36Sopenharmony_ci : : "r" (arg), "r" (__tlb_flag), "Ir" (f) \ 31062306a36Sopenharmony_ci : "cc"); \ 31162306a36Sopenharmony_ci } while (0) 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci#define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg) 31462306a36Sopenharmony_ci#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg) 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic inline void __local_flush_tlb_all(void) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci const int zero = 0; 31962306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero); 32262306a36Sopenharmony_ci tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero); 32362306a36Sopenharmony_ci tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic inline void local_flush_tlb_all(void) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci const int zero = 0; 32962306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 33262306a36Sopenharmony_ci dsb(nshst); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci __local_flush_tlb_all(); 33562306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) { 33862306a36Sopenharmony_ci dsb(nsh); 33962306a36Sopenharmony_ci isb(); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic inline void __flush_tlb_all(void) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci const int zero = 0; 34662306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 34962306a36Sopenharmony_ci dsb(ishst); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci __local_flush_tlb_all(); 35262306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) { 35562306a36Sopenharmony_ci dsb(ish); 35662306a36Sopenharmony_ci isb(); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic inline void __local_flush_tlb_mm(struct mm_struct *mm) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci const int zero = 0; 36362306a36Sopenharmony_ci const int asid = ASID(mm); 36462306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (possible_tlb_flags & (TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) { 36762306a36Sopenharmony_ci if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) { 36862306a36Sopenharmony_ci tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero); 36962306a36Sopenharmony_ci tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero); 37062306a36Sopenharmony_ci tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid); 37562306a36Sopenharmony_ci tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid); 37662306a36Sopenharmony_ci tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic inline void local_flush_tlb_mm(struct mm_struct *mm) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci const int asid = ASID(mm); 38262306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 38562306a36Sopenharmony_ci dsb(nshst); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci __local_flush_tlb_mm(mm); 38862306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_ASID, "c8, c7, 2", asid); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) 39162306a36Sopenharmony_ci dsb(nsh); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic inline void __flush_tlb_mm(struct mm_struct *mm) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 39962306a36Sopenharmony_ci dsb(ishst); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci __local_flush_tlb_mm(mm); 40262306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_720789 40362306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", 0); 40462306a36Sopenharmony_ci#else 40562306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", ASID(mm)); 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) 40962306a36Sopenharmony_ci dsb(ish); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic inline void 41362306a36Sopenharmony_ci__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci const int zero = 0; 41662306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (possible_tlb_flags & (TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) && 42162306a36Sopenharmony_ci cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { 42262306a36Sopenharmony_ci tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr); 42362306a36Sopenharmony_ci tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr); 42462306a36Sopenharmony_ci tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr); 42562306a36Sopenharmony_ci if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) 42662306a36Sopenharmony_ci asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr); 43062306a36Sopenharmony_ci tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr); 43162306a36Sopenharmony_ci tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic inline void 43562306a36Sopenharmony_cilocal_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 44262306a36Sopenharmony_ci dsb(nshst); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci __local_flush_tlb_page(vma, uaddr); 44562306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", uaddr); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) 44862306a36Sopenharmony_ci dsb(nsh); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic inline void 45262306a36Sopenharmony_ci__flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 45962306a36Sopenharmony_ci dsb(ishst); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci __local_flush_tlb_page(vma, uaddr); 46262306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_720789 46362306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK); 46462306a36Sopenharmony_ci#else 46562306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr); 46662306a36Sopenharmony_ci#endif 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) 46962306a36Sopenharmony_ci dsb(ish); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic inline void __local_flush_tlb_kernel_page(unsigned long kaddr) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci const int zero = 0; 47562306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr); 47862306a36Sopenharmony_ci tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr); 47962306a36Sopenharmony_ci tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr); 48062306a36Sopenharmony_ci if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) 48162306a36Sopenharmony_ci asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr); 48462306a36Sopenharmony_ci tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr); 48562306a36Sopenharmony_ci tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic inline void local_flush_tlb_kernel_page(unsigned long kaddr) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci kaddr &= PAGE_MASK; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 49562306a36Sopenharmony_ci dsb(nshst); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci __local_flush_tlb_kernel_page(kaddr); 49862306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", kaddr); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) { 50162306a36Sopenharmony_ci dsb(nsh); 50262306a36Sopenharmony_ci isb(); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic inline void __flush_tlb_kernel_page(unsigned long kaddr) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci kaddr &= PAGE_MASK; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 51362306a36Sopenharmony_ci dsb(ishst); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci __local_flush_tlb_kernel_page(kaddr); 51662306a36Sopenharmony_ci tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (tlb_flag(TLB_BARRIER)) { 51962306a36Sopenharmony_ci dsb(ish); 52062306a36Sopenharmony_ci isb(); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* 52562306a36Sopenharmony_ci * Branch predictor maintenance is paired with full TLB invalidation, so 52662306a36Sopenharmony_ci * there is no need for any barriers here. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_cistatic inline void __local_flush_bp_all(void) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci const int zero = 0; 53162306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (tlb_flag(TLB_V6_BP)) 53462306a36Sopenharmony_ci asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero)); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic inline void local_flush_bp_all(void) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci const int zero = 0; 54062306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci __local_flush_bp_all(); 54362306a36Sopenharmony_ci if (tlb_flag(TLB_V7_UIS_BP)) 54462306a36Sopenharmony_ci asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero)); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic inline void __flush_bp_all(void) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci const int zero = 0; 55062306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci __local_flush_bp_all(); 55362306a36Sopenharmony_ci if (tlb_flag(TLB_V7_UIS_BP)) 55462306a36Sopenharmony_ci asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero)); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * flush_pmd_entry 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * Flush a PMD entry (word aligned, or double-word aligned) to 56162306a36Sopenharmony_ci * RAM if the TLB for the CPU we are running on requires this. 56262306a36Sopenharmony_ci * This is typically used when we are creating PMD entries. 56362306a36Sopenharmony_ci * 56462306a36Sopenharmony_ci * clean_pmd_entry 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * Clean (but don't drain the write buffer) if the CPU requires 56762306a36Sopenharmony_ci * these operations. This is typically used when we are removing 56862306a36Sopenharmony_ci * PMD entries. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic inline void flush_pmd_entry(void *pmd) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); 57562306a36Sopenharmony_ci tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (tlb_flag(TLB_WB)) 57862306a36Sopenharmony_ci dsb(ishst); 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic inline void clean_pmd_entry(void *pmd) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci const unsigned int __tlb_flag = __cpu_tlb_flags; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); 58662306a36Sopenharmony_ci tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci#undef tlb_op 59062306a36Sopenharmony_ci#undef tlb_flag 59162306a36Sopenharmony_ci#undef always_tlb_flags 59262306a36Sopenharmony_ci#undef possible_tlb_flags 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/* 59562306a36Sopenharmony_ci * Convert calls to our calling convention. 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) 59862306a36Sopenharmony_ci#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci#ifndef CONFIG_SMP 60162306a36Sopenharmony_ci#define flush_tlb_all local_flush_tlb_all 60262306a36Sopenharmony_ci#define flush_tlb_mm local_flush_tlb_mm 60362306a36Sopenharmony_ci#define flush_tlb_page local_flush_tlb_page 60462306a36Sopenharmony_ci#define flush_tlb_kernel_page local_flush_tlb_kernel_page 60562306a36Sopenharmony_ci#define flush_tlb_range local_flush_tlb_range 60662306a36Sopenharmony_ci#define flush_tlb_kernel_range local_flush_tlb_kernel_range 60762306a36Sopenharmony_ci#define flush_bp_all local_flush_bp_all 60862306a36Sopenharmony_ci#else 60962306a36Sopenharmony_ciextern void flush_tlb_all(void); 61062306a36Sopenharmony_ciextern void flush_tlb_mm(struct mm_struct *mm); 61162306a36Sopenharmony_ciextern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr); 61262306a36Sopenharmony_ciextern void flush_tlb_kernel_page(unsigned long kaddr); 61362306a36Sopenharmony_ciextern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); 61462306a36Sopenharmony_ciextern void flush_tlb_kernel_range(unsigned long start, unsigned long end); 61562306a36Sopenharmony_ciextern void flush_bp_all(void); 61662306a36Sopenharmony_ci#endif 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/* 61962306a36Sopenharmony_ci * If PG_dcache_clean is not set for the page, we need to ensure that any 62062306a36Sopenharmony_ci * cache entries for the kernels virtual memory range are written 62162306a36Sopenharmony_ci * back to the page. On ARMv6 and later, the cache coherency is handled via 62262306a36Sopenharmony_ci * the set_ptes() function. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 62562306a36Sopenharmony_civoid update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma, 62662306a36Sopenharmony_ci unsigned long addr, pte_t *ptep, unsigned int nr); 62762306a36Sopenharmony_ci#else 62862306a36Sopenharmony_cistatic inline void update_mmu_cache_range(struct vm_fault *vmf, 62962306a36Sopenharmony_ci struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, 63062306a36Sopenharmony_ci unsigned int nr) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci#define update_mmu_cache(vma, addr, ptep) \ 63662306a36Sopenharmony_ci update_mmu_cache_range(NULL, vma, addr, ptep, 1) 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci#elif defined(CONFIG_SMP) /* !CONFIG_MMU */ 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 64562306a36Sopenharmony_cistatic inline void local_flush_tlb_all(void) { } 64662306a36Sopenharmony_cistatic inline void local_flush_tlb_mm(struct mm_struct *mm) { } 64762306a36Sopenharmony_cistatic inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) { } 64862306a36Sopenharmony_cistatic inline void local_flush_tlb_kernel_page(unsigned long kaddr) { } 64962306a36Sopenharmony_cistatic inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { } 65062306a36Sopenharmony_cistatic inline void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { } 65162306a36Sopenharmony_cistatic inline void local_flush_bp_all(void) { } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ciextern void flush_tlb_all(void); 65462306a36Sopenharmony_ciextern void flush_tlb_mm(struct mm_struct *mm); 65562306a36Sopenharmony_ciextern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr); 65662306a36Sopenharmony_ciextern void flush_tlb_kernel_page(unsigned long kaddr); 65762306a36Sopenharmony_ciextern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); 65862306a36Sopenharmony_ciextern void flush_tlb_kernel_range(unsigned long start, unsigned long end); 65962306a36Sopenharmony_ciextern void flush_bp_all(void); 66062306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci#endif 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 66562306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_798181 66662306a36Sopenharmony_ciextern void erratum_a15_798181_init(void); 66762306a36Sopenharmony_ci#else 66862306a36Sopenharmony_cistatic inline void erratum_a15_798181_init(void) {} 66962306a36Sopenharmony_ci#endif 67062306a36Sopenharmony_ciextern bool (*erratum_a15_798181_handler)(void); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic inline bool erratum_a15_798181(void) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci if (unlikely(IS_ENABLED(CONFIG_ARM_ERRATA_798181) && 67562306a36Sopenharmony_ci erratum_a15_798181_handler)) 67662306a36Sopenharmony_ci return erratum_a15_798181_handler(); 67762306a36Sopenharmony_ci return false; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci#endif 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci#endif 682