Skip to content

Commit 41628d3

Browse files
Konstantin Weitzmatosatti
Konstantin Weitz
authored andcommitted
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>
1 parent b6ddf05 commit 41628d3

File tree

5 files changed

+54
-16
lines changed

5 files changed

+54
-16
lines changed

arch/s390/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ struct kvm_vcpu_stat {
148148
u32 instruction_sigp_restart;
149149
u32 diagnose_10;
150150
u32 diagnose_44;
151+
u32 diagnose_9c;
151152
};
152153

153154
struct kvm_s390_io_info {

arch/s390/kvm/diag.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,29 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
5353
return 0;
5454
}
5555

56+
static 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+
5679
static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
5780
{
5881
unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
@@ -89,6 +112,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
89112
return diag_release_pages(vcpu);
90113
case 0x44:
91114
return __diag_time_slice_end(vcpu);
115+
case 0x9c:
116+
return __diag_time_slice_end_directed(vcpu);
92117
case 0x308:
93118
return __diag_ipl_functions(vcpu);
94119
default:

arch/s390/kvm/kvm-s390.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
7474
{ "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
7575
{ "diagnose_10", VCPU_STAT(diagnose_10) },
7676
{ "diagnose_44", VCPU_STAT(diagnose_44) },
77+
{ "diagnose_9c", VCPU_STAT(diagnose_9c) },
7778
{ NULL }
7879
};
7980

include/linux/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot,
461461

462462
void kvm_vcpu_block(struct kvm_vcpu *vcpu);
463463
void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
464+
bool kvm_vcpu_yield_to(struct kvm_vcpu *target);
464465
void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu);
465466
void kvm_resched(struct kvm_vcpu *vcpu);
466467
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);

virt/kvm/kvm_main.c

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,31 @@ void kvm_resched(struct kvm_vcpu *vcpu)
15431543
}
15441544
EXPORT_SYMBOL_GPL(kvm_resched);
15451545

1546+
bool 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+
}
1569+
EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to);
1570+
15461571
void kvm_vcpu_on_spin(struct kvm_vcpu *me)
15471572
{
15481573
struct kvm *kvm = me->kvm;
@@ -1561,8 +1586,6 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
15611586
*/
15621587
for (pass = 0; pass < 2 && !yielded; pass++) {
15631588
kvm_for_each_vcpu(i, vcpu, kvm) {
1564-
struct task_struct *task = NULL;
1565-
struct pid *pid;
15661589
if (!pass && i < last_boosted_vcpu) {
15671590
i = last_boosted_vcpu;
15681591
continue;
@@ -1572,24 +1595,11 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
15721595
continue;
15731596
if (waitqueue_active(&vcpu->wq))
15741597
continue;
1575-
rcu_read_lock();
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);
1598+
if (kvm_vcpu_yield_to(vcpu)) {
15881599
kvm->last_boosted_vcpu = i;
15891600
yielded = 1;
15901601
break;
15911602
}
1592-
put_task_struct(task);
15931603
}
15941604
}
15951605
}

0 commit comments

Comments
 (0)