aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2016-02-08 22:32:41 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2016-03-01 06:04:18 -0500
commit27828f98a0522ad4a745a80407d051e5874c8d93 (patch)
treeaf9b66562749a261ea8b3a493d778748ea4c5ca1
parentabd0a0e7914a1137973119ac3b3cace26e8ffa96 (diff)
powerpc/mm: Handle removing maybe-present bolted HPTEs
At the moment the hpte_removebolted callback in ppc_md returns void and will BUG_ON() if the hpte it's asked to remove doesn't exist in the first place. This is awkward for the case of cleaning up a mapping which was partially made before failing. So, we add a return value to hpte_removebolted, and have it return ENOENT in the case that the HPTE to remove didn't exist in the first place. In the (sole) caller, we propagate errors in hpte_removebolted to its caller to handle. However, we handle ENOENT specially, continuing to complete the unmapping over the specified range before returning the error to the caller. This means that htab_remove_mapping() will work sanely on a partially present mapping, removing any HPTEs which are present, while also returning ENOENT to its caller in case it's important there. There are two callers of htab_remove_mapping(): - In remove_section_mapping() we already WARN_ON() any error return, which is reasonable - in this case the mapping should be fully present - In vmemmap_remove_mapping() we BUG_ON() any error. We change that to just a WARN_ON() in the case of ENOENT, since failing to remove a mapping that wasn't there in the first place probably shouldn't be fatal. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/machdep.h2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c15
-rw-r--r--arch/powerpc/mm/init_64.c9
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c9
4 files changed, 24 insertions, 11 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 5c38e49ddd42..fd22442d30a9 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -54,7 +54,7 @@ struct machdep_calls {
54 int psize, int apsize, 54 int psize, int apsize,
55 int ssize); 55 int ssize);
56 long (*hpte_remove)(unsigned long hpte_group); 56 long (*hpte_remove)(unsigned long hpte_group);
57 void (*hpte_removebolted)(unsigned long ea, 57 int (*hpte_removebolted)(unsigned long ea,
58 int psize, int ssize); 58 int psize, int ssize);
59 void (*flush_hash_range)(unsigned long number, int local); 59 void (*flush_hash_range)(unsigned long number, int local);
60 void (*hugepage_invalidate)(unsigned long vsid, 60 void (*hugepage_invalidate)(unsigned long vsid,
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 70490c41e14e..44f145a66578 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -269,6 +269,8 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend,
269{ 269{
270 unsigned long vaddr; 270 unsigned long vaddr;
271 unsigned int step, shift; 271 unsigned int step, shift;
272 int rc;
273 int ret = 0;
272 274
273 shift = mmu_psize_defs[psize].shift; 275 shift = mmu_psize_defs[psize].shift;
274 step = 1 << shift; 276 step = 1 << shift;
@@ -276,10 +278,17 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend,
276 if (!ppc_md.hpte_removebolted) 278 if (!ppc_md.hpte_removebolted)
277 return -ENODEV; 279 return -ENODEV;
278 280
279 for (vaddr = vstart; vaddr < vend; vaddr += step) 281 for (vaddr = vstart; vaddr < vend; vaddr += step) {
280 ppc_md.hpte_removebolted(vaddr, psize, ssize); 282 rc = ppc_md.hpte_removebolted(vaddr, psize, ssize);
283 if (rc == -ENOENT) {
284 ret = -ENOENT;
285 continue;
286 }
287 if (rc < 0)
288 return rc;
289 }
281 290
282 return 0; 291 return ret;
283} 292}
284#endif /* CONFIG_MEMORY_HOTPLUG */ 293#endif /* CONFIG_MEMORY_HOTPLUG */
285 294
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 379a6a90644b..baa1a23488d3 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -232,10 +232,11 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
232static void vmemmap_remove_mapping(unsigned long start, 232static void vmemmap_remove_mapping(unsigned long start,
233 unsigned long page_size) 233 unsigned long page_size)
234{ 234{
235 int mapped = htab_remove_mapping(start, start + page_size, 235 int rc = htab_remove_mapping(start, start + page_size,
236 mmu_vmemmap_psize, 236 mmu_vmemmap_psize,
237 mmu_kernel_ssize); 237 mmu_kernel_ssize);
238 BUG_ON(mapped < 0); 238 BUG_ON((rc < 0) && (rc != -ENOENT));
239 WARN_ON(rc == -ENOENT);
239} 240}
240#endif 241#endif
241 242
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 477290ad855e..2415a0d31f8f 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -505,8 +505,8 @@ static void pSeries_lpar_hugepage_invalidate(unsigned long vsid,
505} 505}
506#endif 506#endif
507 507
508static void pSeries_lpar_hpte_removebolted(unsigned long ea, 508static int pSeries_lpar_hpte_removebolted(unsigned long ea,
509 int psize, int ssize) 509 int psize, int ssize)
510{ 510{
511 unsigned long vpn; 511 unsigned long vpn;
512 unsigned long slot, vsid; 512 unsigned long slot, vsid;
@@ -515,11 +515,14 @@ static void pSeries_lpar_hpte_removebolted(unsigned long ea,
515 vpn = hpt_vpn(ea, vsid, ssize); 515 vpn = hpt_vpn(ea, vsid, ssize);
516 516
517 slot = pSeries_lpar_hpte_find(vpn, psize, ssize); 517 slot = pSeries_lpar_hpte_find(vpn, psize, ssize);
518 BUG_ON(slot == -1); 518 if (slot == -1)
519 return -ENOENT;
520
519 /* 521 /*
520 * lpar doesn't use the passed actual page size 522 * lpar doesn't use the passed actual page size
521 */ 523 */
522 pSeries_lpar_hpte_invalidate(slot, vpn, psize, 0, ssize, 0); 524 pSeries_lpar_hpte_invalidate(slot, vpn, psize, 0, ssize, 0);
525 return 0;
523} 526}
524 527
525/* 528/*