diff options
| -rw-r--r-- | arch/powerpc/kernel/cpu_setup_power.S | 13 | ||||
| -rw-r--r-- | arch/powerpc/kernel/dt_cpu_ftrs.c | 16 | ||||
| -rw-r--r-- | arch/powerpc/kernel/mce_power.c | 56 |
3 files changed, 67 insertions, 18 deletions
diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 10cb2896b2ae..610955fe8b81 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S | |||
| @@ -218,13 +218,20 @@ __init_tlb_power8: | |||
| 218 | ptesync | 218 | ptesync |
| 219 | 1: blr | 219 | 1: blr |
| 220 | 220 | ||
| 221 | /* | ||
| 222 | * Flush the TLB in hash mode. Hash must flush with RIC=2 once for process | ||
| 223 | * and one for partition scope to clear process and partition table entries. | ||
| 224 | */ | ||
| 221 | __init_tlb_power9: | 225 | __init_tlb_power9: |
| 222 | li r6,POWER9_TLB_SETS_HASH | 226 | li r6,POWER9_TLB_SETS_HASH - 1 |
| 223 | mtctr r6 | 227 | mtctr r6 |
| 224 | li r7,0xc00 /* IS field = 0b11 */ | 228 | li r7,0xc00 /* IS field = 0b11 */ |
| 229 | li r8,0 | ||
| 225 | ptesync | 230 | ptesync |
| 226 | 2: tlbiel r7 | 231 | PPC_TLBIEL(7, 8, 2, 1, 0) |
| 227 | addi r7,r7,0x1000 | 232 | PPC_TLBIEL(7, 8, 2, 0, 0) |
| 233 | 2: addi r7,r7,0x1000 | ||
| 234 | PPC_TLBIEL(7, 8, 0, 0, 0) | ||
| 228 | bdnz 2b | 235 | bdnz 2b |
| 229 | ptesync | 236 | ptesync |
| 230 | 1: blr | 237 | 1: blr |
diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 4c7656dc4e04..1df770e8cbe0 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c | |||
| @@ -94,9 +94,6 @@ static void (*init_pmu_registers)(void); | |||
| 94 | 94 | ||
| 95 | static void cpufeatures_flush_tlb(void) | 95 | static void cpufeatures_flush_tlb(void) |
| 96 | { | 96 | { |
| 97 | unsigned long rb; | ||
| 98 | unsigned int i, num_sets; | ||
| 99 | |||
| 100 | /* | 97 | /* |
| 101 | * This is a temporary measure to keep equivalent TLB flush as the | 98 | * This is a temporary measure to keep equivalent TLB flush as the |
| 102 | * cputable based setup code. | 99 | * cputable based setup code. |
| @@ -105,24 +102,15 @@ static void cpufeatures_flush_tlb(void) | |||
| 105 | case PVR_POWER8: | 102 | case PVR_POWER8: |
| 106 | case PVR_POWER8E: | 103 | case PVR_POWER8E: |
| 107 | case PVR_POWER8NVL: | 104 | case PVR_POWER8NVL: |
| 108 | num_sets = POWER8_TLB_SETS; | 105 | __flush_tlb_power8(POWER8_TLB_SETS); |
| 109 | break; | 106 | break; |
| 110 | case PVR_POWER9: | 107 | case PVR_POWER9: |
| 111 | num_sets = POWER9_TLB_SETS_HASH; | 108 | __flush_tlb_power9(POWER9_TLB_SETS_HASH); |
| 112 | break; | 109 | break; |
| 113 | default: | 110 | default: |
| 114 | num_sets = 1; | ||
| 115 | pr_err("unknown CPU version for boot TLB flush\n"); | 111 | pr_err("unknown CPU version for boot TLB flush\n"); |
| 116 | break; | 112 | break; |
| 117 | } | 113 | } |
| 118 | |||
| 119 | asm volatile("ptesync" : : : "memory"); | ||
| 120 | rb = TLBIEL_INVAL_SET; | ||
| 121 | for (i = 0; i < num_sets; i++) { | ||
| 122 | asm volatile("tlbiel %0" : : "r" (rb)); | ||
| 123 | rb += 1 << TLBIEL_INVAL_SET_SHIFT; | ||
| 124 | } | ||
| 125 | asm volatile("ptesync" : : : "memory"); | ||
| 126 | } | 114 | } |
| 127 | 115 | ||
| 128 | static void __restore_cpu_cpufeatures(void) | 116 | static void __restore_cpu_cpufeatures(void) |
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index d24e689e893f..b76ca198e09c 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c | |||
| @@ -53,6 +53,60 @@ static void flush_tlb_206(unsigned int num_sets, unsigned int action) | |||
| 53 | asm volatile("ptesync" : : : "memory"); | 53 | asm volatile("ptesync" : : : "memory"); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static void flush_tlb_300(unsigned int num_sets, unsigned int action) | ||
| 57 | { | ||
| 58 | unsigned long rb; | ||
| 59 | unsigned int i; | ||
| 60 | unsigned int r; | ||
| 61 | |||
| 62 | switch (action) { | ||
| 63 | case TLB_INVAL_SCOPE_GLOBAL: | ||
| 64 | rb = TLBIEL_INVAL_SET; | ||
| 65 | break; | ||
| 66 | case TLB_INVAL_SCOPE_LPID: | ||
| 67 | rb = TLBIEL_INVAL_SET_LPID; | ||
| 68 | break; | ||
| 69 | default: | ||
| 70 | BUG(); | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | |||
| 74 | asm volatile("ptesync" : : : "memory"); | ||
| 75 | |||
| 76 | if (early_radix_enabled()) | ||
| 77 | r = 1; | ||
| 78 | else | ||
| 79 | r = 0; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * First flush table/PWC caches with set 0, then flush the | ||
| 83 | * rest of the sets, partition scope. Radix must then do it | ||
| 84 | * all again with process scope. Hash just has to flush | ||
| 85 | * process table. | ||
| 86 | */ | ||
| 87 | asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : : | ||
| 88 | "r"(rb), "r"(0), "i"(2), "i"(0), "r"(r)); | ||
| 89 | for (i = 1; i < num_sets; i++) { | ||
| 90 | unsigned long set = i * (1<<TLBIEL_INVAL_SET_SHIFT); | ||
| 91 | |||
| 92 | asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : : | ||
| 93 | "r"(rb+set), "r"(0), "i"(2), "i"(0), "r"(r)); | ||
| 94 | } | ||
| 95 | |||
| 96 | asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : : | ||
| 97 | "r"(rb), "r"(0), "i"(2), "i"(1), "r"(r)); | ||
| 98 | if (early_radix_enabled()) { | ||
| 99 | for (i = 1; i < num_sets; i++) { | ||
| 100 | unsigned long set = i * (1<<TLBIEL_INVAL_SET_SHIFT); | ||
| 101 | |||
| 102 | asm volatile(PPC_TLBIEL(%0, %1, %2, %3, %4) : : | ||
| 103 | "r"(rb+set), "r"(0), "i"(2), "i"(1), "r"(r)); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | asm volatile("ptesync" : : : "memory"); | ||
| 108 | } | ||
| 109 | |||
| 56 | /* | 110 | /* |
| 57 | * Generic routines to flush TLB on POWER processors. These routines | 111 | * Generic routines to flush TLB on POWER processors. These routines |
| 58 | * are used as flush_tlb hook in the cpu_spec. | 112 | * are used as flush_tlb hook in the cpu_spec. |
| @@ -79,7 +133,7 @@ void __flush_tlb_power9(unsigned int action) | |||
| 79 | else | 133 | else |
| 80 | num_sets = POWER9_TLB_SETS_HASH; | 134 | num_sets = POWER9_TLB_SETS_HASH; |
| 81 | 135 | ||
| 82 | flush_tlb_206(num_sets, action); | 136 | flush_tlb_300(num_sets, action); |
| 83 | } | 137 | } |
| 84 | 138 | ||
| 85 | 139 | ||
