linux-old/include/asm-i386/pgalloc.h History
<<
>>
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#define pmd_populate(mm, pmd, pte) \
  15                set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
  16
  17/*
  18 * Allocate and free page tables.
  19 */
  20
  21#if defined (CONFIG_X86_PAE)
  22/*
  23 * We can't include <linux/slab.h> here, thus these uglinesses.
  24 */
  25struct kmem_cache_s;
  26
  27extern struct kmem_cache_s *pae_pgd_cachep;
  28extern void *kmem_cache_alloc(struct kmem_cache_s *, int);
  29extern void kmem_cache_free(struct kmem_cache_s *, void *);
  30
  31
  32static inline pgd_t *get_pgd_slow(void)
  33{
  34        int i;
  35        pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
  36
  37        if (pgd) {
  38                for (i = 0; i < USER_PTRS_PER_PGD; i++) {
  39                        unsigned long pmd = __get_free_page(GFP_KERNEL);
  40                        if (!pmd)
  41                                goto out_oom;
  42                        clear_page(pmd);
  43                        set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
  44                }
  45                memcpy(pgd + USER_PTRS_PER_PGD,
  46                        swapper_pg_dir + USER_PTRS_PER_PGD,
  47                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
  48        }
  49        return pgd;
  50out_oom:
  51        for (i--; i >= 0; i--)
  52                free_page((unsigned long)__va(pgd_val(pgd[i])-1));
  53        kmem_cache_free(pae_pgd_cachep, pgd);
  54        return NULL;
  55}
  56
  57#else
  58
  59static inline pgd_t *get_pgd_slow(void)
  60{
  61        pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
  62
  63        if (pgd) {
  64                memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
  65                memcpy(pgd + USER_PTRS_PER_PGD,
  66                        swapper_pg_dir + USER_PTRS_PER_PGD,
  67                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
  68        }
  69        return pgd;
  70}
  71
  72#endif /* CONFIG_X86_PAE */
  73
  74static inline pgd_t *get_pgd_fast(void)
  75{
  76        unsigned long *ret;
  77
  78        if ((ret = pgd_quicklist) != NULL) {
  79                pgd_quicklist = (unsigned long *)(*ret);
  80                ret[0] = 0;
  81                pgtable_cache_size--;
  82        } else
  83                ret = (unsigned long *)get_pgd_slow();
  84        return (pgd_t *)ret;
  85}
  86
  87static inline void free_pgd_fast(pgd_t *pgd)
  88{
  89        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
  90        pgd_quicklist = (unsigned long *) pgd;
  91        pgtable_cache_size++;
  92}
  93
  94static inline void free_pgd_slow(pgd_t *pgd)
  95{
  96#if defined(CONFIG_X86_PAE)
  97        int i;
  98
  99        for (i = 0; i < USER_PTRS_PER_PGD; i++)
 100                free_page((unsigned long)__va(pgd_val(pgd[i])-1));
 101        kmem_cache_free(pae_pgd_cachep, pgd);
 102#else
 103        free_page((unsigned long)pgd);
 104#endif
 105}
 106
 107static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 108{
 109        pte_t *pte;
 110
 111        pte = (pte_t *) __get_free_page(GFP_KERNEL);
 112        if (pte)
 113                clear_page(pte);
 114        return pte;
 115}
 116
 117static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
 118                                        unsigned long address)
 119{
 120        unsigned long *ret;
 121
 122        if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 123                pte_quicklist = (unsigned long *)(*ret);
 124                ret[0] = ret[1];
 125                pgtable_cache_size--;
 126        }
 127        return (pte_t *)ret;
 128}
 129
 130static inline void pte_free_fast(pte_t *pte)
 131{
 132        *(unsigned long *)pte = (unsigned long) pte_quicklist;
 133        pte_quicklist = (unsigned long *) pte;
 134        pgtable_cache_size++;
 135}
 136
 137static __inline__ void pte_free_slow(pte_t *pte)
 138{
 139        free_page((unsigned long)pte);
 140}
 141
 142#define pte_free(pte)           pte_free_fast(pte)
 143#define pgd_free(pgd)           free_pgd_slow(pgd)
 144#define pgd_alloc(mm)           get_pgd_fast()
 145
 146/*
 147 * allocating and freeing a pmd is trivial: the 1-entry pmd is
 148 * inside the pgd, so has no extra memory associated with it.
 149 * (In the PAE case we free the pmds as part of the pgd.)
 150 */
 151
 152#define pmd_alloc_one_fast(mm, addr)    ({ BUG(); ((pmd_t *)1); })
 153#define pmd_alloc_one(mm, addr)         ({ BUG(); ((pmd_t *)2); })
 154#define pmd_free_slow(x)                do { } while (0)
 155#define pmd_free_fast(x)                do { } while (0)
 156#define pmd_free(x)                     do { } while (0)
 157#define pgd_populate(mm, pmd, pte)      BUG()
 158
 159extern int do_check_pgt_cache(int, int);
 160
 161/*
 162 * TLB flushing:
 163 *
 164 *  - flush_tlb() flushes the current mm struct TLBs
 165 *  - flush_tlb_all() flushes all processes TLBs
 166 *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
 167 *  - flush_tlb_page(vma, vmaddr) flushes one page
 168 *  - flush_tlb_range(mm, start, end) flushes a range of pages
 169 *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
 170 *
 171 * ..but the i386 has somewhat limited tlb flushing capabilities,
 172 * and page-granular flushes are available only on i486 and up.
 173 */
 174
 175#ifndef CONFIG_SMP
 176
 177#define flush_tlb() __flush_tlb()
 178#define flush_tlb_all() __flush_tlb_all()
 179#define local_flush_tlb() __flush_tlb()
 180
 181static inline void flush_tlb_mm(struct mm_struct *mm)
 182{
 183        if (mm == current->active_mm)
 184                __flush_tlb();
 185}
 186
 187static inline void flush_tlb_page(struct vm_area_struct *vma,
 188        unsigned long addr)
 189{
 190        if (vma->vm_mm == current->active_mm)
 191                __flush_tlb_one(addr);
 192}
 193
 194static inline void flush_tlb_range(struct mm_struct *mm,
 195        unsigned long start, unsigned long end)
 196{
 197        if (mm == current->active_mm)
 198                __flush_tlb();
 199}
 200
 201#else
 202
 203#include <asm/smp.h>
 204
 205#define local_flush_tlb() \
 206        __flush_tlb()
 207
 208extern void flush_tlb_all(void);
 209extern void flush_tlb_current_task(void);
 210extern void flush_tlb_mm(struct mm_struct *);
 211extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 212
 213#define flush_tlb()     flush_tlb_current_task()
 214
 215static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
 216{
 217        flush_tlb_mm(mm);
 218}
 219
 220#define TLBSTATE_OK     1
 221#define TLBSTATE_LAZY   2
 222
 223struct tlb_state
 224{
 225        struct mm_struct *active_mm;
 226        int state;
 227};
 228extern struct tlb_state cpu_tlbstate[NR_CPUS];
 229
 230#endif /* CONFIG_SMP */
 231
 232static inline void flush_tlb_pgtables(struct mm_struct *mm,
 233                                      unsigned long start, unsigned long end)
 234{
 235        flush_tlb_mm(mm);
 236}
 237
 238#endif /* _I386_PGALLOC_H */
 239
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.