KVM: s390: Fixes for 4.4
A bunch of fixes and optimizations for interrupt and time handling. No fix is important enough to qualify for 4.3 or stable. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJWHQ0hAAoJEBF7vIC1phx8pmMP/jx+wYMA5U4Gi5OT4HzyFUoh nNoQUuwLSykg82vTZgajJFP5Wo4cIDXs2pLUOsuJFpufUY1S2fRgdqjNLcnIKarz BY/a6t9nXYQqEDxeHXIkS1sqTXcpEv6yHfitpZCyAz2D+oDmOXQLyJ7tEpp3JGUh WwTA1b4cTOpdASWCB2ldcgKDiKMA70dm7e+3ejGlib6v/aoEWDI0/n/0/UZbH8gm Q9hKcdxhwqTqVMlMSHcCkcKqKMJpY/8eNNWtlTgVc7gd0kFaLc+T5JToJKUTmE5G lCCkBO3TjOGKnoccIRYc7DW+vHVR5er5IaNIRpxnCf/g3FF9R1jbfm9DixYT29IG H3GJSZwQMo0glWNfzuBlgmBAgMTGMka9+0zXvXUw+TIOFmjgjIx0w5H0rYmUdE6j tZYLYGa96DqdDur1lLN6RJGaO2O08bI2J6TJXJ5h1x8qY6V2YKLRGOabXxLEUut2 LvanLczT4ou27fgW2kOpcLgCYKT1l2nlH22WzilpITKpBQFSq1flFMQfB32jqQJI v41aNBwIEqE/9dR1Zrwad6m//t9u8PAv3fna8cdchYolq/ZZF30R8BJW9lYxeify htPKhITzL30JdN3bw5ItVFA/p4YIqVswwq6u+pc9vpWeI4xG71Vq2DybhmuOQ6yd kuojcihXhEzkk2vit3Cc =LJJQ -----END PGP SIGNATURE----- Merge tag 'kvm-s390-next-20151013' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD KVM: s390: Fixes for 4.4 A bunch of fixes and optimizations for interrupt and time handling. No fix is important enough to qualify for 4.3 or stable.
This commit is contained in:
commit
1330a0170a
4 changed files with 97 additions and 119 deletions
|
@ -51,11 +51,9 @@ static int psw_mchk_disabled(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
|
static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
|
return psw_extint_disabled(vcpu) &&
|
||||||
(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) ||
|
psw_ioint_disabled(vcpu) &&
|
||||||
(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT))
|
psw_mchk_disabled(vcpu);
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
|
static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
|
||||||
|
@ -71,13 +69,8 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static int ckc_irq_pending(struct kvm_vcpu *vcpu)
|
static int ckc_irq_pending(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
preempt_disable();
|
if (vcpu->arch.sie_block->ckc >= kvm_s390_get_tod_clock_fast(vcpu->kvm))
|
||||||
if (!(vcpu->arch.sie_block->ckc <
|
|
||||||
get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) {
|
|
||||||
preempt_enable();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
preempt_enable();
|
|
||||||
return ckc_interrupts_enabled(vcpu);
|
return ckc_interrupts_enabled(vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,14 +102,10 @@ static inline u8 int_word_to_isc(u32 int_word)
|
||||||
return (int_word & 0x38000000) >> 27;
|
return (int_word & 0x38000000) >> 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long pending_floating_irqs(struct kvm_vcpu *vcpu)
|
static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
return vcpu->kvm->arch.float_int.pending_irqs;
|
return vcpu->kvm->arch.float_int.pending_irqs |
|
||||||
}
|
vcpu->arch.local_int.pending_irqs;
|
||||||
|
|
||||||
static inline unsigned long pending_local_irqs(struct kvm_vcpu *vcpu)
|
|
||||||
{
|
|
||||||
return vcpu->arch.local_int.pending_irqs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
|
static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
|
||||||
|
@ -135,8 +124,7 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
unsigned long active_mask;
|
unsigned long active_mask;
|
||||||
|
|
||||||
active_mask = pending_local_irqs(vcpu);
|
active_mask = pending_irqs(vcpu);
|
||||||
active_mask |= pending_floating_irqs(vcpu);
|
|
||||||
if (!active_mask)
|
if (!active_mask)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -204,7 +192,7 @@ static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
|
||||||
|
|
||||||
static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
|
static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (!(pending_floating_irqs(vcpu) & IRQ_PEND_IO_MASK))
|
if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK))
|
||||||
return;
|
return;
|
||||||
else if (psw_ioint_disabled(vcpu))
|
else if (psw_ioint_disabled(vcpu))
|
||||||
__set_cpuflag(vcpu, CPUSTAT_IO_INT);
|
__set_cpuflag(vcpu, CPUSTAT_IO_INT);
|
||||||
|
@ -214,7 +202,7 @@ static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
|
static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (!(pending_local_irqs(vcpu) & IRQ_PEND_EXT_MASK))
|
if (!(pending_irqs(vcpu) & IRQ_PEND_EXT_MASK))
|
||||||
return;
|
return;
|
||||||
if (psw_extint_disabled(vcpu))
|
if (psw_extint_disabled(vcpu))
|
||||||
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
|
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
|
||||||
|
@ -224,7 +212,7 @@ static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu)
|
static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (!(pending_local_irqs(vcpu) & IRQ_PEND_MCHK_MASK))
|
if (!(pending_irqs(vcpu) & IRQ_PEND_MCHK_MASK))
|
||||||
return;
|
return;
|
||||||
if (psw_mchk_disabled(vcpu))
|
if (psw_mchk_disabled(vcpu))
|
||||||
vcpu->arch.sie_block->ictl |= ICTL_LPSW;
|
vcpu->arch.sie_block->ictl |= ICTL_LPSW;
|
||||||
|
@ -815,23 +803,21 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
|
int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
|
||||||
{
|
{
|
||||||
int rc;
|
if (deliverable_irqs(vcpu))
|
||||||
|
return 1;
|
||||||
|
|
||||||
rc = !!deliverable_irqs(vcpu);
|
if (kvm_cpu_has_pending_timer(vcpu))
|
||||||
|
return 1;
|
||||||
if (!rc && kvm_cpu_has_pending_timer(vcpu))
|
|
||||||
rc = 1;
|
|
||||||
|
|
||||||
/* external call pending and deliverable */
|
/* external call pending and deliverable */
|
||||||
if (!rc && kvm_s390_ext_call_pending(vcpu) &&
|
if (kvm_s390_ext_call_pending(vcpu) &&
|
||||||
!psw_extint_disabled(vcpu) &&
|
!psw_extint_disabled(vcpu) &&
|
||||||
(vcpu->arch.sie_block->gcr[0] & 0x2000ul))
|
(vcpu->arch.sie_block->gcr[0] & 0x2000ul))
|
||||||
rc = 1;
|
return 1;
|
||||||
|
|
||||||
if (!rc && !exclude_stop && kvm_s390_is_stop_irq_pending(vcpu))
|
if (!exclude_stop && kvm_s390_is_stop_irq_pending(vcpu))
|
||||||
rc = 1;
|
return 1;
|
||||||
|
return 0;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
||||||
|
@ -846,7 +832,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
|
||||||
vcpu->stat.exit_wait_state++;
|
vcpu->stat.exit_wait_state++;
|
||||||
|
|
||||||
/* fast path */
|
/* fast path */
|
||||||
if (kvm_cpu_has_pending_timer(vcpu) || kvm_arch_vcpu_runnable(vcpu))
|
if (kvm_arch_vcpu_runnable(vcpu))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (psw_interrupts_disabled(vcpu)) {
|
if (psw_interrupts_disabled(vcpu)) {
|
||||||
|
@ -860,9 +846,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
|
||||||
goto no_timer;
|
goto no_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
preempt_disable();
|
now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
|
||||||
now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
|
|
||||||
preempt_enable();
|
|
||||||
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
|
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
|
||||||
|
|
||||||
/* underflow */
|
/* underflow */
|
||||||
|
@ -901,9 +885,7 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
|
||||||
u64 now, sltime;
|
u64 now, sltime;
|
||||||
|
|
||||||
vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
|
vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
|
||||||
preempt_disable();
|
now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
|
||||||
now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
|
|
||||||
preempt_enable();
|
|
||||||
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
|
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -981,39 +963,30 @@ static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
|
||||||
trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
|
trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
|
||||||
irq->u.pgm.code, 0);
|
irq->u.pgm.code, 0);
|
||||||
|
|
||||||
li->irq.pgm = irq->u.pgm;
|
if (irq->u.pgm.code == PGM_PER) {
|
||||||
|
li->irq.pgm.code |= PGM_PER;
|
||||||
|
/* only modify PER related information */
|
||||||
|
li->irq.pgm.per_address = irq->u.pgm.per_address;
|
||||||
|
li->irq.pgm.per_code = irq->u.pgm.per_code;
|
||||||
|
li->irq.pgm.per_atmid = irq->u.pgm.per_atmid;
|
||||||
|
li->irq.pgm.per_access_id = irq->u.pgm.per_access_id;
|
||||||
|
} else if (!(irq->u.pgm.code & PGM_PER)) {
|
||||||
|
li->irq.pgm.code = (li->irq.pgm.code & PGM_PER) |
|
||||||
|
irq->u.pgm.code;
|
||||||
|
/* only modify non-PER information */
|
||||||
|
li->irq.pgm.trans_exc_code = irq->u.pgm.trans_exc_code;
|
||||||
|
li->irq.pgm.mon_code = irq->u.pgm.mon_code;
|
||||||
|
li->irq.pgm.data_exc_code = irq->u.pgm.data_exc_code;
|
||||||
|
li->irq.pgm.mon_class_nr = irq->u.pgm.mon_class_nr;
|
||||||
|
li->irq.pgm.exc_access_id = irq->u.pgm.exc_access_id;
|
||||||
|
li->irq.pgm.op_access_id = irq->u.pgm.op_access_id;
|
||||||
|
} else {
|
||||||
|
li->irq.pgm = irq->u.pgm;
|
||||||
|
}
|
||||||
set_bit(IRQ_PEND_PROG, &li->pending_irqs);
|
set_bit(IRQ_PEND_PROG, &li->pending_irqs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
|
|
||||||
{
|
|
||||||
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
|
|
||||||
struct kvm_s390_irq irq;
|
|
||||||
|
|
||||||
spin_lock(&li->lock);
|
|
||||||
irq.u.pgm.code = code;
|
|
||||||
__inject_prog(vcpu, &irq);
|
|
||||||
BUG_ON(waitqueue_active(li->wq));
|
|
||||||
spin_unlock(&li->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
|
|
||||||
struct kvm_s390_pgm_info *pgm_info)
|
|
||||||
{
|
|
||||||
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
|
|
||||||
struct kvm_s390_irq irq;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
spin_lock(&li->lock);
|
|
||||||
irq.u.pgm = *pgm_info;
|
|
||||||
rc = __inject_prog(vcpu, &irq);
|
|
||||||
BUG_ON(waitqueue_active(li->wq));
|
|
||||||
spin_unlock(&li->lock);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
|
static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
|
||||||
{
|
{
|
||||||
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
|
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
|
||||||
|
@ -1390,12 +1363,9 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
|
||||||
|
|
||||||
static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
|
static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
|
||||||
{
|
{
|
||||||
struct kvm_s390_float_interrupt *fi;
|
|
||||||
u64 type = READ_ONCE(inti->type);
|
u64 type = READ_ONCE(inti->type);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
fi = &kvm->arch.float_int;
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case KVM_S390_MCHK:
|
case KVM_S390_MCHK:
|
||||||
rc = __inject_float_mchk(kvm, inti);
|
rc = __inject_float_mchk(kvm, inti);
|
||||||
|
|
|
@ -521,27 +521,12 @@ static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
|
||||||
static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *cur_vcpu;
|
u64 gtod;
|
||||||
unsigned int vcpu_idx;
|
|
||||||
u64 host_tod, gtod;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod)))
|
if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
r = store_tod_clock(&host_tod);
|
kvm_s390_set_tod_clock(kvm, gtod);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
preempt_disable();
|
|
||||||
kvm->arch.epoch = gtod - host_tod;
|
|
||||||
kvm_s390_vcpu_block_all(kvm);
|
|
||||||
kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm)
|
|
||||||
cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch;
|
|
||||||
kvm_s390_vcpu_unblock_all(kvm);
|
|
||||||
preempt_enable();
|
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx\n", gtod);
|
VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx\n", gtod);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -581,16 +566,9 @@ static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
|
||||||
static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
{
|
{
|
||||||
u64 host_tod, gtod;
|
u64 gtod;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = store_tod_clock(&host_tod);
|
gtod = kvm_s390_get_tod_clock_fast(kvm);
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
gtod = host_tod + kvm->arch.epoch;
|
|
||||||
preempt_enable();
|
|
||||||
if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod)))
|
if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx\n", gtod);
|
VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx\n", gtod);
|
||||||
|
@ -1916,6 +1894,22 @@ retry:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
preempt_disable();
|
||||||
|
kvm->arch.epoch = tod - get_tod_clock();
|
||||||
|
kvm_s390_vcpu_block_all(kvm);
|
||||||
|
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||||
|
vcpu->arch.sie_block->epoch = kvm->arch.epoch;
|
||||||
|
kvm_s390_vcpu_unblock_all(kvm);
|
||||||
|
preempt_enable();
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_arch_fault_in_page - fault-in guest page if necessary
|
* kvm_arch_fault_in_page - fault-in guest page if necessary
|
||||||
* @vcpu: The corresponding virtual cpu
|
* @vcpu: The corresponding virtual cpu
|
||||||
|
|
|
@ -175,6 +175,7 @@ static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm)
|
||||||
return kvm->arch.user_cpu_state_ctrl != 0;
|
return kvm->arch.user_cpu_state_ctrl != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* implemented in interrupt.c */
|
||||||
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
|
||||||
void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
|
void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
|
||||||
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
|
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
|
||||||
|
@ -185,7 +186,25 @@ int __must_check kvm_s390_inject_vm(struct kvm *kvm,
|
||||||
struct kvm_s390_interrupt *s390int);
|
struct kvm_s390_interrupt *s390int);
|
||||||
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_s390_irq *irq);
|
struct kvm_s390_irq *irq);
|
||||||
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
|
static inline int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
|
||||||
|
struct kvm_s390_pgm_info *pgm_info)
|
||||||
|
{
|
||||||
|
struct kvm_s390_irq irq = {
|
||||||
|
.type = KVM_S390_PROGRAM_INT,
|
||||||
|
.u.pgm = *pgm_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
return kvm_s390_inject_vcpu(vcpu, &irq);
|
||||||
|
}
|
||||||
|
static inline int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
|
||||||
|
{
|
||||||
|
struct kvm_s390_irq irq = {
|
||||||
|
.type = KVM_S390_PROGRAM_INT,
|
||||||
|
.u.pgm.code = code,
|
||||||
|
};
|
||||||
|
|
||||||
|
return kvm_s390_inject_vcpu(vcpu, &irq);
|
||||||
|
}
|
||||||
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
||||||
u64 isc_mask, u32 schid);
|
u64 isc_mask, u32 schid);
|
||||||
int kvm_s390_reinject_io_int(struct kvm *kvm,
|
int kvm_s390_reinject_io_int(struct kvm *kvm,
|
||||||
|
@ -212,6 +231,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
|
||||||
int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
|
||||||
|
|
||||||
/* implemented in kvm-s390.c */
|
/* implemented in kvm-s390.c */
|
||||||
|
void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
|
||||||
long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
|
long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
|
||||||
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
|
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
|
||||||
int kvm_s390_store_adtl_status_unloaded(struct kvm_vcpu *vcpu,
|
int kvm_s390_store_adtl_status_unloaded(struct kvm_vcpu *vcpu,
|
||||||
|
@ -231,9 +251,6 @@ extern unsigned long kvm_s390_fac_list_mask[];
|
||||||
|
|
||||||
/* implemented in diag.c */
|
/* implemented in diag.c */
|
||||||
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
|
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
|
||||||
/* implemented in interrupt.c */
|
|
||||||
int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
|
|
||||||
struct kvm_s390_pgm_info *pgm_info);
|
|
||||||
|
|
||||||
static inline void kvm_s390_vcpu_block_all(struct kvm *kvm)
|
static inline void kvm_s390_vcpu_block_all(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
|
@ -254,6 +271,16 @@ static inline void kvm_s390_vcpu_unblock_all(struct kvm *kvm)
|
||||||
kvm_s390_vcpu_unblock(vcpu);
|
kvm_s390_vcpu_unblock(vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u64 kvm_s390_get_tod_clock_fast(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
u64 rc;
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
|
rc = get_tod_clock_fast() + kvm->arch.epoch;
|
||||||
|
preempt_enable();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_s390_inject_prog_cond - conditionally inject a program check
|
* kvm_s390_inject_prog_cond - conditionally inject a program check
|
||||||
* @vcpu: virtual cpu
|
* @vcpu: virtual cpu
|
||||||
|
|
|
@ -33,11 +33,9 @@
|
||||||
/* Handle SCK (SET CLOCK) interception */
|
/* Handle SCK (SET CLOCK) interception */
|
||||||
static int handle_set_clock(struct kvm_vcpu *vcpu)
|
static int handle_set_clock(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *cpup;
|
int rc;
|
||||||
s64 hostclk, val;
|
|
||||||
int i, rc;
|
|
||||||
ar_t ar;
|
ar_t ar;
|
||||||
u64 op2;
|
u64 op2, val;
|
||||||
|
|
||||||
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
|
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
|
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
|
||||||
|
@ -49,19 +47,8 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
|
||||||
if (rc)
|
if (rc)
|
||||||
return kvm_s390_inject_prog_cond(vcpu, rc);
|
return kvm_s390_inject_prog_cond(vcpu, rc);
|
||||||
|
|
||||||
if (store_tod_clock(&hostclk)) {
|
|
||||||
kvm_s390_set_psw_cc(vcpu, 3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val);
|
VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val);
|
||||||
val = (val - hostclk) & ~0x3fUL;
|
kvm_s390_set_tod_clock(vcpu->kvm, val);
|
||||||
|
|
||||||
mutex_lock(&vcpu->kvm->lock);
|
|
||||||
preempt_disable();
|
|
||||||
kvm_for_each_vcpu(i, cpup, vcpu->kvm)
|
|
||||||
cpup->arch.sie_block->epoch = val;
|
|
||||||
preempt_enable();
|
|
||||||
mutex_unlock(&vcpu->kvm->lock);
|
|
||||||
|
|
||||||
kvm_s390_set_psw_cc(vcpu, 0);
|
kvm_s390_set_psw_cc(vcpu, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue