1 /*
2  * Copyright (C) 2004-2006 Atmel Corporation
3  *
4  * ASID handling taken from SH implementation.
5  *   Copyright (C) 1999 Niibe Yutaka
6  *   Copyright (C) 2003 Paul Mundt
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #ifndef __ASM_AVR32_MMU_CONTEXT_H
13 #define __ASM_AVR32_MMU_CONTEXT_H
14 
15 #include <asm/tlbflush.h>
16 #include <asm/sysreg.h>
17 #include <asm-generic/mm_hooks.h>
18 
19 /*
20  * The MMU "context" consists of two things:
21  *    (a) TLB cache version
22  *    (b) ASID (Address Space IDentifier)
23  */
24 #define MMU_CONTEXT_ASID_MASK		0x000000ff
25 #define MMU_CONTEXT_VERSION_MASK	0xffffff00
26 #define MMU_CONTEXT_FIRST_VERSION       0x00000100
27 #define NO_CONTEXT			0
28 
29 #define MMU_NO_ASID			0x100
30 
31 /* Virtual Page Number mask */
32 #define MMU_VPN_MASK	0xfffff000
33 
34 /* Cache of MMU context last used */
35 extern unsigned long mmu_context_cache;
36 
37 /*
38  * Get MMU context if needed
39  */
40 static inline void
get_mmu_context(struct mm_struct * mm)41 get_mmu_context(struct mm_struct *mm)
42 {
43 	unsigned long mc = mmu_context_cache;
44 
45 	if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
46 		/* It's up to date, do nothing */
47 		return;
48 
49 	/* It's old, we need to get new context with new version */
50 	mc = ++mmu_context_cache;
51 	if (!(mc & MMU_CONTEXT_ASID_MASK)) {
52 		/*
53 		 * We have exhausted all ASIDs of this version.
54 		 * Flush the TLB and start new cycle.
55 		 */
56 		flush_tlb_all();
57 		/*
58 		 * Fix version. Note that we avoid version #0
59 		 * to distinguish NO_CONTEXT.
60 		 */
61 		if (!mc)
62 			mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
63 	}
64 	mm->context = mc;
65 }
66 
67 /*
68  * Initialize the context related info for a new mm_struct
69  * instance.
70  */
init_new_context(struct task_struct * tsk,struct mm_struct * mm)71 static inline int init_new_context(struct task_struct *tsk,
72 				       struct mm_struct *mm)
73 {
74 	mm->context = NO_CONTEXT;
75 	return 0;
76 }
77 
78 /*
79  * Destroy context related info for an mm_struct that is about
80  * to be put to rest.
81  */
destroy_context(struct mm_struct * mm)82 static inline void destroy_context(struct mm_struct *mm)
83 {
84 	/* Do nothing */
85 }
86 
set_asid(unsigned long asid)87 static inline void set_asid(unsigned long asid)
88 {
89 	/* XXX: We're destroying TLBEHI[8:31] */
90 	sysreg_write(TLBEHI, asid & MMU_CONTEXT_ASID_MASK);
91 	cpu_sync_pipeline();
92 }
93 
get_asid(void)94 static inline unsigned long get_asid(void)
95 {
96 	unsigned long asid;
97 
98 	asid = sysreg_read(TLBEHI);
99 	return asid & MMU_CONTEXT_ASID_MASK;
100 }
101 
activate_context(struct mm_struct * mm)102 static inline void activate_context(struct mm_struct *mm)
103 {
104 	get_mmu_context(mm);
105 	set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
106 }
107 
switch_mm(struct mm_struct * prev,struct mm_struct * next,struct task_struct * tsk)108 static inline void switch_mm(struct mm_struct *prev,
109 				 struct mm_struct *next,
110 				 struct task_struct *tsk)
111 {
112 	if (likely(prev != next)) {
113 		unsigned long __pgdir = (unsigned long)next->pgd;
114 
115 		sysreg_write(PTBR, __pgdir);
116 		activate_context(next);
117 	}
118 }
119 
120 #define deactivate_mm(tsk,mm) do { } while(0)
121 
122 #define activate_mm(prev, next) switch_mm((prev), (next), NULL)
123 
124 static inline void
enter_lazy_tlb(struct mm_struct * mm,struct task_struct * tsk)125 enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
126 {
127 }
128 
129 
enable_mmu(void)130 static inline void enable_mmu(void)
131 {
132 	sysreg_write(MMUCR, (SYSREG_BIT(MMUCR_S)
133 			     | SYSREG_BIT(E)
134 			     | SYSREG_BIT(MMUCR_I)));
135 	nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop();
136 
137 	if (mmu_context_cache == NO_CONTEXT)
138 		mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
139 
140 	set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
141 }
142 
disable_mmu(void)143 static inline void disable_mmu(void)
144 {
145 	sysreg_write(MMUCR, SYSREG_BIT(MMUCR_S));
146 }
147 
148 #endif /* __ASM_AVR32_MMU_CONTEXT_H */
149