Merge master.kernel.org:/home/rmk/linux-2.6-serial
[sfrench/cifs-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/domain.h>
14 #include <asm/pgtable-hwdef.h>
15 #include <asm/processor.h>
16 #include <asm/cacheflush.h>
17 #include <asm/tlbflush.h>
18
19 #define _PAGE_USER_TABLE        (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
20 #define _PAGE_KERNEL_TABLE      (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
21
22 /*
23  * Since we have only two-level page tables, these are trivial
24  */
25 #define pmd_alloc_one(mm,addr)          ({ BUG(); ((pmd_t *)2); })
26 #define pmd_free(pmd)                   do { } while (0)
27 #define pgd_populate(mm,pmd,pte)        BUG()
28
29 extern pgd_t *get_pgd_slow(struct mm_struct *mm);
30 extern void free_pgd_slow(pgd_t *pgd);
31
32 #define pgd_alloc(mm)                   get_pgd_slow(mm)
33 #define pgd_free(pgd)                   free_pgd_slow(pgd)
34
35 #define check_pgt_cache()               do { } while (0)
36
37 /*
38  * Allocate one PTE table.
39  *
40  * This actually allocates two hardware PTE tables, but we wrap this up
41  * into one table thus:
42  *
43  *  +------------+
44  *  |  h/w pt 0  |
45  *  +------------+
46  *  |  h/w pt 1  |
47  *  +------------+
48  *  | Linux pt 0 |
49  *  +------------+
50  *  | Linux pt 1 |
51  *  +------------+
52  */
53 static inline pte_t *
54 pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
55 {
56         pte_t *pte;
57
58         pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
59         if (pte) {
60                 clean_dcache_area(pte, sizeof(pte_t) * PTRS_PER_PTE);
61                 pte += PTRS_PER_PTE;
62         }
63
64         return pte;
65 }
66
67 static inline struct page *
68 pte_alloc_one(struct mm_struct *mm, unsigned long addr)
69 {
70         struct page *pte;
71
72         pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
73         if (pte) {
74                 void *page = page_address(pte);
75                 clean_dcache_area(page, sizeof(pte_t) * PTRS_PER_PTE);
76         }
77
78         return pte;
79 }
80
81 /*
82  * Free one PTE table.
83  */
84 static inline void pte_free_kernel(pte_t *pte)
85 {
86         if (pte) {
87                 pte -= PTRS_PER_PTE;
88                 free_page((unsigned long)pte);
89         }
90 }
91
92 static inline void pte_free(struct page *pte)
93 {
94         __free_page(pte);
95 }
96
97 static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
98 {
99         pmdp[0] = __pmd(pmdval);
100         pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
101         flush_pmd_entry(pmdp);
102 }
103
104 /*
105  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
106  * of the mm address space.
107  *
108  * Ensure that we always set both PMD entries.
109  */
110 static inline void
111 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
112 {
113         unsigned long pte_ptr = (unsigned long)ptep;
114
115         /*
116          * The pmd must be loaded with the physical
117          * address of the PTE table
118          */
119         pte_ptr -= PTRS_PER_PTE * sizeof(void *);
120         __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE);
121 }
122
123 static inline void
124 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep)
125 {
126         __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
127 }
128
129 #endif