1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/mm.h>
16#include <asm/machdep.h>
17#include <asm/mmu.h>
18
19int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
20 pte_t *ptep, unsigned long trap, unsigned long flags,
21 int ssize, int subpg_prot)
22{
23 unsigned long hpte_group;
24 unsigned long rflags, pa;
25 unsigned long old_pte, new_pte;
26 unsigned long vpn, hash, slot;
27 unsigned long shift = mmu_psize_defs[MMU_PAGE_4K].shift;
28
29
30
31
32 do {
33 pte_t pte = READ_ONCE(*ptep);
34
35 old_pte = pte_val(pte);
36
37 if (unlikely(old_pte & H_PAGE_BUSY))
38 return 0;
39
40 if (unlikely(!check_pte_access(access, old_pte)))
41 return 1;
42
43
44
45
46
47 new_pte = old_pte | H_PAGE_BUSY | _PAGE_ACCESSED;
48 if (access & _PAGE_WRITE)
49 new_pte |= _PAGE_DIRTY;
50 } while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte)));
51
52
53
54
55
56 rflags = htab_convert_pte_flags(new_pte);
57
58 if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
59 !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
60 rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
61
62 vpn = hpt_vpn(ea, vsid, ssize);
63 if (unlikely(old_pte & H_PAGE_HASHPTE)) {
64
65
66
67 hash = hpt_hash(vpn, shift, ssize);
68 if (old_pte & H_PAGE_F_SECOND)
69 hash = ~hash;
70 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
71 slot += (old_pte & H_PAGE_F_GIX) >> H_PAGE_F_GIX_SHIFT;
72
73 if (mmu_hash_ops.hpte_updatepp(slot, rflags, vpn, MMU_PAGE_4K,
74 MMU_PAGE_4K, ssize, flags) == -1)
75 old_pte &= ~_PAGE_HPTEFLAGS;
76 }
77
78 if (likely(!(old_pte & H_PAGE_HASHPTE))) {
79
80 pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT;
81 hash = hpt_hash(vpn, shift, ssize);
82
83repeat:
84 hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
85
86
87 slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa, rflags, 0,
88 MMU_PAGE_4K, MMU_PAGE_4K, ssize);
89
90
91
92 if (unlikely(slot == -1)) {
93 hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
94 slot = mmu_hash_ops.hpte_insert(hpte_group, vpn, pa,
95 rflags,
96 HPTE_V_SECONDARY,
97 MMU_PAGE_4K,
98 MMU_PAGE_4K, ssize);
99 if (slot == -1) {
100 if (mftb() & 0x1)
101 hpte_group = ((hash & htab_hash_mask) *
102 HPTES_PER_GROUP) & ~0x7UL;
103 mmu_hash_ops.hpte_remove(hpte_group);
104
105
106
107 goto repeat;
108 }
109 }
110
111
112
113
114 if (unlikely(slot == -2)) {
115 *ptep = __pte(old_pte);
116 hash_failure_debug(ea, access, vsid, trap, ssize,
117 MMU_PAGE_4K, MMU_PAGE_4K, old_pte);
118 return -1;
119 }
120 new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE;
121 new_pte |= (slot << H_PAGE_F_GIX_SHIFT) &
122 (H_PAGE_F_SECOND | H_PAGE_F_GIX);
123 }
124 *ptep = __pte(new_pte & ~H_PAGE_BUSY);
125 return 0;
126}
127