diff options
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/xics.h | 1 | ||||
-rw-r--r-- | arch/powerpc/mm/fault.c | 21 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb-radix.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 12 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xics/icp-opal.c | 35 |
6 files changed, 52 insertions, 26 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 0d4531aa2052..dff79798903d 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -649,9 +649,10 @@ | |||
649 | #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ | 649 | #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ |
650 | #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ | 650 | #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ |
651 | #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ | 651 | #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ |
652 | #define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ | 652 | #define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 and 9 */ |
653 | #define SRR1_WAKESYSERR 0x00300000 /* System error */ | 653 | #define SRR1_WAKESYSERR 0x00300000 /* System error */ |
654 | #define SRR1_WAKEEE 0x00200000 /* External interrupt */ | 654 | #define SRR1_WAKEEE 0x00200000 /* External interrupt */ |
655 | #define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virtualization Interrupt (P9) */ | ||
655 | #define SRR1_WAKEMT 0x00280000 /* mtctrl */ | 656 | #define SRR1_WAKEMT 0x00280000 /* mtctrl */ |
656 | #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ | 657 | #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ |
657 | #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ | 658 | #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ |
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index f0b238516e9b..e0b9e576905a 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h | |||
@@ -44,6 +44,7 @@ static inline int icp_hv_init(void) { return -ENODEV; } | |||
44 | 44 | ||
45 | #ifdef CONFIG_PPC_POWERNV | 45 | #ifdef CONFIG_PPC_POWERNV |
46 | extern int icp_opal_init(void); | 46 | extern int icp_opal_init(void); |
47 | extern void icp_opal_flush_interrupt(void); | ||
47 | #else | 48 | #else |
48 | static inline int icp_opal_init(void) { return -ENODEV; } | 49 | static inline int icp_opal_init(void) { return -ENODEV; } |
49 | #endif | 50 | #endif |
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 6fd30ac7d14a..62a50d6d1053 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -253,8 +253,11 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, | |||
253 | if (unlikely(debugger_fault_handler(regs))) | 253 | if (unlikely(debugger_fault_handler(regs))) |
254 | goto bail; | 254 | goto bail; |
255 | 255 | ||
256 | /* On a kernel SLB miss we can only check for a valid exception entry */ | 256 | /* |
257 | if (!user_mode(regs) && (address >= TASK_SIZE)) { | 257 | * The kernel should never take an execute fault nor should it |
258 | * take a page fault to a kernel address. | ||
259 | */ | ||
260 | if (!user_mode(regs) && (is_exec || (address >= TASK_SIZE))) { | ||
258 | rc = SIGSEGV; | 261 | rc = SIGSEGV; |
259 | goto bail; | 262 | goto bail; |
260 | } | 263 | } |
@@ -391,20 +394,6 @@ good_area: | |||
391 | 394 | ||
392 | if (is_exec) { | 395 | if (is_exec) { |
393 | /* | 396 | /* |
394 | * An execution fault + no execute ? | ||
395 | * | ||
396 | * On CPUs that don't have CPU_FTR_COHERENT_ICACHE we | ||
397 | * deliberately create NX mappings, and use the fault to do the | ||
398 | * cache flush. This is usually handled in hash_page_do_lazy_icache() | ||
399 | * but we could end up here if that races with a concurrent PTE | ||
400 | * update. In that case we need to fall through here to the VMA | ||
401 | * check below. | ||
402 | */ | ||
403 | if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && | ||
404 | (regs->msr & SRR1_ISI_N_OR_G)) | ||
405 | goto bad_area; | ||
406 | |||
407 | /* | ||
408 | * Allow execution from readable areas if the MMU does not | 397 | * Allow execution from readable areas if the MMU does not |
409 | * provide separate controls over reading and executing. | 398 | * provide separate controls over reading and executing. |
410 | * | 399 | * |
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index 61b79119065f..952713d6cf04 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c | |||
@@ -50,9 +50,7 @@ static inline void _tlbiel_pid(unsigned long pid, unsigned long ric) | |||
50 | for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) { | 50 | for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) { |
51 | __tlbiel_pid(pid, set, ric); | 51 | __tlbiel_pid(pid, set, ric); |
52 | } | 52 | } |
53 | if (cpu_has_feature(CPU_FTR_POWER9_DD1)) | 53 | asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory"); |
54 | asm volatile(PPC_INVALIDATE_ERAT : : :"memory"); | ||
55 | return; | ||
56 | } | 54 | } |
57 | 55 | ||
58 | static inline void _tlbie_pid(unsigned long pid, unsigned long ric) | 56 | static inline void _tlbie_pid(unsigned long pid, unsigned long ric) |
@@ -85,8 +83,6 @@ static inline void _tlbiel_va(unsigned long va, unsigned long pid, | |||
85 | asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1) | 83 | asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1) |
86 | : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); | 84 | : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); |
87 | asm volatile("ptesync": : :"memory"); | 85 | asm volatile("ptesync": : :"memory"); |
88 | if (cpu_has_feature(CPU_FTR_POWER9_DD1)) | ||
89 | asm volatile(PPC_INVALIDATE_ERAT : : :"memory"); | ||
90 | } | 86 | } |
91 | 87 | ||
92 | static inline void _tlbie_va(unsigned long va, unsigned long pid, | 88 | static inline void _tlbie_va(unsigned long va, unsigned long pid, |
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index c789258ae1e1..eec0e8d0454d 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c | |||
@@ -155,8 +155,10 @@ static void pnv_smp_cpu_kill_self(void) | |||
155 | wmask = SRR1_WAKEMASK_P8; | 155 | wmask = SRR1_WAKEMASK_P8; |
156 | 156 | ||
157 | idle_states = pnv_get_supported_cpuidle_states(); | 157 | idle_states = pnv_get_supported_cpuidle_states(); |
158 | |||
158 | /* We don't want to take decrementer interrupts while we are offline, | 159 | /* We don't want to take decrementer interrupts while we are offline, |
159 | * so clear LPCR:PECE1. We keep PECE2 enabled. | 160 | * so clear LPCR:PECE1. We keep PECE2 (and LPCR_PECE_HVEE on P9) |
161 | * enabled as to let IPIs in. | ||
160 | */ | 162 | */ |
161 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); | 163 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); |
162 | 164 | ||
@@ -206,8 +208,12 @@ static void pnv_smp_cpu_kill_self(void) | |||
206 | * contains 0. | 208 | * contains 0. |
207 | */ | 209 | */ |
208 | if (((srr1 & wmask) == SRR1_WAKEEE) || | 210 | if (((srr1 & wmask) == SRR1_WAKEEE) || |
211 | ((srr1 & wmask) == SRR1_WAKEHVI) || | ||
209 | (local_paca->irq_happened & PACA_IRQ_EE)) { | 212 | (local_paca->irq_happened & PACA_IRQ_EE)) { |
210 | icp_native_flush_interrupt(); | 213 | if (cpu_has_feature(CPU_FTR_ARCH_300)) |
214 | icp_opal_flush_interrupt(); | ||
215 | else | ||
216 | icp_native_flush_interrupt(); | ||
211 | } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { | 217 | } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { |
212 | unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); | 218 | unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); |
213 | asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); | 219 | asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); |
@@ -221,6 +227,8 @@ static void pnv_smp_cpu_kill_self(void) | |||
221 | if (srr1 && !generic_check_cpu_restart(cpu)) | 227 | if (srr1 && !generic_check_cpu_restart(cpu)) |
222 | DBG("CPU%d Unexpected exit while offline !\n", cpu); | 228 | DBG("CPU%d Unexpected exit while offline !\n", cpu); |
223 | } | 229 | } |
230 | |||
231 | /* Re-enable decrementer interrupts */ | ||
224 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); | 232 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); |
225 | DBG("CPU%d coming online...\n", cpu); | 233 | DBG("CPU%d coming online...\n", cpu); |
226 | } | 234 | } |
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c index 60c57657c772..f9670eabfcfa 100644 --- a/arch/powerpc/sysdev/xics/icp-opal.c +++ b/arch/powerpc/sysdev/xics/icp-opal.c | |||
@@ -120,18 +120,49 @@ static void icp_opal_cause_ipi(int cpu, unsigned long data) | |||
120 | { | 120 | { |
121 | int hw_cpu = get_hard_smp_processor_id(cpu); | 121 | int hw_cpu = get_hard_smp_processor_id(cpu); |
122 | 122 | ||
123 | kvmppc_set_host_ipi(cpu, 1); | ||
123 | opal_int_set_mfrr(hw_cpu, IPI_PRIORITY); | 124 | opal_int_set_mfrr(hw_cpu, IPI_PRIORITY); |
124 | } | 125 | } |
125 | 126 | ||
126 | static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id) | 127 | static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id) |
127 | { | 128 | { |
128 | int hw_cpu = hard_smp_processor_id(); | 129 | int cpu = smp_processor_id(); |
129 | 130 | ||
130 | opal_int_set_mfrr(hw_cpu, 0xff); | 131 | kvmppc_set_host_ipi(cpu, 0); |
132 | opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff); | ||
131 | 133 | ||
132 | return smp_ipi_demux(); | 134 | return smp_ipi_demux(); |
133 | } | 135 | } |
134 | 136 | ||
137 | /* | ||
138 | * Called when an interrupt is received on an off-line CPU to | ||
139 | * clear the interrupt, so that the CPU can go back to nap mode. | ||
140 | */ | ||
141 | void icp_opal_flush_interrupt(void) | ||
142 | { | ||
143 | unsigned int xirr; | ||
144 | unsigned int vec; | ||
145 | |||
146 | do { | ||
147 | xirr = icp_opal_get_xirr(); | ||
148 | vec = xirr & 0x00ffffff; | ||
149 | if (vec == XICS_IRQ_SPURIOUS) | ||
150 | break; | ||
151 | if (vec == XICS_IPI) { | ||
152 | /* Clear pending IPI */ | ||
153 | int cpu = smp_processor_id(); | ||
154 | kvmppc_set_host_ipi(cpu, 0); | ||
155 | opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff); | ||
156 | } else { | ||
157 | pr_err("XICS: hw interrupt 0x%x to offline cpu, " | ||
158 | "disabling\n", vec); | ||
159 | xics_mask_unknown_vec(vec); | ||
160 | } | ||
161 | |||
162 | /* EOI the interrupt */ | ||
163 | } while (opal_int_eoi(xirr) > 0); | ||
164 | } | ||
165 | |||
135 | #endif /* CONFIG_SMP */ | 166 | #endif /* CONFIG_SMP */ |
136 | 167 | ||
137 | static const struct icp_ops icp_opal_ops = { | 168 | static const struct icp_ops icp_opal_ops = { |