Merge branch 'master' into upstream
[pandora-kernel.git] / include / asm-x86_64 / pgalloc.h
1 #ifndef _X86_64_PGALLOC_H
2 #define _X86_64_PGALLOC_H
3
4 #include <asm/fixmap.h>
5 #include <asm/pda.h>
6 #include <linux/threads.h>
7 #include <linux/mm.h>
8
9 #define pmd_populate_kernel(mm, pmd, pte) \
10                 set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
11 #define pud_populate(mm, pud, pmd) \
12                 set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)))
13 #define pgd_populate(mm, pgd, pud) \
14                 set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)))
15
16 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
17 {
18         set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
19 }
20
21 static inline void pmd_free(pmd_t *pmd)
22 {
23         BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
24         free_page((unsigned long)pmd);
25 }
26
27 static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
28 {
29         return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
30 }
31
32 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
33 {
34         return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
35 }
36
37 static inline void pud_free (pud_t *pud)
38 {
39         BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
40         free_page((unsigned long)pud);
41 }
42
43 static inline void pgd_list_add(pgd_t *pgd)
44 {
45         struct page *page = virt_to_page(pgd);
46
47         spin_lock(&pgd_lock);
48         page->index = (pgoff_t)pgd_list;
49         if (pgd_list)
50                 pgd_list->private = (unsigned long)&page->index;
51         pgd_list = page;
52         page->private = (unsigned long)&pgd_list;
53         spin_unlock(&pgd_lock);
54 }
55
56 static inline void pgd_list_del(pgd_t *pgd)
57 {
58         struct page *next, **pprev, *page = virt_to_page(pgd);
59
60         spin_lock(&pgd_lock);
61         next = (struct page *)page->index;
62         pprev = (struct page **)page->private;
63         *pprev = next;
64         if (next)
65                 next->private = (unsigned long)pprev;
66         spin_unlock(&pgd_lock);
67 }
68
69 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
70 {
71         unsigned boundary;
72         pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
73         if (!pgd)
74                 return NULL;
75         pgd_list_add(pgd);
76         /*
77          * Copy kernel pointers in from init.
78          * Could keep a freelist or slab cache of those because the kernel
79          * part never changes.
80          */
81         boundary = pgd_index(__PAGE_OFFSET);
82         memset(pgd, 0, boundary * sizeof(pgd_t));
83         memcpy(pgd + boundary,
84                init_level4_pgt + boundary,
85                (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
86         return pgd;
87 }
88
89 static inline void pgd_free(pgd_t *pgd)
90 {
91         BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
92         pgd_list_del(pgd);
93         free_page((unsigned long)pgd);
94 }
95
96 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
97 {
98         return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
99 }
100
101 static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
102 {
103         void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
104         if (!p)
105                 return NULL;
106         return virt_to_page(p);
107 }
108
109 /* Should really implement gc for free page table pages. This could be
110    done with a reference count in struct page. */
111
112 static inline void pte_free_kernel(pte_t *pte)
113 {
114         BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
115         free_page((unsigned long)pte); 
116 }
117
118 static inline void pte_free(struct page *pte)
119 {
120         __free_page(pte);
121
122
123 #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
124
125 #define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
126 #define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
127
128 #endif /* _X86_64_PGALLOC_H */