linux-old/include/asm-i386/pgalloc.h
<<
>>
Prefs
   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
  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 * 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
 153extern 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
 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        /* i386 does not keep any page table caches in TLB */
 231}
 232
 233#endif /* _I386_PGALLOC_H */
 234
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.