aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2013-08-09 03:29:29 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-15 01:59:05 -0400
commit734ce4ea808b69a9896677fd1ebdf272a29665d9 (patch)
tree7296c4a9ca2666e40a24bafe8cee099fb4ce6d99 /arch/powerpc/kernel
parentf60232beaf08ab9567fb40b55379acba0c649aed (diff)
powerpc: Fix context switch DSCR on POWER8
commit 2517617e0de65f8f7cfe75cae745d06b1fa98586 upstream. POWER8 allows the DSCR to be accessed directly from userspace via a new SPR number 0x3 (Rather than 0x11. DSCR SPR number 0x11 is still used on POWER8 but like POWER7, is only accessible in HV and OS modes). Currently, we allow this by setting H/FSCR DSCR bit on boot. Unfortunately this doesn't work, as the kernel needs to see the DSCR change so that it knows to no longer restore the system wide version of DSCR on context switch (ie. to set thread.dscr_inherit). This clears the H/FSCR DSCR bit initially. If a process then accesses the DSCR (via SPR 0x3), it'll trap into the kernel where we set thread.dscr_inherit in facility_unavailable_exception(). We also change _switch() so that we set or clear the H/FSCR DSCR bit based on the thread.dscr_inherit. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/entry_64.S27
-rw-r--r--arch/powerpc/kernel/traps.c58
2 files changed, 60 insertions, 25 deletions
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 8741c854e03d..48816ed66cf5 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -584,9 +584,34 @@ BEGIN_FTR_SECTION
584 ld r7,DSCR_DEFAULT@toc(2) 584 ld r7,DSCR_DEFAULT@toc(2)
585 ld r0,THREAD_DSCR(r4) 585 ld r0,THREAD_DSCR(r4)
586 cmpwi r6,0 586 cmpwi r6,0
587 li r8, FSCR_DSCR
587 bne 1f 588 bne 1f
588 ld r0,0(r7) 589 ld r0,0(r7)
5891: cmpd r0,r25 590 b 3f
5911:
592 BEGIN_FTR_SECTION_NESTED(70)
593 mfspr r6, SPRN_FSCR
594 or r6, r6, r8
595 mtspr SPRN_FSCR, r6
596 BEGIN_FTR_SECTION_NESTED(69)
597 mfspr r6, SPRN_HFSCR
598 or r6, r6, r8
599 mtspr SPRN_HFSCR, r6
600 END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69)
601 b 4f
602 END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70)
6033:
604 BEGIN_FTR_SECTION_NESTED(70)
605 mfspr r6, SPRN_FSCR
606 andc r6, r6, r8
607 mtspr SPRN_FSCR, r6
608 BEGIN_FTR_SECTION_NESTED(69)
609 mfspr r6, SPRN_HFSCR
610 andc r6, r6, r8
611 mtspr SPRN_HFSCR, r6
612 END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69)
613 END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70)
6144: cmpd r0,r25
590 beq 2f 615 beq 2f
591 mtspr SPRN_DSCR,r0 616 mtspr SPRN_DSCR,r0
5922: 6172:
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index e4f205a209d2..88929b1f4f77 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -44,9 +44,7 @@
44#include <asm/machdep.h> 44#include <asm/machdep.h>
45#include <asm/rtas.h> 45#include <asm/rtas.h>
46#include <asm/pmc.h> 46#include <asm/pmc.h>
47#ifdef CONFIG_PPC32
48#include <asm/reg.h> 47#include <asm/reg.h>
49#endif
50#ifdef CONFIG_PMAC_BACKLIGHT 48#ifdef CONFIG_PMAC_BACKLIGHT
51#include <asm/backlight.h> 49#include <asm/backlight.h>
52#endif 50#endif
@@ -1282,43 +1280,54 @@ void vsx_unavailable_exception(struct pt_regs *regs)
1282 die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT); 1280 die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT);
1283} 1281}
1284 1282
1283#ifdef CONFIG_PPC64
1285void facility_unavailable_exception(struct pt_regs *regs) 1284void facility_unavailable_exception(struct pt_regs *regs)
1286{ 1285{
1287 static char *facility_strings[] = { 1286 static char *facility_strings[] = {
1288 "FPU", 1287 [FSCR_FP_LG] = "FPU",
1289 "VMX/VSX", 1288 [FSCR_VECVSX_LG] = "VMX/VSX",
1290 "DSCR", 1289 [FSCR_DSCR_LG] = "DSCR",
1291 "PMU SPRs", 1290 [FSCR_PM_LG] = "PMU SPRs",
1292 "BHRB", 1291 [FSCR_BHRB_LG] = "BHRB",
1293 "TM", 1292 [FSCR_TM_LG] = "TM",
1294 "AT", 1293 [FSCR_EBB_LG] = "EBB",
1295 "EBB", 1294 [FSCR_TAR_LG] = "TAR",
1296 "TAR",
1297 }; 1295 };
1298 char *facility, *prefix; 1296 char *facility = "unknown";
1299 u64 value; 1297 u64 value;
1298 u8 status;
1299 bool hv;
1300 1300
1301 if (regs->trap == 0xf60) { 1301 hv = (regs->trap == 0xf80);
1302 value = mfspr(SPRN_FSCR); 1302 if (hv)
1303 prefix = "";
1304 } else {
1305 value = mfspr(SPRN_HFSCR); 1303 value = mfspr(SPRN_HFSCR);
1306 prefix = "Hypervisor "; 1304 else
1305 value = mfspr(SPRN_FSCR);
1306
1307 status = value >> 56;
1308 if (status == FSCR_DSCR_LG) {
1309 /* User is acessing the DSCR. Set the inherit bit and allow
1310 * the user to set it directly in future by setting via the
1311 * H/FSCR DSCR bit.
1312 */
1313 current->thread.dscr_inherit = 1;
1314 if (hv)
1315 mtspr(SPRN_HFSCR, value | HFSCR_DSCR);
1316 else
1317 mtspr(SPRN_FSCR, value | FSCR_DSCR);
1318 return;
1307 } 1319 }
1308 1320
1309 value = value >> 56; 1321 if ((status < ARRAY_SIZE(facility_strings)) &&
1322 facility_strings[status])
1323 facility = facility_strings[status];
1310 1324
1311 /* We restore the interrupt state now */ 1325 /* We restore the interrupt state now */
1312 if (!arch_irq_disabled_regs(regs)) 1326 if (!arch_irq_disabled_regs(regs))
1313 local_irq_enable(); 1327 local_irq_enable();
1314 1328
1315 if (value < ARRAY_SIZE(facility_strings))
1316 facility = facility_strings[value];
1317 else
1318 facility = "unknown";
1319
1320 pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n", 1329 pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
1321 prefix, facility, regs->nip, regs->msr); 1330 hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
1322 1331
1323 if (user_mode(regs)) { 1332 if (user_mode(regs)) {
1324 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); 1333 _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
@@ -1327,6 +1336,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
1327 1336
1328 die("Unexpected facility unavailable exception", regs, SIGABRT); 1337 die("Unexpected facility unavailable exception", regs, SIGABRT);
1329} 1338}
1339#endif
1330 1340
1331#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 1341#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1332 1342