cleanup
[linux-2.4.21-pre4.git] / include / asm-parisc / pgalloc.h
1 #ifndef _ASM_PGALLOC_H
2 #define _ASM_PGALLOC_H
3
4 /* The usual comment is "Caches aren't brain-dead on the <architecture>".
5  * Unfortunately, that doesn't apply to PA-RISC. */
6
7 #include <asm/processor.h>
8 #include <asm/fixmap.h>
9 #include <linux/threads.h>
10
11 #include <asm/pgtable.h>
12 #include <asm/cache.h>
13
14 #define flush_kernel_dcache_range(start,size) \
15         flush_kernel_dcache_range_asm((start), (start)+(size));
16
17 static inline void
18 flush_page_to_ram(struct page *page)
19 {
20 }
21
22 extern void flush_cache_all_local(void);
23
24 #ifdef CONFIG_SMP
25 static inline void flush_cache_all(void)
26 {
27         smp_call_function((void (*)(void *))flush_cache_all_local, NULL, 1, 1);
28         flush_cache_all_local();
29 }
30 #else
31 #define flush_cache_all flush_cache_all_local
32 #endif
33
34 #ifdef CONFIG_SMP
35 #define flush_cache_mm(mm) flush_cache_all()
36 #else
37 #define flush_cache_mm(mm) flush_cache_all_local()
38 #endif
39
40 /* The following value needs to be tuned and probably scaled with the
41  * cache size.
42  */
43
44 #define FLUSH_THRESHOLD 0x80000
45
46 static inline void
47 flush_user_dcache_range(unsigned long start, unsigned long end)
48 {
49 #ifdef CONFIG_SMP
50         flush_user_dcache_range_asm(start,end);
51 #else
52         if ((end - start) < FLUSH_THRESHOLD)
53                 flush_user_dcache_range_asm(start,end);
54         else
55                 flush_data_cache();
56 #endif
57 }
58
59 static inline void
60 flush_user_icache_range(unsigned long start, unsigned long end)
61 {
62 #ifdef CONFIG_SMP
63         flush_user_icache_range_asm(start,end);
64 #else
65         if ((end - start) < FLUSH_THRESHOLD)
66                 flush_user_icache_range_asm(start,end);
67         else
68                 flush_instruction_cache();
69 #endif
70 }
71
72 static inline void
73 flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
74 {
75         int sr3;
76
77         if (!mm->context) {
78                 BUG();
79                 return;
80         }
81
82         sr3 = mfsp(3);
83         if (mm->context == sr3) {
84                 flush_user_dcache_range(start,end);
85                 flush_user_icache_range(start,end);
86         } else {
87                 flush_cache_all();
88         }
89 }
90
91 static inline void
92 flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
93 {
94         int sr3;
95
96         if (!vma->vm_mm->context) {
97                 BUG();
98                 return;
99         }
100
101         sr3 = mfsp(3);
102         if (vma->vm_mm->context == sr3) {
103                 flush_user_dcache_range(vmaddr,vmaddr + PAGE_SIZE);
104                 if (vma->vm_flags & VM_EXEC)
105                         flush_user_icache_range(vmaddr,vmaddr + PAGE_SIZE);
106         } else {
107                 if (vma->vm_flags & VM_EXEC)
108                         flush_cache_all();
109                 else
110                         flush_data_cache();
111         }
112 }
113
114 static inline void flush_dcache_page(struct page *page)
115 {
116         if (page->mapping && !page->mapping->i_mmap &&
117                         !page->mapping->i_mmap_shared) {
118                 set_bit(PG_dcache_dirty, &page->flags);
119         } else {
120                 flush_kernel_dcache_page(page_address(page));
121         }
122 }
123
124 #define flush_icache_page(vma,page)     do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
125
126 #define flush_icache_user_range(vma, page, addr, len) \
127         flush_user_icache_range(addr, addr + len);
128
129 #define flush_icache_range(s,e)         do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
130
131 /* TLB flushing routines.... */
132
133 extern void flush_tlb_all(void);
134
135 static inline void load_context(mm_context_t context)
136 {
137         mtsp(context, 3);
138 #if SPACEID_SHIFT == 0
139         mtctl(context << 1,8);
140 #else
141         mtctl(context >> (SPACEID_SHIFT - 1),8);
142 #endif
143 }
144
145 /*
146  * flush_tlb_mm()
147  *
148  * XXX This code is NOT valid for HP-UX compatibility processes,
149  * (although it will probably work 99% of the time). HP-UX
150  * processes are free to play with the space id's and save them
151  * over long periods of time, etc. so we have to preserve the
152  * space and just flush the entire tlb. We need to check the
153  * personality in order to do that, but the personality is not
154  * currently being set correctly.
155  *
156  * Of course, Linux processes could do the same thing, but
157  * we don't support that (and the compilers, dynamic linker,
158  * etc. do not do that).
159  */
160
161 static inline void flush_tlb_mm(struct mm_struct *mm)
162 {
163         if (mm == &init_mm) BUG(); /* Should never happen */
164
165 #ifdef CONFIG_SMP
166         flush_tlb_all();
167 #else
168         if (mm) {
169                 if (mm->context != 0)
170                         free_sid(mm->context);
171                 mm->context = alloc_sid();
172                 if (mm == current->active_mm)
173                         load_context(mm->context);
174         }
175 #endif
176 }
177
178 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
179 {
180 }
181  
182 static inline void flush_tlb_page(struct vm_area_struct *vma,
183         unsigned long addr)
184 {
185         /* For one page, it's not worth testing the split_tlb variable */
186
187         mtsp(vma->vm_mm->context,1);
188         pdtlb(addr);
189         pitlb(addr);
190 }
191
192 static inline void flush_tlb_range(struct mm_struct *mm,
193         unsigned long start, unsigned long end)
194 {
195         unsigned long npages;
196
197         npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
198         if (npages >= 512)  /* XXX arbitrary, should be tuned */
199                 flush_tlb_all();
200         else {
201
202                 mtsp(mm->context,1);
203                 if (split_tlb) {
204                         while (npages--) {
205                                 pdtlb(start);
206                                 pitlb(start);
207                                 start += PAGE_SIZE;
208                         }
209                 } else {
210                         while (npages--) {
211                                 pdtlb(start);
212                                 start += PAGE_SIZE;
213                         }
214                 }
215         }
216 }
217
218 static inline pgd_t *pgd_alloc_one_fast (void)
219 {
220         return NULL; /* not implemented */
221 }
222
223 static inline pgd_t *pgd_alloc (struct mm_struct *mm)
224 {
225         /* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
226         pgd_t *pgd = pgd_alloc_one_fast();
227         if (!pgd) {
228                 pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
229                 if (pgd)
230                         clear_page(pgd);
231         }
232         return pgd;
233 }
234
235 static inline void pgd_free(pgd_t *pgd)
236 {
237         free_page((unsigned long)pgd);
238 }
239
240 #ifdef __LP64__
241
242 /* Three Level Page Table Support for pmd's */
243
244 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
245 {
246         pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)pmd);
247 }
248
249 static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
250 {
251         return NULL; /* la la */
252 }
253
254 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
255 {
256         pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
257         if (pmd)
258                 clear_page(pmd);
259         return pmd;
260 }
261
262 static inline void pmd_free(pmd_t *pmd)
263 {
264         free_page((unsigned long)pmd);
265 }
266
267 #else
268
269 /* Two Level Page Table Support for pmd's */
270
271 /*
272  * allocating and freeing a pmd is trivial: the 1-entry pmd is
273  * inside the pgd, so has no extra memory associated with it.
274  */
275
276 #define pmd_alloc_one_fast(mm, addr)    ({ BUG(); ((pmd_t *)1); })
277 #define pmd_alloc_one(mm, addr)         ({ BUG(); ((pmd_t *)2); })
278 #define pmd_free(x)                     do { } while (0)
279 #define pgd_populate(mm, pmd, pte)      BUG()
280
281 #endif
282
283 static inline void pmd_populate (struct mm_struct *mm, pmd_t *pmd_entry, pte_t *pte)
284 {
285         pmd_val(*pmd_entry) = _PAGE_TABLE + __pa((unsigned long)pte);
286 }
287
288 static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
289 {
290         return NULL; /* la la */
291 }
292
293 static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
294 {
295         pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL);
296         if (pte)
297                 clear_page(pte);
298         return pte;
299 }
300
301 static inline void pte_free(pte_t *pte)
302 {
303         free_page((unsigned long)pte);
304 }
305
306 extern int do_check_pgt_cache(int, int);
307
308 #endif