aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-05-26 05:48:40 -0400
committerAlexander Graf <agraf@suse.de>2014-05-30 08:26:29 -0400
commit9bc01a9bc77edac2ea6db62c5111a7f4335d4021 (patch)
tree302ce7b1b9e01ef8489d65083300c96a151c390d /arch/powerpc
parent6c576e74fd91b93ca1eedcd9eb5200171d2ba32b (diff)
KVM: PPC: Book3S HV: Work around POWER8 performance monitor bugs
This adds workarounds for two hardware bugs in the POWER8 performance monitor unit (PMU), both related to interrupt generation. The effect of these bugs is that PMU interrupts can get lost, leading to tools such as perf reporting fewer counts and samples than they should. The first bug relates to the PMAO (perf. mon. alert occurred) bit in MMCR0; setting it should cause an interrupt, but doesn't. The other bug relates to the PMAE (perf. mon. alert enable) bit in MMCR0. Setting PMAE when a counter is negative and counter negative conditions are enabled to cause alerts should cause an alert, but doesn't. The workaround for the first bug is to create conditions where a counter will overflow, whenever we are about to restore a MMCR0 value that has PMAO set (and PMAO_SYNC clear). The workaround for the second bug is to freeze all counters using MMCR2 before reading MMCR0. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/reg.h12
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S59
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 */
89BEGIN_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
94END_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
735BEGIN_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
740END_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)
132425: 133625:
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 */
1339BEGIN_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
1362END_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)
1386BEGIN_FTR_SECTION
1387 std r10, VCPU_MMCR + 24(r9)
1388END_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)
1371END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) 1410END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
1372BEGIN_FTR_SECTION 1411BEGIN_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
23121: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG 23491: 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 */
2358kvmppc_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