aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/book3s_hv.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv.c')
-rw-r--r--arch/powerpc/kvm/book3s_hv.c150
1 files changed, 150 insertions, 0 deletions
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: