162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __ASM_ASM_ASID_H 362306a36Sopenharmony_ci#define __ASM_ASM_ASID_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/atomic.h> 662306a36Sopenharmony_ci#include <linux/compiler.h> 762306a36Sopenharmony_ci#include <linux/cpumask.h> 862306a36Sopenharmony_ci#include <linux/percpu.h> 962306a36Sopenharmony_ci#include <linux/spinlock.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct asid_info 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci atomic64_t generation; 1462306a36Sopenharmony_ci unsigned long *map; 1562306a36Sopenharmony_ci atomic64_t __percpu *active; 1662306a36Sopenharmony_ci u64 __percpu *reserved; 1762306a36Sopenharmony_ci u32 bits; 1862306a36Sopenharmony_ci /* Lock protecting the structure */ 1962306a36Sopenharmony_ci raw_spinlock_t lock; 2062306a36Sopenharmony_ci /* Which CPU requires context flush on next call */ 2162306a36Sopenharmony_ci cpumask_t flush_pending; 2262306a36Sopenharmony_ci /* Number of ASID allocated by context (shift value) */ 2362306a36Sopenharmony_ci unsigned int ctxt_shift; 2462306a36Sopenharmony_ci /* Callback to locally flush the context. */ 2562306a36Sopenharmony_ci void (*flush_cpu_ctxt_cb)(void); 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define NUM_ASIDS(info) (1UL << ((info)->bits)) 2962306a36Sopenharmony_ci#define NUM_CTXT_ASIDS(info) (NUM_ASIDS(info) >> (info)->ctxt_shift) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define active_asid(info, cpu) *per_cpu_ptr((info)->active, cpu) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_civoid asid_new_context(struct asid_info *info, atomic64_t *pasid, 3462306a36Sopenharmony_ci unsigned int cpu, struct mm_struct *mm); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * Check the ASID is still valid for the context. If not generate a new ASID. 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * @pasid: Pointer to the current ASID batch 4062306a36Sopenharmony_ci * @cpu: current CPU ID. Must have been acquired through get_cpu() 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic inline void asid_check_context(struct asid_info *info, 4362306a36Sopenharmony_ci atomic64_t *pasid, unsigned int cpu, 4462306a36Sopenharmony_ci struct mm_struct *mm) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci u64 asid, old_active_asid; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci asid = atomic64_read(pasid); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* 5162306a36Sopenharmony_ci * The memory ordering here is subtle. 5262306a36Sopenharmony_ci * If our active_asid is non-zero and the ASID matches the current 5362306a36Sopenharmony_ci * generation, then we update the active_asid entry with a relaxed 5462306a36Sopenharmony_ci * cmpxchg. Racing with a concurrent rollover means that either: 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * - We get a zero back from the cmpxchg and end up waiting on the 5762306a36Sopenharmony_ci * lock. Taking the lock synchronises with the rollover and so 5862306a36Sopenharmony_ci * we are forced to see the updated generation. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * - We get a valid ASID back from the cmpxchg, which means the 6162306a36Sopenharmony_ci * relaxed xchg in flush_context will treat us as reserved 6262306a36Sopenharmony_ci * because atomic RmWs are totally ordered for a given location. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci old_active_asid = atomic64_read(&active_asid(info, cpu)); 6562306a36Sopenharmony_ci if (old_active_asid && 6662306a36Sopenharmony_ci !((asid ^ atomic64_read(&info->generation)) >> info->bits) && 6762306a36Sopenharmony_ci atomic64_cmpxchg_relaxed(&active_asid(info, cpu), 6862306a36Sopenharmony_ci old_active_asid, asid)) 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci asid_new_context(info, pasid, cpu, mm); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciint asid_allocator_init(struct asid_info *info, 7562306a36Sopenharmony_ci u32 bits, unsigned int asid_per_ctxt, 7662306a36Sopenharmony_ci void (*flush_cpu_ctxt_cb)(void)); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#endif 79