2 * Copyright IBM Corporation, 2015
3 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU Lesser General Public License
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 #include <asm/machdep.h>
21 bool __rpte_sub_valid(real_pte_t rpte
, unsigned long index
)
24 unsigned long ptev
= pte_val(rpte
.pte
);
26 g_idx
= (ptev
& _PAGE_COMBO_VALID
) >> _PAGE_F_GIX_SHIFT
;
28 if (g_idx
& (0x1 << index
))
36 static unsigned long mark_subptegroup_valid(unsigned long ptev
, unsigned long index
)
40 if (!(ptev
& _PAGE_COMBO
))
45 return ptev
| (g_idx
<< _PAGE_F_GIX_SHIFT
);
48 int __hash_page_4K(unsigned long ea
, unsigned long access
, unsigned long vsid
,
49 pte_t
*ptep
, unsigned long trap
, unsigned long flags
,
50 int ssize
, int subpg_prot
)
54 unsigned long hpte_group
;
55 unsigned int subpg_index
;
56 unsigned long rflags
, pa
, hidx
;
57 unsigned long old_pte
, new_pte
, subpg_pte
;
58 unsigned long vpn
, hash
, slot
;
59 unsigned long shift
= mmu_psize_defs
[MMU_PAGE_4K
].shift
;
62 * atomically mark the linux large page PTE busy and dirty
65 pte_t pte
= READ_ONCE(*ptep
);
67 old_pte
= pte_val(pte
);
68 /* If PTE busy, retry the access */
69 if (unlikely(old_pte
& _PAGE_BUSY
))
71 /* If PTE permissions don't match, take page fault */
72 if (unlikely(access
& ~old_pte
))
75 * Try to lock the PTE, add ACCESSED and DIRTY if it was
76 * a write access. Since this is 4K insert of 64K page size
77 * also add _PAGE_COMBO
79 new_pte
= old_pte
| _PAGE_BUSY
| _PAGE_ACCESSED
| _PAGE_COMBO
;
80 if (access
& _PAGE_RW
)
81 new_pte
|= _PAGE_DIRTY
;
82 } while (old_pte
!= __cmpxchg_u64((unsigned long *)ptep
,
85 * Handle the subpage protection bits
87 subpg_pte
= new_pte
& ~subpg_prot
;
88 rflags
= htab_convert_pte_flags(subpg_pte
);
90 if (!cpu_has_feature(CPU_FTR_NOEXECUTE
) &&
91 !cpu_has_feature(CPU_FTR_COHERENT_ICACHE
)) {
94 * No CPU has hugepages but lacks no execute, so we
95 * don't need to worry about that case
97 rflags
= hash_page_do_lazy_icache(rflags
, __pte(old_pte
), trap
);
100 subpg_index
= (ea
& (PAGE_SIZE
- 1)) >> shift
;
101 vpn
= hpt_vpn(ea
, vsid
, ssize
);
102 rpte
= __real_pte(__pte(old_pte
), ptep
);
104 *None of the sub 4k page is hashed
106 if (!(old_pte
& _PAGE_HASHPTE
))
107 goto htab_insert_hpte
;
109 * Check if the pte was already inserted into the hash table
110 * as a 64k HW page, and invalidate the 64k HPTE if so.
112 if (!(old_pte
& _PAGE_COMBO
)) {
113 flush_hash_page(vpn
, rpte
, MMU_PAGE_64K
, ssize
, flags
);
115 * clear the old slot details from the old and new pte.
116 * On hash insert failure we use old pte value and we don't
117 * want slot information there if we have a insert failure.
119 old_pte
&= ~(_PAGE_HASHPTE
| _PAGE_F_GIX
| _PAGE_F_SECOND
);
120 new_pte
&= ~(_PAGE_HASHPTE
| _PAGE_F_GIX
| _PAGE_F_SECOND
);
121 goto htab_insert_hpte
;
124 * Check for sub page valid and update
126 if (__rpte_sub_valid(rpte
, subpg_index
)) {
129 hash
= hpt_hash(vpn
, shift
, ssize
);
130 hidx
= __rpte_to_hidx(rpte
, subpg_index
);
131 if (hidx
& _PTEIDX_SECONDARY
)
133 slot
= (hash
& htab_hash_mask
) * HPTES_PER_GROUP
;
134 slot
+= hidx
& _PTEIDX_GROUP_IX
;
136 ret
= ppc_md
.hpte_updatepp(slot
, rflags
, vpn
,
137 MMU_PAGE_4K
, MMU_PAGE_4K
,
140 *if we failed because typically the HPTE wasn't really here
141 * we try an insertion.
144 goto htab_insert_hpte
;
146 *ptep
= __pte(new_pte
& ~_PAGE_BUSY
);
152 * handle _PAGE_4K_PFN case
154 if (old_pte
& _PAGE_4K_PFN
) {
156 * All the sub 4k page have the same
159 pa
= pte_pfn(__pte(old_pte
)) << HW_PAGE_SHIFT
;
161 pa
= pte_pfn(__pte(old_pte
)) << PAGE_SHIFT
;
162 pa
+= (subpg_index
<< shift
);
164 hash
= hpt_hash(vpn
, shift
, ssize
);
166 hpte_group
= ((hash
& htab_hash_mask
) * HPTES_PER_GROUP
) & ~0x7UL
;
168 /* Insert into the hash table, primary slot */
169 slot
= ppc_md
.hpte_insert(hpte_group
, vpn
, pa
, rflags
, 0,
170 MMU_PAGE_4K
, MMU_PAGE_4K
, ssize
);
172 * Primary is full, try the secondary
174 if (unlikely(slot
== -1)) {
175 hpte_group
= ((~hash
& htab_hash_mask
) * HPTES_PER_GROUP
) & ~0x7UL
;
176 slot
= ppc_md
.hpte_insert(hpte_group
, vpn
, pa
,
177 rflags
, HPTE_V_SECONDARY
,
178 MMU_PAGE_4K
, MMU_PAGE_4K
, ssize
);
181 hpte_group
= ((hash
& htab_hash_mask
) *
182 HPTES_PER_GROUP
) & ~0x7UL
;
183 ppc_md
.hpte_remove(hpte_group
);
185 * FIXME!! Should be try the group from which we removed ?
191 * Hypervisor failure. Restore old pte and return -1
192 * similar to __hash_page_*
194 if (unlikely(slot
== -2)) {
195 *ptep
= __pte(old_pte
);
196 hash_failure_debug(ea
, access
, vsid
, trap
, ssize
,
197 MMU_PAGE_4K
, MMU_PAGE_4K
, old_pte
);
201 * Insert slot number & secondary bit in PTE second half,
202 * clear _PAGE_BUSY and set appropriate HPTE slot bit
203 * Since we have _PAGE_BUSY set on ptep, we can be sure
204 * nobody is undating hidx.
206 hidxp
= (unsigned long *)(ptep
+ PTRS_PER_PTE
);
207 rpte
.hidx
&= ~(0xfUL
<< (subpg_index
<< 2));
208 *hidxp
= rpte
.hidx
| (slot
<< (subpg_index
<< 2));
209 new_pte
= mark_subptegroup_valid(new_pte
, subpg_index
);
210 new_pte
|= _PAGE_HASHPTE
;
212 * check __real_pte for details on matching smp_rmb()
215 *ptep
= __pte(new_pte
& ~_PAGE_BUSY
);
219 int __hash_page_64K(unsigned long ea
, unsigned long access
,
220 unsigned long vsid
, pte_t
*ptep
, unsigned long trap
,
221 unsigned long flags
, int ssize
)
224 unsigned long hpte_group
;
225 unsigned long rflags
, pa
;
226 unsigned long old_pte
, new_pte
;
227 unsigned long vpn
, hash
, slot
;
228 unsigned long shift
= mmu_psize_defs
[MMU_PAGE_64K
].shift
;
231 * atomically mark the linux large page PTE busy and dirty
234 pte_t pte
= READ_ONCE(*ptep
);
236 old_pte
= pte_val(pte
);
237 /* If PTE busy, retry the access */
238 if (unlikely(old_pte
& _PAGE_BUSY
))
240 /* If PTE permissions don't match, take page fault */
241 if (unlikely(access
& ~old_pte
))
244 * Check if PTE has the cache-inhibit bit set
245 * If so, bail out and refault as a 4k page
247 if (!mmu_has_feature(MMU_FTR_CI_LARGE_PAGE
) &&
248 unlikely(old_pte
& _PAGE_NO_CACHE
))
251 * Try to lock the PTE, add ACCESSED and DIRTY if it was
254 new_pte
= old_pte
| _PAGE_BUSY
| _PAGE_ACCESSED
;
255 if (access
& _PAGE_RW
)
256 new_pte
|= _PAGE_DIRTY
;
257 } while (old_pte
!= __cmpxchg_u64((unsigned long *)ptep
,
260 rflags
= htab_convert_pte_flags(new_pte
);
262 if (!cpu_has_feature(CPU_FTR_NOEXECUTE
) &&
263 !cpu_has_feature(CPU_FTR_COHERENT_ICACHE
))
264 rflags
= hash_page_do_lazy_icache(rflags
, __pte(old_pte
), trap
);
266 vpn
= hpt_vpn(ea
, vsid
, ssize
);
267 if (unlikely(old_pte
& _PAGE_HASHPTE
)) {
269 * There MIGHT be an HPTE for this pte
271 hash
= hpt_hash(vpn
, shift
, ssize
);
272 if (old_pte
& _PAGE_F_SECOND
)
274 slot
= (hash
& htab_hash_mask
) * HPTES_PER_GROUP
;
275 slot
+= (old_pte
& _PAGE_F_GIX
) >> _PAGE_F_GIX_SHIFT
;
277 if (ppc_md
.hpte_updatepp(slot
, rflags
, vpn
, MMU_PAGE_64K
,
278 MMU_PAGE_64K
, ssize
, flags
) == -1)
279 old_pte
&= ~_PAGE_HPTEFLAGS
;
282 if (likely(!(old_pte
& _PAGE_HASHPTE
))) {
284 pa
= pte_pfn(__pte(old_pte
)) << PAGE_SHIFT
;
285 hash
= hpt_hash(vpn
, shift
, ssize
);
288 hpte_group
= ((hash
& htab_hash_mask
) * HPTES_PER_GROUP
) & ~0x7UL
;
290 /* Insert into the hash table, primary slot */
291 slot
= ppc_md
.hpte_insert(hpte_group
, vpn
, pa
, rflags
, 0,
292 MMU_PAGE_64K
, MMU_PAGE_64K
, ssize
);
294 * Primary is full, try the secondary
296 if (unlikely(slot
== -1)) {
297 hpte_group
= ((~hash
& htab_hash_mask
) * HPTES_PER_GROUP
) & ~0x7UL
;
298 slot
= ppc_md
.hpte_insert(hpte_group
, vpn
, pa
,
299 rflags
, HPTE_V_SECONDARY
,
300 MMU_PAGE_64K
, MMU_PAGE_64K
, ssize
);
303 hpte_group
= ((hash
& htab_hash_mask
) *
304 HPTES_PER_GROUP
) & ~0x7UL
;
305 ppc_md
.hpte_remove(hpte_group
);
307 * FIXME!! Should be try the group from which we removed ?
313 * Hypervisor failure. Restore old pte and return -1
314 * similar to __hash_page_*
316 if (unlikely(slot
== -2)) {
317 *ptep
= __pte(old_pte
);
318 hash_failure_debug(ea
, access
, vsid
, trap
, ssize
,
319 MMU_PAGE_64K
, MMU_PAGE_64K
, old_pte
);
322 new_pte
= (new_pte
& ~_PAGE_HPTEFLAGS
) | _PAGE_HASHPTE
;
323 new_pte
|= (slot
<< _PAGE_F_GIX_SHIFT
) & (_PAGE_F_SECOND
| _PAGE_F_GIX
);
325 *ptep
= __pte(new_pte
& ~_PAGE_BUSY
);