Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / arch / arm / include / asm / hugetlb-2level.h
1 /*
2  * arch/arm/include/asm/hugetlb-2level.h
3  *
4  * Copyright (C) 2012 ARM Ltd.
5  *
6  * Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21
22 #ifndef _ASM_ARM_HUGETLB_2LEVEL_H
23 #define _ASM_ARM_HUGETLB_2LEVEL_H
24
25
26 static inline pte_t huge_ptep_get(pte_t *ptep)
27 {
28         pmd_t pmd =  *((pmd_t *)ptep);
29         u32 pmdval = pmd_val(pmd);
30         pte_t retval;
31
32         if (!pmd_val(pmd))
33                 return __pte(0);
34
35         retval = __pte((pteval_t) (pmd_val(pmd) & HPAGE_MASK)
36                         | (pmdval & 0x0c) | ((pmdval >> 8) & 0x10)
37                         | L_PTE_PRESENT | L_PTE_USER | L_PTE_VALID);
38
39         if (pmd_exec(pmd))
40                 retval = pte_mkexec(retval);
41         else
42                 retval = pte_mknexec(retval);
43
44         if (pmd_young(pmd))
45                 retval = pte_mkyoung(retval);
46         else
47                 retval = pte_mkold(retval);
48
49         if (pmd_dirty(pmd))
50                 retval = pte_mkdirty(retval);
51         else
52                 retval = pte_mkclean(retval);
53
54         if (pmd_write(pmd))
55                 retval = pte_mkwrite(retval);
56         else
57                 retval = pte_wrprotect(retval);
58
59         return retval;
60 }
61
62 static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
63                                    pte_t *ptep, pte_t pte)
64 {
65         pmdval_t pmdval = (pmdval_t) pte_val(pte);
66         pmd_t *pmdp = (pmd_t *) ptep;
67
68         /* take the target address bits from the pte only */
69         pmdval &= HPAGE_MASK;
70
71         /*
72          * now use pmd_modify to translate the permission bits from the pte
73          * and set the memory type information.
74          */
75         pmdval = pmd_val(pmd_modify(__pmd(pmdval), __pgprot(pte_val(pte))));
76
77         __sync_icache_dcache(pte);
78
79         set_pmd_at(mm, addr, pmdp, __pmd(pmdval));
80 }
81
82 static inline pte_t pte_mkhuge(pte_t pte) { return pte; }
83
84 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
85                                          unsigned long addr, pte_t *ptep)
86 {
87         pmd_t *pmdp = (pmd_t *)ptep;
88         pmd_clear(pmdp);
89         flush_tlb_range(vma, addr, addr + HPAGE_SIZE);
90 }
91
92 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
93                                            unsigned long addr, pte_t *ptep)
94 {
95         pmd_t *pmdp = (pmd_t *) ptep;
96         set_pmd_at(mm, addr, pmdp, pmd_wrprotect(*pmdp));
97 }
98
99
100 static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
101                                             unsigned long addr, pte_t *ptep)
102 {
103         pmd_t *pmdp = (pmd_t *)ptep;
104         pte_t pte = huge_ptep_get(ptep);
105         pmd_clear(pmdp);
106
107         return pte;
108 }
109
110 static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
111                                              unsigned long addr, pte_t *ptep,
112                                              pte_t pte, int dirty)
113 {
114         int changed = !pte_same(huge_ptep_get(ptep), pte);
115         if (changed) {
116                 set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
117                 flush_tlb_range(vma, addr, addr + HPAGE_SIZE);
118         }
119
120         return changed;
121 }
122
123 #endif /* _ASM_ARM_HUGETLB_2LEVEL_H */