Merge tag 'powerpc-4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-block.git] / arch / powerpc / platforms / pseries / lpar.c
index a78da511ffeb588e632f575c3fe8673aaa9e5b42..5dc1c3c6e7165bad3a404aa4b4a9940ab873f959 100644 (file)
@@ -221,7 +221,7 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
        return -1;
 }
 
-static void pSeries_lpar_hptab_clear(void)
+static void manual_hpte_clear_all(void)
 {
        unsigned long size_bytes = 1UL << ppc64_pft_size;
        unsigned long hpte_count = size_bytes >> 4;
@@ -249,6 +249,26 @@ static void pSeries_lpar_hptab_clear(void)
                                        &(ptes[j].pteh), &(ptes[j].ptel));
                }
        }
+}
+
+static int hcall_hpte_clear_all(void)
+{
+       int rc;
+
+       do {
+               rc = plpar_hcall_norets(H_CLEAR_HPT);
+       } while (rc == H_CONTINUE);
+
+       return rc;
+}
+
+static void pseries_hpte_clear_all(void)
+{
+       int rc;
+
+       rc = hcall_hpte_clear_all();
+       if (rc != H_SUCCESS)
+               manual_hpte_clear_all();
 
 #ifdef __LITTLE_ENDIAN__
        /*
@@ -598,7 +618,7 @@ void __init hpte_init_pseries(void)
        mmu_hash_ops.hpte_remove         = pSeries_lpar_hpte_remove;
        mmu_hash_ops.hpte_removebolted   = pSeries_lpar_hpte_removebolted;
        mmu_hash_ops.flush_hash_range    = pSeries_lpar_flush_hash_range;
-       mmu_hash_ops.hpte_clear_all      = pSeries_lpar_hptab_clear;
+       mmu_hash_ops.hpte_clear_all      = pseries_hpte_clear_all;
        mmu_hash_ops.hugepage_invalidate = pSeries_lpar_hugepage_invalidate;
 }