~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/asm-i386/pgalloc.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  * Allocate and free page tables. The xxx_kernel() versions are
 22  * used to allocate a kernel page table - this turns on ASN bits
 23  * if any.
 24  */
 25 
 26 extern __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 
 43 extern __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 
 56 extern __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 
 63 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 64 {
 65         free_page((unsigned long)pgd);
 66 }
 67 
 68 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 69 extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
 70 
 71 extern __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 
 83 extern __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 
 90 extern __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 
100 extern 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 
120 extern 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;
129 getnew:
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 }
138 fix:
139         __handle_bad_pmd(pmd);
140         return NULL;
141 }
142 
143 /*
144  * allocating and freeing a pmd is trivial: the 1-entry pmd is
145  * inside the pgd, so has no extra memory associated with it.
146  * (In the PAE case we free the page.)
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 
153 extern int do_check_pgt_cache(int, int);
154 
155 /*
156  * TLB flushing:
157  *
158  *  - flush_tlb() flushes the current mm struct TLBs
159  *  - flush_tlb_all() flushes all processes TLBs
160  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
161  *  - flush_tlb_page(vma, vmaddr) flushes one page
162  *  - flush_tlb_range(mm, start, end) flushes a range of pages
163  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
164  *
165  * ..but the i386 has somewhat limited tlb flushing capabilities,
166  * and page-granular flushes are available only on i486 and up.
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 
175 static inline void flush_tlb_mm(struct mm_struct *mm)
176 {
177         if (mm == current->active_mm)
178                 __flush_tlb();
179 }
180 
181 static 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 
188 static 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 
202 extern void flush_tlb_all(void);
203 extern void flush_tlb_current_task(void);
204 extern void flush_tlb_mm(struct mm_struct *);
205 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
206 
207 #define flush_tlb()     flush_tlb_current_task()
208 
209 static 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 
217 struct tlb_state
218 {
219         struct mm_struct *active_mm;
220         int state;
221 };
222 extern struct tlb_state cpu_tlbstate[NR_CPUS];
223 
224 
225 #endif
226 
227 extern inline void flush_tlb_pgtables(struct mm_struct *mm,
228                                       unsigned long start, unsigned long end)
229 {
230         /* i386 does not keep any page table caches in TLB */
231 }
232 
233 #endif /* _I386_PGALLOC_H */
234 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.