powerpc/mm: Update the HID bit when switching from radix to hash
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Wed, 24 Aug 2016 09:33:39 +0000 (15:03 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 13 Sep 2016 07:37:10 +0000 (17:37 +1000)
Power9 DD1 requires to update the hid0 register when switching from
hash to radix.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Acked-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/reg.h
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/pgtable-radix.c

index f69f40f1519ad344d6faef75f39f73de1ad845bc..9dddabc2fcedd1a61713f0a03fa3e10f25f601a5 100644 (file)
 #define HID0_POWER8_1TO4LPAR   __MASK(51)
 #define HID0_POWER8_DYNLPARDIS __MASK(48)
 
+/* POWER9 HID0 bits */
+#define HID0_POWER9_RADIX      __MASK(63 - 8)
+
 #define SPRN_HID1      0x3F1           /* Hardware Implementation Register 1 */
 #ifdef CONFIG_6xx
 #define HID1_EMCP      (1<<31)         /* 7450 Machine Check Pin Enable */
index 0821556e16f4b22e8db28071e8a429499aa5fa87..35a6721b3d25f99f53cf80e7707cdba04226d261 100644 (file)
@@ -711,6 +711,29 @@ int remove_section_mapping(unsigned long start, unsigned long end)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
+static void update_hid_for_hash(void)
+{
+       unsigned long hid0;
+       unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */
+
+       asm volatile("ptesync": : :"memory");
+       /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(0), "i"(0), "i"(2), "r"(0) : "memory");
+       asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory");
+       /*
+        * now switch the HID
+        */
+       hid0  = mfspr(SPRN_HID0);
+       hid0 &= ~HID0_POWER9_RADIX;
+       mtspr(SPRN_HID0, hid0);
+       asm volatile("isync": : :"memory");
+
+       /* Wait for it to happen */
+       while ((mfspr(SPRN_HID0) & HID0_POWER9_RADIX))
+               cpu_relax();
+}
+
 static void __init hash_init_partition_table(phys_addr_t hash_table,
                                             unsigned long htab_size)
 {
@@ -737,6 +760,8 @@ static void __init hash_init_partition_table(phys_addr_t hash_table,
         */
        partition_tb->patb1 = 0;
        pr_info("Partition table %p\n", partition_tb);
+       if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+               update_hid_for_hash();
        /*
         * update partition table control register,
         * 64 K size.
index af897d91d09f4929c06b09aadf5b67d829f13ea9..8f086352e421c3ae4e3a2879f0e166c64c8364b3 100644 (file)
@@ -294,6 +294,32 @@ found:
        return;
 }
 
+static void update_hid_for_radix(void)
+{
+       unsigned long hid0;
+       unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */
+
+       asm volatile("ptesync": : :"memory");
+       /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(1), "i"(0), "i"(2), "r"(0) : "memory");
+       /* prs = 1, ric = 2, rs = 0, r = 1 is = 3 */
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(1), "i"(1), "i"(2), "r"(0) : "memory");
+       asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory");
+       /*
+        * now switch the HID
+        */
+       hid0  = mfspr(SPRN_HID0);
+       hid0 |= HID0_POWER9_RADIX;
+       mtspr(SPRN_HID0, hid0);
+       asm volatile("isync": : :"memory");
+
+       /* Wait for it to happen */
+       while (!(mfspr(SPRN_HID0) & HID0_POWER9_RADIX))
+               cpu_relax();
+}
+
 void __init radix__early_init_mmu(void)
 {
        unsigned long lpcr;
@@ -345,6 +371,8 @@ void __init radix__early_init_mmu(void)
 
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
                radix_init_native();
+               if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+                       update_hid_for_radix();
                lpcr = mfspr(SPRN_LPCR);
                mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR);
                radix_init_partition_table();