aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/reg.h3
-rw-r--r--arch/powerpc/include/asm/xics.h1
-rw-r--r--arch/powerpc/mm/fault.c21
-rw-r--r--arch/powerpc/mm/tlb-radix.c6
-rw-r--r--arch/powerpc/platforms/powernv/smp.c12
-rw-r--r--arch/powerpc/sysdev/xics/icp-opal.c35
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
46extern int icp_opal_init(void); 46extern int icp_opal_init(void);
47extern void icp_opal_flush_interrupt(void);
47#else 48#else
48static inline int icp_opal_init(void) { return -ENODEV; } 49static 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
58static inline void _tlbie_pid(unsigned long pid, unsigned long ric) 56static 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
92static inline void _tlbie_va(unsigned long va, unsigned long pid, 88static 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
126static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id) 127static 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 */
141void 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
137static const struct icp_ops icp_opal_ops = { 168static const struct icp_ops icp_opal_ops = {