summaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2015-03-27 23:21:02 -0400
committerAlexander Graf <agraf@suse.de>2015-04-21 09:21:31 -0400
commitb6c295df3131c6fa25f8f29625ee0609506150ad (patch)
treebb9a89ae934bcefcb16f62de9f432493852b480a /arch/powerpc
parente23a808b1681d398a983ebc51179efc51c4a1eaf (diff)
KVM: PPC: Book3S HV: Accumulate timing information for real-mode code
This reads the timebase at various points in the real-mode guest entry/exit code and uses that to accumulate total, minimum and maximum time spent in those parts of the code. Currently these times are accumulated per vcpu in 5 parts of the code: * rm_entry - time taken from the start of kvmppc_hv_entry() until just before entering the guest. * rm_intr - time from when we take a hypervisor interrupt in the guest until we either re-enter the guest or decide to exit to the host. This includes time spent handling hcalls in real mode. * rm_exit - time from when we decide to exit the guest until the return from kvmppc_hv_entry(). * guest - time spend in the guest * cede - time spent napping in real mode due to an H_CEDE hcall while other threads in the same vcore are active. These times are exposed in debugfs in a directory per vcpu that contains a file called "timings". This file contains one line for each of the 5 timings above, with the name followed by a colon and 4 numbers, which are the count (number of times the code has been executed), the total time, the minimum time, and the maximum time, all in nanoseconds. The overhead of the extra code amounts to about 30ns for an hcall that is handled in real mode (e.g. H_SET_DABR), which is about 25%. Since production environments may not wish to incur this overhead, the new code is conditional on a new config symbol, CONFIG_KVM_BOOK3S_HV_EXIT_TIMING. 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/kvm_host.h21
-rw-r--r--arch/powerpc/include/asm/time.h3
-rw-r--r--arch/powerpc/kernel/asm-offsets.c13
-rw-r--r--arch/powerpc/kernel/time.c6
-rw-r--r--arch/powerpc/kvm/Kconfig14
-rw-r--r--arch/powerpc/kvm/book3s_hv.c150
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S141
7 files changed, 346 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index f1d0bbc0f079..d2068bba9059 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -369,6 +369,14 @@ struct kvmppc_slb {
369 u8 base_page_size; /* MMU_PAGE_xxx */ 369 u8 base_page_size; /* MMU_PAGE_xxx */
370}; 370};
371 371
372/* Struct used to accumulate timing information in HV real mode code */
373struct kvmhv_tb_accumulator {
374 u64 seqcount; /* used to synchronize access, also count * 2 */
375 u64 tb_total; /* total time in timebase ticks */
376 u64 tb_min; /* min time */
377 u64 tb_max; /* max time */
378};
379
372# ifdef CONFIG_PPC_FSL_BOOK3E 380# ifdef CONFIG_PPC_FSL_BOOK3E
373#define KVMPPC_BOOKE_IAC_NUM 2 381#define KVMPPC_BOOKE_IAC_NUM 2
374#define KVMPPC_BOOKE_DAC_NUM 2 382#define KVMPPC_BOOKE_DAC_NUM 2
@@ -657,6 +665,19 @@ struct kvm_vcpu_arch {
657 665
658 u32 emul_inst; 666 u32 emul_inst;
659#endif 667#endif
668
669#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
670 struct kvmhv_tb_accumulator *cur_activity; /* What we're timing */
671 u64 cur_tb_start; /* when it started */
672 struct kvmhv_tb_accumulator rm_entry; /* real-mode entry code */
673 struct kvmhv_tb_accumulator rm_intr; /* real-mode intr handling */
674 struct kvmhv_tb_accumulator rm_exit; /* real-mode exit code */
675 struct kvmhv_tb_accumulator guest_time; /* guest execution */
676 struct kvmhv_tb_accumulator cede_time; /* time napping inside guest */
677
678 struct dentry *debugfs_dir;
679 struct dentry *debugfs_timings;
680#endif /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */
660}; 681};
661 682
662#define VCPU_FPR(vcpu, i) (vcpu)->arch.fp.fpr[i][TS_FPROFFSET] 683#define VCPU_FPR(vcpu, i) (vcpu)->arch.fp.fpr[i][TS_FPROFFSET]
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 03cbada59d3a..10fc784a2ad4 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -211,5 +211,8 @@ extern void secondary_cpu_time_init(void);
211 211
212DECLARE_PER_CPU(u64, decrementers_next_tb); 212DECLARE_PER_CPU(u64, decrementers_next_tb);
213 213
214/* Convert timebase ticks to nanoseconds */
215unsigned long long tb_to_ns(unsigned long long tb_ticks);
216
214#endif /* __KERNEL__ */ 217#endif /* __KERNEL__ */
215#endif /* __POWERPC_TIME_H */ 218#endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 4717859fdd04..3fea721f0da5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -459,6 +459,19 @@ int main(void)
459 DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2)); 459 DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2));
460 DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3)); 460 DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3));
461#endif 461#endif
462#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
463 DEFINE(VCPU_TB_RMENTRY, offsetof(struct kvm_vcpu, arch.rm_entry));
464 DEFINE(VCPU_TB_RMINTR, offsetof(struct kvm_vcpu, arch.rm_intr));
465 DEFINE(VCPU_TB_RMEXIT, offsetof(struct kvm_vcpu, arch.rm_exit));
466 DEFINE(VCPU_TB_GUEST, offsetof(struct kvm_vcpu, arch.guest_time));
467 DEFINE(VCPU_TB_CEDE, offsetof(struct kvm_vcpu, arch.cede_time));
468 DEFINE(VCPU_CUR_ACTIVITY, offsetof(struct kvm_vcpu, arch.cur_activity));
469 DEFINE(VCPU_ACTIVITY_START, offsetof(struct kvm_vcpu, arch.cur_tb_start));
470 DEFINE(TAS_SEQCOUNT, offsetof(struct kvmhv_tb_accumulator, seqcount));
471 DEFINE(TAS_TOTAL, offsetof(struct kvmhv_tb_accumulator, tb_total));
472 DEFINE(TAS_MIN, offsetof(struct kvmhv_tb_accumulator, tb_min));
473 DEFINE(TAS_MAX, offsetof(struct kvmhv_tb_accumulator, tb_max));
474#endif
462 DEFINE(VCPU_SHARED_SPRG3, offsetof(struct kvm_vcpu_arch_shared, sprg3)); 475 DEFINE(VCPU_SHARED_SPRG3, offsetof(struct kvm_vcpu_arch_shared, sprg3));
463 DEFINE(VCPU_SHARED_SPRG4, offsetof(struct kvm_vcpu_arch_shared, sprg4)); 476 DEFINE(VCPU_SHARED_SPRG4, offsetof(struct kvm_vcpu_arch_shared, sprg4));
464 DEFINE(VCPU_SHARED_SPRG5, offsetof(struct kvm_vcpu_arch_shared, sprg5)); 477 DEFINE(VCPU_SHARED_SPRG5, offsetof(struct kvm_vcpu_arch_shared, sprg5));
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 2d7b33fab953..56f44848b044 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -608,6 +608,12 @@ void arch_suspend_enable_irqs(void)
608} 608}
609#endif 609#endif
610 610
611unsigned long long tb_to_ns(unsigned long long ticks)
612{
613 return mulhdu(ticks, tb_to_ns_scale) << tb_to_ns_shift;
614}
615EXPORT_SYMBOL_GPL(tb_to_ns);
616
611/* 617/*
612 * Scheduler clock - returns current time in nanosec units. 618 * Scheduler clock - returns current time in nanosec units.
613 * 619 *
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 11850f310fb4..2963e4dd0b80 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -110,6 +110,20 @@ config KVM_BOOK3S_64_PR
110 processor, including emulating 32-bit processors on a 64-bit 110 processor, including emulating 32-bit processors on a 64-bit
111 host. 111 host.
112 112
113config KVM_BOOK3S_HV_EXIT_TIMING
114 bool "Detailed timing for hypervisor real-mode code"
115 depends on KVM_BOOK3S_HV_POSSIBLE && DEBUG_FS
116 ---help---
117 Calculate time taken for each vcpu in the real-mode guest entry,
118 exit, and interrupt handling code, plus time spent in the guest
119 and in nap mode due to idle (cede) while other threads are still
120 in the guest. The total, minimum and maximum times in nanoseconds
121 together with the number of executions are reported in debugfs in
122 kvm/vm#/vcpu#/timings. The overhead is of the order of 30 - 40
123 ns per exit on POWER8.
124
125 If unsure, say N.
126
113config KVM_BOOKE_HV 127config KVM_BOOKE_HV
114 bool 128 bool
115 129
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 08f8617f4046..64a02d4c737c 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1423,6 +1423,154 @@ static struct kvmppc_vcore *kvmppc_vcore_create(struct kvm *kvm, int core)
1423 return vcore; 1423 return vcore;
1424} 1424}
1425 1425
1426#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1427static struct debugfs_timings_element {
1428 const char *name;
1429 size_t offset;
1430} timings[] = {
1431 {"rm_entry", offsetof(struct kvm_vcpu, arch.rm_entry)},
1432 {"rm_intr", offsetof(struct kvm_vcpu, arch.rm_intr)},
1433 {"rm_exit", offsetof(struct kvm_vcpu, arch.rm_exit)},
1434 {"guest", offsetof(struct kvm_vcpu, arch.guest_time)},
1435 {"cede", offsetof(struct kvm_vcpu, arch.cede_time)},
1436};
1437
1438#define N_TIMINGS (sizeof(timings) / sizeof(timings[0]))
1439
1440struct debugfs_timings_state {
1441 struct kvm_vcpu *vcpu;
1442 unsigned int buflen;
1443 char buf[N_TIMINGS * 100];
1444};
1445
1446static int debugfs_timings_open(struct inode *inode, struct file *file)
1447{
1448 struct kvm_vcpu *vcpu = inode->i_private;
1449 struct debugfs_timings_state *p;
1450
1451 p = kzalloc(sizeof(*p), GFP_KERNEL);
1452 if (!p)
1453 return -ENOMEM;
1454
1455 kvm_get_kvm(vcpu->kvm);
1456 p->vcpu = vcpu;
1457 file->private_data = p;
1458
1459 return nonseekable_open(inode, file);
1460}
1461
1462static int debugfs_timings_release(struct inode *inode, struct file *file)
1463{
1464 struct debugfs_timings_state *p = file->private_data;
1465
1466 kvm_put_kvm(p->vcpu->kvm);
1467 kfree(p);
1468 return 0;
1469}
1470
1471static ssize_t debugfs_timings_read(struct file *file, char __user *buf,
1472 size_t len, loff_t *ppos)
1473{
1474 struct debugfs_timings_state *p = file->private_data;
1475 struct kvm_vcpu *vcpu = p->vcpu;
1476 char *s, *buf_end;
1477 struct kvmhv_tb_accumulator tb;
1478 u64 count;
1479 loff_t pos;
1480 ssize_t n;
1481 int i, loops;
1482 bool ok;
1483
1484 if (!p->buflen) {
1485 s = p->buf;
1486 buf_end = s + sizeof(p->buf);
1487 for (i = 0; i < N_TIMINGS; ++i) {
1488 struct kvmhv_tb_accumulator *acc;
1489
1490 acc = (struct kvmhv_tb_accumulator *)
1491 ((unsigned long)vcpu + timings[i].offset);
1492 ok = false;
1493 for (loops = 0; loops < 1000; ++loops) {
1494 count = acc->seqcount;
1495 if (!(count & 1)) {
1496 smp_rmb();
1497 tb = *acc;
1498 smp_rmb();
1499 if (count == acc->seqcount) {
1500 ok = true;
1501 break;
1502 }
1503 }
1504 udelay(1);
1505 }
1506 if (!ok)
1507 snprintf(s, buf_end - s, "%s: stuck\n",
1508 timings[i].name);
1509 else
1510 snprintf(s, buf_end - s,
1511 "%s: %llu %llu %llu %llu\n",
1512 timings[i].name, count / 2,
1513 tb_to_ns(tb.tb_total),
1514 tb_to_ns(tb.tb_min),
1515 tb_to_ns(tb.tb_max));
1516 s += strlen(s);
1517 }
1518 p->buflen = s - p->buf;
1519 }
1520
1521 pos = *ppos;
1522 if (pos >= p->buflen)
1523 return 0;
1524 if (len > p->buflen - pos)
1525 len = p->buflen - pos;
1526 n = copy_to_user(buf, p->buf + pos, len);
1527 if (n) {
1528 if (n == len)
1529 return -EFAULT;
1530 len -= n;
1531 }
1532 *ppos = pos + len;
1533 return len;
1534}
1535
1536static ssize_t debugfs_timings_write(struct file *file, const char __user *buf,
1537 size_t len, loff_t *ppos)
1538{
1539 return -EACCES;
1540}
1541
1542static const struct file_operations debugfs_timings_ops = {
1543 .owner = THIS_MODULE,
1544 .open = debugfs_timings_open,
1545 .release = debugfs_timings_release,
1546 .read = debugfs_timings_read,
1547 .write = debugfs_timings_write,
1548 .llseek = generic_file_llseek,
1549};
1550
1551/* Create a debugfs directory for the vcpu */
1552static void debugfs_vcpu_init(struct kvm_vcpu *vcpu, unsigned int id)
1553{
1554 char buf[16];
1555 struct kvm *kvm = vcpu->kvm;
1556
1557 snprintf(buf, sizeof(buf), "vcpu%u", id);
1558 if (IS_ERR_OR_NULL(kvm->arch.debugfs_dir))
1559 return;
1560 vcpu->arch.debugfs_dir = debugfs_create_dir(buf, kvm->arch.debugfs_dir);
1561 if (IS_ERR_OR_NULL(vcpu->arch.debugfs_dir))
1562 return;
1563 vcpu->arch.debugfs_timings =
1564 debugfs_create_file("timings", 0444, vcpu->arch.debugfs_dir,
1565 vcpu, &debugfs_timings_ops);
1566}
1567
1568#else /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */
1569static void debugfs_vcpu_init(struct kvm_vcpu *vcpu, unsigned int id)
1570{
1571}
1572#endif /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */
1573
1426static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, 1574static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
1427 unsigned int id) 1575 unsigned int id)
1428{ 1576{
@@ -1492,6 +1640,8 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
1492 vcpu->arch.cpu_type = KVM_CPU_3S_64; 1640 vcpu->arch.cpu_type = KVM_CPU_3S_64;
1493 kvmppc_sanity_check(vcpu); 1641 kvmppc_sanity_check(vcpu);
1494 1642
1643 debugfs_vcpu_init(vcpu, id);
1644
1495 return vcpu; 1645 return vcpu;
1496 1646
1497free_vcpu: 1647free_vcpu:
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 0814ca122fcd..b06fe53fd509 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -225,7 +225,13 @@ kvm_novcpu_wakeup:
225 /* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */ 225 /* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */
226 ld r4, HSTATE_KVM_VCPU(r13) 226 ld r4, HSTATE_KVM_VCPU(r13)
227 cmpdi r4, 0 227 cmpdi r4, 0
228 bne kvmppc_got_guest 228 beq kvmppc_primary_no_guest
229
230#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
231 addi r3, r4, VCPU_TB_RMENTRY
232 bl kvmhv_start_timing
233#endif
234 b kvmppc_got_guest
229 235
230kvm_novcpu_exit: 236kvm_novcpu_exit:
231 b hdec_soon 237 b hdec_soon
@@ -376,6 +382,14 @@ kvmppc_hv_entry:
376 li r6, KVM_GUEST_MODE_HOST_HV 382 li r6, KVM_GUEST_MODE_HOST_HV
377 stb r6, HSTATE_IN_GUEST(r13) 383 stb r6, HSTATE_IN_GUEST(r13)
378 384
385#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
386 /* Store initial timestamp */
387 cmpdi r4, 0
388 beq 1f
389 addi r3, r4, VCPU_TB_RMENTRY
390 bl kvmhv_start_timing
3911:
392#endif
379 /* Clear out SLB */ 393 /* Clear out SLB */
380 li r6,0 394 li r6,0
381 slbmte r6,r6 395 slbmte r6,r6
@@ -880,6 +894,12 @@ fast_guest_return:
880 li r9, KVM_GUEST_MODE_GUEST_HV 894 li r9, KVM_GUEST_MODE_GUEST_HV
881 stb r9, HSTATE_IN_GUEST(r13) 895 stb r9, HSTATE_IN_GUEST(r13)
882 896
897#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
898 /* Accumulate timing */
899 addi r3, r4, VCPU_TB_GUEST
900 bl kvmhv_accumulate_time
901#endif
902
883 /* Enter guest */ 903 /* Enter guest */
884 904
885BEGIN_FTR_SECTION 905BEGIN_FTR_SECTION
@@ -917,6 +937,23 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
917 hrfid 937 hrfid
918 b . 938 b .
919 939
940#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
941secondary_too_late:
942 cmpdi r4, 0
943 beq 11f
944 addi r3, r4, VCPU_TB_RMEXIT
945 bl kvmhv_accumulate_time
94611: b kvmhv_switch_to_host
947
948hdec_soon:
949 ld r4, HSTATE_KVM_VCPU(r13)
950 cmpdi r4, 0
951 beq 12f
952 addi r3, r4, VCPU_TB_RMEXIT
953 bl kvmhv_accumulate_time
95412: b kvmhv_do_exit
955#endif
956
920/****************************************************************************** 957/******************************************************************************
921 * * 958 * *
922 * Exit code * 959 * Exit code *
@@ -1002,6 +1039,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
1002 1039
1003 stw r12,VCPU_TRAP(r9) 1040 stw r12,VCPU_TRAP(r9)
1004 1041
1042#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1043 addi r3, r9, VCPU_TB_RMINTR
1044 mr r4, r9
1045 bl kvmhv_accumulate_time
1046 ld r5, VCPU_GPR(R5)(r9)
1047 ld r6, VCPU_GPR(R6)(r9)
1048 ld r7, VCPU_GPR(R7)(r9)
1049 ld r8, VCPU_GPR(R8)(r9)
1050#endif
1051
1005 /* Save HEIR (HV emulation assist reg) in emul_inst 1052 /* Save HEIR (HV emulation assist reg) in emul_inst
1006 if this is an HEI (HV emulation interrupt, e40) */ 1053 if this is an HEI (HV emulation interrupt, e40) */
1007 li r3,KVM_INST_FETCH_FAILED 1054 li r3,KVM_INST_FETCH_FAILED
@@ -1073,6 +1120,11 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
1073 cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK 1120 cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK
1074 beq machine_check_realmode 1121 beq machine_check_realmode
1075mc_cont: 1122mc_cont:
1123#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1124 addi r3, r9, VCPU_TB_RMEXIT
1125 mr r4, r9
1126 bl kvmhv_accumulate_time
1127#endif
1076 1128
1077 /* Save guest CTRL register, set runlatch to 1 */ 1129 /* Save guest CTRL register, set runlatch to 1 */
10786: mfspr r6,SPRN_CTRLF 11306: mfspr r6,SPRN_CTRLF
@@ -1417,7 +1469,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
1417 slbia 1469 slbia
1418 ptesync 1470 ptesync
1419 1471
1420hdec_soon: /* r12 = trap, r13 = paca */ 1472#ifndef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1473hdec_soon:
1474#endif
1475kvmhv_do_exit: /* r12 = trap, r13 = paca */
1421 /* 1476 /*
1422 * POWER7/POWER8 guest -> host partition switch code. 1477 * POWER7/POWER8 guest -> host partition switch code.
1423 * We don't have to lock against tlbies but we do 1478 * We don't have to lock against tlbies but we do
@@ -1476,7 +1531,10 @@ hdec_soon: /* r12 = trap, r13 = paca */
1476 addi r6,r6,PACA_SIZE 1531 addi r6,r6,PACA_SIZE
1477 bne 42b 1532 bne 42b
1478 1533
1534#ifndef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1479secondary_too_late: 1535secondary_too_late:
1536#endif
1537kvmhv_switch_to_host:
1480 /* Secondary threads wait for primary to do partition switch */ 1538 /* Secondary threads wait for primary to do partition switch */
148143: ld r5,HSTATE_KVM_VCORE(r13) 153943: ld r5,HSTATE_KVM_VCORE(r13)
1482 ld r4,VCORE_KVM(r5) /* pointer to struct kvm */ 1540 ld r4,VCORE_KVM(r5) /* pointer to struct kvm */
@@ -1562,6 +1620,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
15621: addi r8,r8,16 16201: addi r8,r8,16
1563 .endr 1621 .endr
1564 1622
1623#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
1624 /* Finish timing, if we have a vcpu */
1625 ld r4, HSTATE_KVM_VCPU(r13)
1626 cmpdi r4, 0
1627 li r3, 0
1628 beq 2f
1629 bl kvmhv_accumulate_time
16302:
1631#endif
1565 /* Unset guest mode */ 1632 /* Unset guest mode */
1566 li r0, KVM_GUEST_MODE_NONE 1633 li r0, KVM_GUEST_MODE_NONE
1567 stb r0, HSTATE_IN_GUEST(r13) 1634 stb r0, HSTATE_IN_GUEST(r13)
@@ -2069,6 +2136,12 @@ _GLOBAL(kvmppc_h_cede)
2069 /* save FP state */ 2136 /* save FP state */
2070 bl kvmppc_save_fp 2137 bl kvmppc_save_fp
2071 2138
2139#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
2140 ld r4, HSTATE_KVM_VCPU(r13)
2141 addi r3, r4, VCPU_TB_CEDE
2142 bl kvmhv_accumulate_time
2143#endif
2144
2072 /* 2145 /*
2073 * Take a nap until a decrementer or external or doobell interrupt 2146 * Take a nap until a decrementer or external or doobell interrupt
2074 * occurs, with PECE1, PECE0 and PECEDP set in LPCR. Also clear the 2147 * occurs, with PECE1, PECE0 and PECEDP set in LPCR. Also clear the
@@ -2109,6 +2182,11 @@ kvm_end_cede:
2109 /* Woken by external or decrementer interrupt */ 2182 /* Woken by external or decrementer interrupt */
2110 ld r1, HSTATE_HOST_R1(r13) 2183 ld r1, HSTATE_HOST_R1(r13)
2111 2184
2185#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
2186 addi r3, r4, VCPU_TB_RMINTR
2187 bl kvmhv_accumulate_time
2188#endif
2189
2112 /* load up FP state */ 2190 /* load up FP state */
2113 bl kvmppc_load_fp 2191 bl kvmppc_load_fp
2114 2192
@@ -2429,3 +2507,62 @@ kvmppc_fix_pmao:
2429 mtspr SPRN_PMC6, r3 2507 mtspr SPRN_PMC6, r3
2430 isync 2508 isync
2431 blr 2509 blr
2510
2511#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
2512/*
2513 * Start timing an activity
2514 * r3 = pointer to time accumulation struct, r4 = vcpu
2515 */
2516kvmhv_start_timing:
2517 ld r5, HSTATE_KVM_VCORE(r13)
2518 lbz r6, VCORE_IN_GUEST(r5)
2519 cmpwi r6, 0
2520 beq 5f /* if in guest, need to */
2521 ld r6, VCORE_TB_OFFSET(r5) /* subtract timebase offset */
25225: mftb r5
2523 subf r5, r6, r5
2524 std r3, VCPU_CUR_ACTIVITY(r4)
2525 std r5, VCPU_ACTIVITY_START(r4)
2526 blr
2527
2528/*
2529 * Accumulate time to one activity and start another.
2530 * r3 = pointer to new time accumulation struct, r4 = vcpu
2531 */
2532kvmhv_accumulate_time:
2533 ld r5, HSTATE_KVM_VCORE(r13)
2534 lbz r8, VCORE_IN_GUEST(r5)
2535 cmpwi r8, 0
2536 beq 4f /* if in guest, need to */
2537 ld r8, VCORE_TB_OFFSET(r5) /* subtract timebase offset */
25384: ld r5, VCPU_CUR_ACTIVITY(r4)
2539 ld r6, VCPU_ACTIVITY_START(r4)
2540 std r3, VCPU_CUR_ACTIVITY(r4)
2541 mftb r7
2542 subf r7, r8, r7
2543 std r7, VCPU_ACTIVITY_START(r4)
2544 cmpdi r5, 0
2545 beqlr
2546 subf r3, r6, r7
2547 ld r8, TAS_SEQCOUNT(r5)
2548 cmpdi r8, 0
2549 addi r8, r8, 1
2550 std r8, TAS_SEQCOUNT(r5)
2551 lwsync
2552 ld r7, TAS_TOTAL(r5)
2553 add r7, r7, r3
2554 std r7, TAS_TOTAL(r5)
2555 ld r6, TAS_MIN(r5)
2556 ld r7, TAS_MAX(r5)
2557 beq 3f
2558 cmpd r3, r6
2559 bge 1f
25603: std r3, TAS_MIN(r5)
25611: cmpd r3, r7
2562 ble 2f
2563 std r3, TAS_MAX(r5)
25642: lwsync
2565 addi r8, r8, 1
2566 std r8, TAS_SEQCOUNT(r5)
2567 blr
2568#endif