diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 12 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 59 |
2 files changed, 64 insertions, 7 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index e5d2e0bc7e03..4852bcf270f3 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -670,18 +670,20 @@ | |||
670 | #define MMCR0_PROBLEM_DISABLE MMCR0_FCP | 670 | #define MMCR0_PROBLEM_DISABLE MMCR0_FCP |
671 | #define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */ | 671 | #define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */ |
672 | #define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */ | 672 | #define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */ |
673 | #define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */ | 673 | #define MMCR0_PMXE ASM_CONST(0x04000000) /* perf mon exception enable */ |
674 | #define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */ | 674 | #define MMCR0_FCECE ASM_CONST(0x02000000) /* freeze ctrs on enabled cond or event */ |
675 | #define MMCR0_TBEE 0x00400000UL /* time base exception enable */ | 675 | #define MMCR0_TBEE 0x00400000UL /* time base exception enable */ |
676 | #define MMCR0_BHRBA 0x00200000UL /* BHRB Access allowed in userspace */ | 676 | #define MMCR0_BHRBA 0x00200000UL /* BHRB Access allowed in userspace */ |
677 | #define MMCR0_EBE 0x00100000UL /* Event based branch enable */ | 677 | #define MMCR0_EBE 0x00100000UL /* Event based branch enable */ |
678 | #define MMCR0_PMCC 0x000c0000UL /* PMC control */ | 678 | #define MMCR0_PMCC 0x000c0000UL /* PMC control */ |
679 | #define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */ | 679 | #define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */ |
680 | #define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/ | 680 | #define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/ |
681 | #define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/ | 681 | #define MMCR0_PMCjCE ASM_CONST(0x00004000) /* PMCj count enable*/ |
682 | #define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */ | 682 | #define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */ |
683 | #define MMCR0_PMAO_SYNC 0x00000800UL /* PMU interrupt is synchronous */ | 683 | #define MMCR0_PMAO_SYNC ASM_CONST(0x00000800) /* PMU intr is synchronous */ |
684 | #define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */ | 684 | #define MMCR0_C56RUN ASM_CONST(0x00000100) /* PMC5/6 count when RUN=0 */ |
685 | /* performance monitor alert has occurred, set to 0 after handling exception */ | ||
686 | #define MMCR0_PMAO ASM_CONST(0x00000080) | ||
685 | #define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */ | 687 | #define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */ |
686 | #define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */ | 688 | #define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */ |
687 | #define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */ | 689 | #define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */ |
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index ffbb871c2bd8..60fe8ba318cf 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -86,6 +86,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) | |||
86 | lbz r4, LPPACA_PMCINUSE(r3) | 86 | lbz r4, LPPACA_PMCINUSE(r3) |
87 | cmpwi r4, 0 | 87 | cmpwi r4, 0 |
88 | beq 23f /* skip if not */ | 88 | beq 23f /* skip if not */ |
89 | BEGIN_FTR_SECTION | ||
90 | ld r3, HSTATE_MMCR(r13) | ||
91 | andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO | ||
92 | cmpwi r4, MMCR0_PMAO | ||
93 | beql kvmppc_fix_pmao | ||
94 | END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) | ||
89 | lwz r3, HSTATE_PMC(r13) | 95 | lwz r3, HSTATE_PMC(r13) |
90 | lwz r4, HSTATE_PMC + 4(r13) | 96 | lwz r4, HSTATE_PMC + 4(r13) |
91 | lwz r5, HSTATE_PMC + 8(r13) | 97 | lwz r5, HSTATE_PMC + 8(r13) |
@@ -726,6 +732,12 @@ skip_tm: | |||
726 | sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ | 732 | sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ |
727 | mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ | 733 | mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ |
728 | isync | 734 | isync |
735 | BEGIN_FTR_SECTION | ||
736 | ld r3, VCPU_MMCR(r4) | ||
737 | andi. r5, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO | ||
738 | cmpwi r5, MMCR0_PMAO | ||
739 | beql kvmppc_fix_pmao | ||
740 | END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) | ||
729 | lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ | 741 | lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ |
730 | lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ | 742 | lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ |
731 | lwz r6, VCPU_PMC + 8(r4) | 743 | lwz r6, VCPU_PMC + 8(r4) |
@@ -1324,6 +1336,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) | |||
1324 | 25: | 1336 | 25: |
1325 | /* Save PMU registers if requested */ | 1337 | /* Save PMU registers if requested */ |
1326 | /* r8 and cr0.eq are live here */ | 1338 | /* r8 and cr0.eq are live here */ |
1339 | BEGIN_FTR_SECTION | ||
1340 | /* | ||
1341 | * POWER8 seems to have a hardware bug where setting | ||
1342 | * MMCR0[PMAE] along with MMCR0[PMC1CE] and/or MMCR0[PMCjCE] | ||
1343 | * when some counters are already negative doesn't seem | ||
1344 | * to cause a performance monitor alert (and hence interrupt). | ||
1345 | * The effect of this is that when saving the PMU state, | ||
1346 | * if there is no PMU alert pending when we read MMCR0 | ||
1347 | * before freezing the counters, but one becomes pending | ||
1348 | * before we read the counters, we lose it. | ||
1349 | * To work around this, we need a way to freeze the counters | ||
1350 | * before reading MMCR0. Normally, freezing the counters | ||
1351 | * is done by writing MMCR0 (to set MMCR0[FC]) which | ||
1352 | * unavoidably writes MMCR0[PMA0] as well. On POWER8, | ||
1353 | * we can also freeze the counters using MMCR2, by writing | ||
1354 | * 1s to all the counter freeze condition bits (there are | ||
1355 | * 9 bits each for 6 counters). | ||
1356 | */ | ||
1357 | li r3, -1 /* set all freeze bits */ | ||
1358 | clrrdi r3, r3, 10 | ||
1359 | mfspr r10, SPRN_MMCR2 | ||
1360 | mtspr SPRN_MMCR2, r3 | ||
1361 | isync | ||
1362 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) | ||
1327 | li r3, 1 | 1363 | li r3, 1 |
1328 | sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ | 1364 | sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ |
1329 | mfspr r4, SPRN_MMCR0 /* save MMCR0 */ | 1365 | mfspr r4, SPRN_MMCR0 /* save MMCR0 */ |
@@ -1347,6 +1383,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) | |||
1347 | std r4, VCPU_MMCR(r9) | 1383 | std r4, VCPU_MMCR(r9) |
1348 | std r5, VCPU_MMCR + 8(r9) | 1384 | std r5, VCPU_MMCR + 8(r9) |
1349 | std r6, VCPU_MMCR + 16(r9) | 1385 | std r6, VCPU_MMCR + 16(r9) |
1386 | BEGIN_FTR_SECTION | ||
1387 | std r10, VCPU_MMCR + 24(r9) | ||
1388 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) | ||
1350 | std r7, VCPU_SIAR(r9) | 1389 | std r7, VCPU_SIAR(r9) |
1351 | std r8, VCPU_SDAR(r9) | 1390 | std r8, VCPU_SDAR(r9) |
1352 | mfspr r3, SPRN_PMC1 | 1391 | mfspr r3, SPRN_PMC1 |
@@ -1370,12 +1409,10 @@ BEGIN_FTR_SECTION | |||
1370 | stw r11, VCPU_PMC + 28(r9) | 1409 | stw r11, VCPU_PMC + 28(r9) |
1371 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) | 1410 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) |
1372 | BEGIN_FTR_SECTION | 1411 | BEGIN_FTR_SECTION |
1373 | mfspr r4, SPRN_MMCR2 | ||
1374 | mfspr r5, SPRN_SIER | 1412 | mfspr r5, SPRN_SIER |
1375 | mfspr r6, SPRN_SPMC1 | 1413 | mfspr r6, SPRN_SPMC1 |
1376 | mfspr r7, SPRN_SPMC2 | 1414 | mfspr r7, SPRN_SPMC2 |
1377 | mfspr r8, SPRN_MMCRS | 1415 | mfspr r8, SPRN_MMCRS |
1378 | std r4, VCPU_MMCR + 24(r9) | ||
1379 | std r5, VCPU_SIER(r9) | 1416 | std r5, VCPU_SIER(r9) |
1380 | stw r6, VCPU_PMC + 24(r9) | 1417 | stw r6, VCPU_PMC + 24(r9) |
1381 | stw r7, VCPU_PMC + 28(r9) | 1418 | stw r7, VCPU_PMC + 28(r9) |
@@ -2311,3 +2348,21 @@ kvmppc_msr_interrupt: | |||
2311 | li r0, 1 | 2348 | li r0, 1 |
2312 | 1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG | 2349 | 1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG |
2313 | blr | 2350 | blr |
2351 | |||
2352 | /* | ||
2353 | * This works around a hardware bug on POWER8E processors, where | ||
2354 | * writing a 1 to the MMCR0[PMAO] bit doesn't generate a | ||
2355 | * performance monitor interrupt. Instead, when we need to have | ||
2356 | * an interrupt pending, we have to arrange for a counter to overflow. | ||
2357 | */ | ||
2358 | kvmppc_fix_pmao: | ||
2359 | li r3, 0 | ||
2360 | mtspr SPRN_MMCR2, r3 | ||
2361 | lis r3, (MMCR0_PMXE | MMCR0_FCECE)@h | ||
2362 | ori r3, r3, MMCR0_PMCjCE | MMCR0_C56RUN | ||
2363 | mtspr SPRN_MMCR0, r3 | ||
2364 | lis r3, 0x7fff | ||
2365 | ori r3, r3, 0xffff | ||
2366 | mtspr SPRN_PMC6, r3 | ||
2367 | isync | ||
2368 | blr | ||