File Index
Files and directories
Sign in
FILE

mmu_context.h

File preview with syntax highlighting.

linux-6.19.14/arch/loongarch/include/asm/mmu_context.h C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2/*
  3 * Switch a MMU context.
  4 *
  5 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  6 */
  7#ifndef _ASM_MMU_CONTEXT_H
  8#define _ASM_MMU_CONTEXT_H
  9
 10#include <linux/errno.h>
 11#include <linux/sched.h>
 12#include <linux/mm_types.h>
 13#include <linux/smp.h>
 14#include <linux/slab.h>
 15
 16#include <asm/cacheflush.h>
 17#include <asm/tlbflush.h>
 18#include <asm-generic/mm_hooks.h>
 19
 20/*
 21 *  All unused by hardware upper bits will be considered
 22 *  as a software asid extension.
 23 */
 24static inline u64 asid_version_mask(unsigned int cpu)
 25{
 26	return ~(u64)(cpu_asid_mask(&cpu_data[cpu]));
 27}
 28
 29static inline u64 asid_first_version(unsigned int cpu)
 30{
 31	return cpu_asid_mask(&cpu_data[cpu]) + 1;
 32}
 33
 34#define cpu_context(cpu, mm)	((mm)->context.asid[cpu])
 35#define asid_cache(cpu)		(cpu_data[cpu].asid_cache)
 36#define cpu_asid(cpu, mm)	(cpu_context((cpu), (mm)) & cpu_asid_mask(&cpu_data[cpu]))
 37
 38static inline int asid_valid(struct mm_struct *mm, unsigned int cpu)
 39{
 40	if ((cpu_context(cpu, mm) ^ asid_cache(cpu)) & asid_version_mask(cpu))
 41		return 0;
 42
 43	return 1;
 44}
 45
 46static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 47{
 48}
 49
 50/* Normal, classic get_new_mmu_context */
 51static inline void
 52get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, bool *need_flush)
 53{
 54	u64 asid = asid_cache(cpu);
 55
 56	if (!((++asid) & cpu_asid_mask(&cpu_data[cpu])))
 57		*need_flush = true;	/* start new asid cycle */
 58
 59	cpu_context(cpu, mm) = asid_cache(cpu) = asid;
 60}
 61
 62/*
 63 * Initialize the context related info for a new mm_struct
 64 * instance.
 65 */
 66static inline int
 67init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 68{
 69	int i;
 70
 71	for_each_possible_cpu(i)
 72		cpu_context(i, mm) = 0;
 73
 74	return 0;
 75}
 76
 77static inline void atomic_update_pgd_asid(unsigned long asid, unsigned long pgdl)
 78{
 79	__asm__ __volatile__(
 80	"csrwr %[pgdl_val], %[pgdl_reg] \n\t"
 81	"csrwr %[asid_val], %[asid_reg] \n\t"
 82	: [asid_val] "+r" (asid), [pgdl_val] "+r" (pgdl)
 83	: [asid_reg] "i" (LOONGARCH_CSR_ASID), [pgdl_reg] "i" (LOONGARCH_CSR_PGDL)
 84	: "memory"
 85	);
 86}
 87
 88static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
 89				      struct task_struct *tsk)
 90{
 91	bool need_flush = false;
 92	unsigned int cpu = smp_processor_id();
 93
 94	/* Check if our ASID is of an older version and thus invalid */
 95	if (!asid_valid(next, cpu))
 96		get_new_mmu_context(next, cpu, &need_flush);
 97
 98	if (next != &init_mm)
 99		atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)next->pgd);
100	else
101		atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)invalid_pg_dir);
102
103	if (need_flush)
104		local_flush_tlb_user(); /* Flush tlb after update ASID */
105
106	/*
107	 * Mark current->active_mm as not "active" anymore.
108	 * We don't want to mislead possible IPI tlb flush routines.
109	 */
110	cpumask_set_cpu(cpu, mm_cpumask(next));
111}
112
113#define switch_mm_irqs_off switch_mm_irqs_off
114
115static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
116			     struct task_struct *tsk)
117{
118	unsigned long flags;
119
120	local_irq_save(flags);
121	switch_mm_irqs_off(prev, next, tsk);
122	local_irq_restore(flags);
123}
124
125/*
126 * Destroy context related info for an mm_struct that is about
127 * to be put to rest.
128 */
129static inline void destroy_context(struct mm_struct *mm)
130{
131}
132
133#define activate_mm(prev, next)	switch_mm(prev, next, current)
134#define deactivate_mm(task, mm)	do { } while (0)
135
136/*
137 * If mm is currently active, we can't really drop it.
138 * Instead, we will get a new one for it.
139 */
140static inline void
141drop_mmu_context(struct mm_struct *mm, unsigned int cpu)
142{
143	int asid;
144	unsigned long flags;
145
146	local_irq_save(flags);
147
148	asid = read_csr_asid() & cpu_asid_mask(&current_cpu_data);
149
150	if (asid == cpu_asid(cpu, mm)) {
151		bool need_flush = false;
152
153		if (!current->mm || (current->mm == mm)) {
154			get_new_mmu_context(mm, cpu, &need_flush);
155
156			write_csr_asid(cpu_asid(cpu, mm));
157			if (need_flush)
158				local_flush_tlb_user(); /* Flush tlb after update ASID */
159
160			goto out;
161		}
162	}
163
164	/* Will get a new context next time */
165	cpu_context(cpu, mm) = 0;
166	cpumask_clear_cpu(cpu, mm_cpumask(mm));
167out:
168	local_irq_restore(flags);
169}
170
171#endif /* _ASM_MMU_CONTEXT_H */
~/ Read-only file preview.