1#ifndef _I386_PGALLOC_H
2#define _I386_PGALLOC_H
3
4#include <linux/config.h>
5#include <asm/processor.h>
6#include <asm/fixmap.h>
7#include <linux/threads.h>
8
9#define pgd_quicklist (current_cpu_data.pgd_quick)
10#define pmd_quicklist (current_cpu_data.pmd_quick)
11#define pte_quicklist (current_cpu_data.pte_quick)
12#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
13
14#if CONFIG_X86_PAE
15# include <asm/pgalloc-3level.h>
16#else
17# include <asm/pgalloc-2level.h>
18#endif
19
20
21
22
23
24
25
26extern __inline__ pgd_t *get_pgd_slow(void)
27{
28 pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
29
30 if (ret) {
31#if CONFIG_X86_PAE
32 int i;
33 for (i = 0; i < USER_PTRS_PER_PGD; i++)
34 __pgd_clear(ret + i);
35#else
36 memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
37#endif
38 memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
39 }
40 return ret;
41}
42
43extern __inline__ pgd_t *get_pgd_fast(void)
44{
45 unsigned long *ret;
46
47 if ((ret = pgd_quicklist) != NULL) {
48 pgd_quicklist = (unsigned long *)(*ret);
49 ret[0] = 0;
50 pgtable_cache_size--;
51 } else
52 ret = (unsigned long *)get_pgd_slow();
53 return (pgd_t *)ret;
54}
55
56extern __inline__ void free_pgd_fast(pgd_t *pgd)
57{
58 *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
59 pgd_quicklist = (unsigned long *) pgd;
60 pgtable_cache_size++;
61}
62
63extern __inline__ void free_pgd_slow(pgd_t *pgd)
64{
65 free_page((unsigned long)pgd);
66}
67
68extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
69extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
70
71extern __inline__ pte_t *get_pte_fast(void)
72{
73 unsigned long *ret;
74
75 if((ret = (unsigned long *)pte_quicklist) != NULL) {
76 pte_quicklist = (unsigned long *)(*ret);
77 ret[0] = ret[1];
78 pgtable_cache_size--;
79 }
80 return (pte_t *)ret;
81}
82
83extern __inline__ void free_pte_fast(pte_t *pte)
84{
85 *(unsigned long *)pte = (unsigned long) pte_quicklist;
86 pte_quicklist = (unsigned long *) pte;
87 pgtable_cache_size++;
88}
89
90extern __inline__ void free_pte_slow(pte_t *pte)
91{
92 free_page((unsigned long)pte);
93}
94
95#define pte_free_kernel(pte) free_pte_slow(pte)
96#define pte_free(pte) free_pte_slow(pte)
97#define pgd_free(pgd) free_pgd_slow(pgd)
98#define pgd_alloc() get_pgd_fast()
99
100extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
101{
102 if (!pmd)
103 BUG();
104 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
105 if (pmd_none(*pmd)) {
106 pte_t * page = (pte_t *) get_pte_fast();
107
108 if (!page)
109 return get_pte_kernel_slow(pmd, address);
110 set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page)));
111 return page + address;
112 }
113 if (pmd_bad(*pmd)) {
114 __handle_bad_pmd_kernel(pmd);
115 return NULL;
116 }
117 return (pte_t *) pmd_page(*pmd) + address;
118}
119
120extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
121{
122 address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
123
124 if (pmd_none(*pmd))
125 goto getnew;
126 if (pmd_bad(*pmd))
127 goto fix;
128 return (pte_t *)pmd_page(*pmd) + address;
129getnew:
130{
131 unsigned long page = (unsigned long) get_pte_fast();
132
133 if (!page)
134 return get_pte_slow(pmd, address);
135 set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page)));
136 return (pte_t *)page + address;
137}
138fix:
139 __handle_bad_pmd(pmd);
140 return NULL;
141}
142
143
144
145
146
147
148#define pmd_free(pmd) free_pmd_slow(pmd)
149
150#define pmd_free_kernel pmd_free
151#define pmd_alloc_kernel pmd_alloc
152
153extern int do_check_pgt_cache(int, int);
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169#ifndef CONFIG_SMP
170
171#define flush_tlb() __flush_tlb()
172#define flush_tlb_all() __flush_tlb_all()
173#define local_flush_tlb() __flush_tlb()
174
175static inline void flush_tlb_mm(struct mm_struct *mm)
176{
177 if (mm == current->active_mm)
178 __flush_tlb();
179}
180
181static inline void flush_tlb_page(struct vm_area_struct *vma,
182 unsigned long addr)
183{
184 if (vma->vm_mm == current->active_mm)
185 __flush_tlb_one(addr);
186}
187
188static inline void flush_tlb_range(struct mm_struct *mm,
189 unsigned long start, unsigned long end)
190{
191 if (mm == current->active_mm)
192 __flush_tlb();
193}
194
195#else
196
197#include <asm/smp.h>
198
199#define local_flush_tlb() \
200 __flush_tlb()
201
202extern void flush_tlb_all(void);
203extern void flush_tlb_current_task(void);
204extern void flush_tlb_mm(struct mm_struct *);
205extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
206
207#define flush_tlb() flush_tlb_current_task()
208
209static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
210{
211 flush_tlb_mm(mm);
212}
213
214#define TLBSTATE_OK 1
215#define TLBSTATE_LAZY 2
216
217struct tlb_state
218{
219 struct mm_struct *active_mm;
220 int state;
221};
222extern struct tlb_state cpu_tlbstate[NR_CPUS];
223
224
225#endif
226
227extern inline void flush_tlb_pgtables(struct mm_struct *mm,
228 unsigned long start, unsigned long end)
229{
230
231}
232
233#endif
234