diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 150 |
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 | ||
1427 | static 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 | |||
1440 | struct debugfs_timings_state { | ||
1441 | struct kvm_vcpu *vcpu; | ||
1442 | unsigned int buflen; | ||
1443 | char buf[N_TIMINGS * 100]; | ||
1444 | }; | ||
1445 | |||
1446 | static 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 | |||
1462 | static 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 | |||
1471 | static 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 | |||
1536 | static 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 | |||
1542 | static 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 */ | ||
1552 | static 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 */ | ||
1569 | static void debugfs_vcpu_init(struct kvm_vcpu *vcpu, unsigned int id) | ||
1570 | { | ||
1571 | } | ||
1572 | #endif /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */ | ||
1573 | |||
1426 | static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, | 1574 | static 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 | ||
1497 | free_vcpu: | 1647 | free_vcpu: |