diff options
Diffstat (limited to 'arch/powerpc/mm/hugepage-hash64.c')
-rw-r--r-- | arch/powerpc/mm/hugepage-hash64.c | 88 |
1 files changed, 77 insertions, 11 deletions
diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c index 826893fcb3a7..5f5e6328c21c 100644 --- a/arch/powerpc/mm/hugepage-hash64.c +++ b/arch/powerpc/mm/hugepage-hash64.c | |||
@@ -18,6 +18,57 @@ | |||
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
20 | 20 | ||
21 | static void invalidate_old_hpte(unsigned long vsid, unsigned long addr, | ||
22 | pmd_t *pmdp, unsigned int psize, int ssize) | ||
23 | { | ||
24 | int i, max_hpte_count, valid; | ||
25 | unsigned long s_addr; | ||
26 | unsigned char *hpte_slot_array; | ||
27 | unsigned long hidx, shift, vpn, hash, slot; | ||
28 | |||
29 | s_addr = addr & HPAGE_PMD_MASK; | ||
30 | hpte_slot_array = get_hpte_slot_array(pmdp); | ||
31 | /* | ||
32 | * IF we try to do a HUGE PTE update after a withdraw is done. | ||
33 | * we will find the below NULL. This happens when we do | ||
34 | * split_huge_page_pmd | ||
35 | */ | ||
36 | if (!hpte_slot_array) | ||
37 | return; | ||
38 | |||
39 | if (ppc_md.hugepage_invalidate) | ||
40 | return ppc_md.hugepage_invalidate(vsid, s_addr, hpte_slot_array, | ||
41 | psize, ssize); | ||
42 | /* | ||
43 | * No bluk hpte removal support, invalidate each entry | ||
44 | */ | ||
45 | shift = mmu_psize_defs[psize].shift; | ||
46 | max_hpte_count = HPAGE_PMD_SIZE >> shift; | ||
47 | for (i = 0; i < max_hpte_count; i++) { | ||
48 | /* | ||
49 | * 8 bits per each hpte entries | ||
50 | * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit] | ||
51 | */ | ||
52 | valid = hpte_valid(hpte_slot_array, i); | ||
53 | if (!valid) | ||
54 | continue; | ||
55 | hidx = hpte_hash_index(hpte_slot_array, i); | ||
56 | |||
57 | /* get the vpn */ | ||
58 | addr = s_addr + (i * (1ul << shift)); | ||
59 | vpn = hpt_vpn(addr, vsid, ssize); | ||
60 | hash = hpt_hash(vpn, shift, ssize); | ||
61 | if (hidx & _PTEIDX_SECONDARY) | ||
62 | hash = ~hash; | ||
63 | |||
64 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
65 | slot += hidx & _PTEIDX_GROUP_IX; | ||
66 | ppc_md.hpte_invalidate(slot, vpn, psize, | ||
67 | MMU_PAGE_16M, ssize, 0); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | |||
21 | int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | 72 | int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, |
22 | pmd_t *pmdp, unsigned long trap, int local, int ssize, | 73 | pmd_t *pmdp, unsigned long trap, int local, int ssize, |
23 | unsigned int psize) | 74 | unsigned int psize) |
@@ -33,7 +84,9 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
33 | * atomically mark the linux large page PMD busy and dirty | 84 | * atomically mark the linux large page PMD busy and dirty |
34 | */ | 85 | */ |
35 | do { | 86 | do { |
36 | old_pmd = pmd_val(*pmdp); | 87 | pmd_t pmd = ACCESS_ONCE(*pmdp); |
88 | |||
89 | old_pmd = pmd_val(pmd); | ||
37 | /* If PMD busy, retry the access */ | 90 | /* If PMD busy, retry the access */ |
38 | if (unlikely(old_pmd & _PAGE_BUSY)) | 91 | if (unlikely(old_pmd & _PAGE_BUSY)) |
39 | return 0; | 92 | return 0; |
@@ -85,6 +138,15 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
85 | vpn = hpt_vpn(ea, vsid, ssize); | 138 | vpn = hpt_vpn(ea, vsid, ssize); |
86 | hash = hpt_hash(vpn, shift, ssize); | 139 | hash = hpt_hash(vpn, shift, ssize); |
87 | hpte_slot_array = get_hpte_slot_array(pmdp); | 140 | hpte_slot_array = get_hpte_slot_array(pmdp); |
141 | if (psize == MMU_PAGE_4K) { | ||
142 | /* | ||
143 | * invalidate the old hpte entry if we have that mapped via 64K | ||
144 | * base page size. This is because demote_segment won't flush | ||
145 | * hash page table entries. | ||
146 | */ | ||
147 | if ((old_pmd & _PAGE_HASHPTE) && !(old_pmd & _PAGE_COMBO)) | ||
148 | invalidate_old_hpte(vsid, ea, pmdp, MMU_PAGE_64K, ssize); | ||
149 | } | ||
88 | 150 | ||
89 | valid = hpte_valid(hpte_slot_array, index); | 151 | valid = hpte_valid(hpte_slot_array, index); |
90 | if (valid) { | 152 | if (valid) { |
@@ -107,11 +169,8 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
107 | * safely update this here. | 169 | * safely update this here. |
108 | */ | 170 | */ |
109 | valid = 0; | 171 | valid = 0; |
110 | new_pmd &= ~_PAGE_HPTEFLAGS; | ||
111 | hpte_slot_array[index] = 0; | 172 | hpte_slot_array[index] = 0; |
112 | } else | 173 | } |
113 | /* clear the busy bits and set the hash pte bits */ | ||
114 | new_pmd = (new_pmd & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE; | ||
115 | } | 174 | } |
116 | 175 | ||
117 | if (!valid) { | 176 | if (!valid) { |
@@ -119,11 +178,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
119 | 178 | ||
120 | /* insert new entry */ | 179 | /* insert new entry */ |
121 | pa = pmd_pfn(__pmd(old_pmd)) << PAGE_SHIFT; | 180 | pa = pmd_pfn(__pmd(old_pmd)) << PAGE_SHIFT; |
122 | repeat: | 181 | new_pmd |= _PAGE_HASHPTE; |
123 | hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; | ||
124 | |||
125 | /* clear the busy bits and set the hash pte bits */ | ||
126 | new_pmd = (new_pmd & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE; | ||
127 | 182 | ||
128 | /* Add in WIMG bits */ | 183 | /* Add in WIMG bits */ |
129 | rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | | 184 | rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | |
@@ -132,6 +187,8 @@ repeat: | |||
132 | * enable the memory coherence always | 187 | * enable the memory coherence always |
133 | */ | 188 | */ |
134 | rflags |= HPTE_R_M; | 189 | rflags |= HPTE_R_M; |
190 | repeat: | ||
191 | hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; | ||
135 | 192 | ||
136 | /* Insert into the hash table, primary slot */ | 193 | /* Insert into the hash table, primary slot */ |
137 | slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0, | 194 | slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0, |
@@ -172,8 +229,17 @@ repeat: | |||
172 | mark_hpte_slot_valid(hpte_slot_array, index, slot); | 229 | mark_hpte_slot_valid(hpte_slot_array, index, slot); |
173 | } | 230 | } |
174 | /* | 231 | /* |
175 | * No need to use ldarx/stdcx here | 232 | * Mark the pte with _PAGE_COMBO, if we are trying to hash it with |
233 | * base page size 4k. | ||
234 | */ | ||
235 | if (psize == MMU_PAGE_4K) | ||
236 | new_pmd |= _PAGE_COMBO; | ||
237 | /* | ||
238 | * The hpte valid is stored in the pgtable whose address is in the | ||
239 | * second half of the PMD. Order this against clearing of the busy bit in | ||
240 | * huge pmd. | ||
176 | */ | 241 | */ |
242 | smp_wmb(); | ||
177 | *pmdp = __pmd(new_pmd & ~_PAGE_BUSY); | 243 | *pmdp = __pmd(new_pmd & ~_PAGE_BUSY); |
178 | return 0; | 244 | return 0; |
179 | } | 245 | } |