aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Weitz <WEITZKON@de.ibm.com>2012-04-25 09:30:38 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2012-04-30 20:38:31 -0400
commit41628d334361670d825fb03c04568f5ef9f084dc (patch)
tree88b2eadd0f7de12f1d8b226e4491532b8783ee94
parentb6ddf05ff68d81a7c1736717faf492b70e9bf4f9 (diff)
KVM: s390: Implement the directed yield (diag 9c) hypervisor call for KVM
This patch implements the directed yield hypercall found on other System z hypervisors. It delegates execution time to the virtual cpu specified in the instruction's parameter. Useful to avoid long spinlock waits in the guest. Christian Borntraeger: moved common code in virt/kvm/ Signed-off-by: Konstantin Weitz <WEITZKON@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h1
-rw-r--r--arch/s390/kvm/diag.c25
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--virt/kvm/kvm_main.c42
5 files changed, 54 insertions, 16 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 7343872890a2..dd17537b9a9d 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -148,6 +148,7 @@ struct kvm_vcpu_stat {
148 u32 instruction_sigp_restart; 148 u32 instruction_sigp_restart;
149 u32 diagnose_10; 149 u32 diagnose_10;
150 u32 diagnose_44; 150 u32 diagnose_44;
151 u32 diagnose_9c;
151}; 152};
152 153
153struct kvm_s390_io_info { 154struct kvm_s390_io_info {
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index a353f0ea45c2..2d2ae327b747 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -53,6 +53,29 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
53 return 0; 53 return 0;
54} 54}
55 55
56static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
57{
58 struct kvm *kvm = vcpu->kvm;
59 struct kvm_vcpu *tcpu;
60 int tid;
61 int i;
62
63 tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
64 vcpu->stat.diagnose_9c++;
65 VCPU_EVENT(vcpu, 5, "diag time slice end directed to %d", tid);
66
67 if (tid == vcpu->vcpu_id)
68 return 0;
69
70 kvm_for_each_vcpu(i, tcpu, kvm)
71 if (tcpu->vcpu_id == tid) {
72 kvm_vcpu_yield_to(tcpu);
73 break;
74 }
75
76 return 0;
77}
78
56static int __diag_ipl_functions(struct kvm_vcpu *vcpu) 79static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
57{ 80{
58 unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; 81 unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
@@ -89,6 +112,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
89 return diag_release_pages(vcpu); 112 return diag_release_pages(vcpu);
90 case 0x44: 113 case 0x44:
91 return __diag_time_slice_end(vcpu); 114 return __diag_time_slice_end(vcpu);
115 case 0x9c:
116 return __diag_time_slice_end_directed(vcpu);
92 case 0x308: 117 case 0x308:
93 return __diag_ipl_functions(vcpu); 118 return __diag_ipl_functions(vcpu);
94 default: 119 default:
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index d30c8350b949..fd98914a36f1 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -74,6 +74,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
74 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, 74 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
75 { "diagnose_10", VCPU_STAT(diagnose_10) }, 75 { "diagnose_10", VCPU_STAT(diagnose_10) },
76 { "diagnose_44", VCPU_STAT(diagnose_44) }, 76 { "diagnose_44", VCPU_STAT(diagnose_44) },
77 { "diagnose_9c", VCPU_STAT(diagnose_9c) },
77 { NULL } 78 { NULL }
78}; 79};
79 80
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 6f343307d72b..cae342d29d1b 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -461,6 +461,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot,
461 461
462void kvm_vcpu_block(struct kvm_vcpu *vcpu); 462void kvm_vcpu_block(struct kvm_vcpu *vcpu);
463void kvm_vcpu_kick(struct kvm_vcpu *vcpu); 463void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
464bool kvm_vcpu_yield_to(struct kvm_vcpu *target);
464void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu); 465void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu);
465void kvm_resched(struct kvm_vcpu *vcpu); 466void kvm_resched(struct kvm_vcpu *vcpu);
466void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); 467void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1847c762d8d9..7e140683ff14 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1543,6 +1543,31 @@ void kvm_resched(struct kvm_vcpu *vcpu)
1543} 1543}
1544EXPORT_SYMBOL_GPL(kvm_resched); 1544EXPORT_SYMBOL_GPL(kvm_resched);
1545 1545
1546bool kvm_vcpu_yield_to(struct kvm_vcpu *target)
1547{
1548 struct pid *pid;
1549 struct task_struct *task = NULL;
1550
1551 rcu_read_lock();
1552 pid = rcu_dereference(target->pid);
1553 if (pid)
1554 task = get_pid_task(target->pid, PIDTYPE_PID);
1555 rcu_read_unlock();
1556 if (!task)
1557 return false;
1558 if (task->flags & PF_VCPU) {
1559 put_task_struct(task);
1560 return false;
1561 }
1562 if (yield_to(task, 1)) {
1563 put_task_struct(task);
1564 return true;
1565 }
1566 put_task_struct(task);
1567 return false;
1568}
1569EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to);
1570
1546void kvm_vcpu_on_spin(struct kvm_vcpu *me) 1571void kvm_vcpu_on_spin(struct kvm_vcpu *me)
1547{ 1572{
1548 struct kvm *kvm = me->kvm; 1573 struct kvm *kvm = me->kvm;
@@ -1561,8 +1586,6 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
1561 */ 1586 */
1562 for (pass = 0; pass < 2 && !yielded; pass++) { 1587 for (pass = 0; pass < 2 && !yielded; pass++) {
1563 kvm_for_each_vcpu(i, vcpu, kvm) { 1588 kvm_for_each_vcpu(i, vcpu, kvm) {
1564 struct task_struct *task = NULL;
1565 struct pid *pid;
1566 if (!pass && i < last_boosted_vcpu) { 1589 if (!pass && i < last_boosted_vcpu) {
1567 i = last_boosted_vcpu; 1590 i = last_boosted_vcpu;
1568 continue; 1591 continue;
@@ -1572,24 +1595,11 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
1572 continue; 1595 continue;
1573 if (waitqueue_active(&vcpu->wq)) 1596 if (waitqueue_active(&vcpu->wq))
1574 continue; 1597 continue;
1575 rcu_read_lock(); 1598 if (kvm_vcpu_yield_to(vcpu)) {
1576 pid = rcu_dereference(vcpu->pid);
1577 if (pid)
1578 task = get_pid_task(vcpu->pid, PIDTYPE_PID);
1579 rcu_read_unlock();
1580 if (!task)
1581 continue;
1582 if (task->flags & PF_VCPU) {
1583 put_task_struct(task);
1584 continue;
1585 }
1586 if (yield_to(task, 1)) {
1587 put_task_struct(task);
1588 kvm->last_boosted_vcpu = i; 1599 kvm->last_boosted_vcpu = i;
1589 yielded = 1; 1600 yielded = 1;
1590 break; 1601 break;
1591 } 1602 }
1592 put_task_struct(task);
1593 } 1603 }
1594 } 1604 }
1595} 1605}