ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-arm / pgalloc.h
1 /*
2  *  linux/include/asm-arm/pgalloc.h
3  *
4  *  Copyright (C) 2000-2001 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #ifndef _ASMARM_PGALLOC_H
11 #define _ASMARM_PGALLOC_H
12
13 #include <asm/processor.h>
14 #include <asm/cacheflush.h>
15 #include <asm/tlbflush.h>
16
17 /*
18  * Since we have only two-level page tables, these are trivial
19  */
20 #define pmd_alloc_one(mm,addr)          ({ BUG(); ((pmd_t *)2); })
21 #define pmd_free(pmd)                   do { } while (0)
22 #define pgd_populate(mm,pmd,pte)        BUG()
23
24 extern pgd_t *get_pgd_slow(struct mm_struct *mm);
25 extern void free_pgd_slow(pgd_t *pgd);
26
27 #define pgd_alloc(mm)                   get_pgd_slow(mm)
28 #define pgd_free(pgd)                   free_pgd_slow(pgd)
29
30 #define check_pgt_cache()               do { } while (0)
31
32 /*
33  * Allocate one PTE table.
34  *
35  * This actually allocates two hardware PTE tables, but we wrap this up
36  * into one table thus:
37  *
38  *  +------------+
39  *  |  h/w pt 0  |
40  *  +------------+
41  *  |  h/w pt 1  |
42  *  +------------+
43  *  | Linux pt 0 |
44  *  +------------+
45  *  | Linux pt 1 |
46  *  +------------+
47  */
48 static inline pte_t *
49 pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
50 {
51         pte_t *pte;
52
53         pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
54         if (pte) {
55                 clear_page(pte);
56                 clean_dcache_area(pte, sizeof(pte_t) * PTRS_PER_PTE);
57                 pte += PTRS_PER_PTE;
58         }
59
60         return pte;
61 }
62
63 static inline struct page *
64 pte_alloc_one(struct mm_struct *mm, unsigned long addr)
65 {
66         struct page *pte;
67
68         pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);
69         if (pte) {
70                 void *page = page_address(pte);
71                 clear_page(page);
72                 clean_dcache_area(page, sizeof(pte_t) * PTRS_PER_PTE);
73         }
74
75         return pte;
76 }
77
78 /*
79  * Free one PTE table.
80  */
81 static inline void pte_free_kernel(pte_t *pte)
82 {
83         if (pte) {
84                 pte -= PTRS_PER_PTE;
85                 free_page((unsigned long)pte);
86         }
87 }
88
89 static inline void pte_free(struct page *pte)
90 {
91         __free_page(pte);
92 }
93
94 /*
95  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
96  * of the mm address space.
97  *
98  * Ensure that we always set both PMD entries.
99  */
100 static inline void
101 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
102 {
103         unsigned long pte_ptr = (unsigned long)ptep;
104         unsigned long pmdval;
105
106         BUG_ON(mm != &init_mm);
107
108         /*
109          * The pmd must be loaded with the physical
110          * address of the PTE table
111          */
112         pte_ptr -= PTRS_PER_PTE * sizeof(void *);
113         pmdval = __pa(pte_ptr) | _PAGE_KERNEL_TABLE;
114         pmdp[0] = __pmd(pmdval);
115         pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
116         flush_pmd_entry(pmdp);
117 }
118
119 static inline void
120 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep)
121 {
122         unsigned long pmdval;
123
124         BUG_ON(mm == &init_mm);
125
126         pmdval = page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE;
127         pmdp[0] = __pmd(pmdval);
128         pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
129         flush_pmd_entry(pmdp);
130 }
131
132 #endif