Skip to content

Commit

Permalink
Merge tag 'kvm-s390-next-4.6-2' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/kvms390/linux into HEAD

KVM: s390: Fixes and features for kvm/next (4.6) part 2

- add watchdog diagnose to trace event decoder
- better handle the cpu timer when not inside the guest
- only provide STFLE if the CPU model has STFLE
- reduce DMA page usage
  • Loading branch information
bonzini committed Mar 10, 2016
2 parents 5a5fbdc + c54f0d6 commit f958ee7
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 71 deletions.
33 changes: 25 additions & 8 deletions arch/s390/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/kvm_types.h>
#include <linux/kvm_host.h>
#include <linux/kvm.h>
#include <linux/seqlock.h>
#include <asm/debug.h>
#include <asm/cpu.h>
#include <asm/fpu/api.h>
Expand Down Expand Up @@ -552,6 +553,15 @@ struct kvm_vcpu_arch {
unsigned long pfault_token;
unsigned long pfault_select;
unsigned long pfault_compare;
bool cputm_enabled;
/*
* The seqcount protects updates to cputm_start and sie_block.cputm,
* this way we can have non-blocking reads with consistent values.
* Only the owning VCPU thread (vcpu->cpu) is allowed to change these
* values and to start/stop/enable/disable cpu timer accounting.
*/
seqcount_t cputm_seqcount;
__u64 cputm_start;
};

struct kvm_vm_stat {
Expand Down Expand Up @@ -590,15 +600,11 @@ struct s390_io_adapter {
#define S390_ARCH_FAC_MASK_SIZE_U64 \
(S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))

struct kvm_s390_fac {
/* facility list requested by guest */
__u64 list[S390_ARCH_FAC_LIST_SIZE_U64];
/* facility mask supported by kvm & hosting machine */
__u64 mask[S390_ARCH_FAC_LIST_SIZE_U64];
};

struct kvm_s390_cpu_model {
struct kvm_s390_fac *fac;
/* facility mask supported by kvm & hosting machine */
__u64 fac_mask[S390_ARCH_FAC_LIST_SIZE_U64];
/* facility list requested by guest (in dma page) */
__u64 *fac_list;
struct cpuid cpu_id;
unsigned short ibc;
};
Expand All @@ -617,6 +623,16 @@ struct kvm_s390_crypto_cb {
__u8 reserved80[128]; /* 0x0080 */
};

/*
* sie_page2 has to be allocated as DMA because fac_list and crycb need
* 31bit addresses in the sie control block.
*/
struct sie_page2 {
__u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */
struct kvm_s390_crypto_cb crycb; /* 0x0800 */
u8 reserved900[0x1000 - 0x900]; /* 0x0900 */
} __packed;

struct kvm_arch{
void *sca;
int use_esca;
Expand All @@ -637,6 +653,7 @@ struct kvm_arch{
int ipte_lock_count;
struct mutex ipte_mutex;
spinlock_t start_stop_lock;
struct sie_page2 *sie_page2;
struct kvm_s390_cpu_model model;
struct kvm_s390_crypto crypto;
u64 epoch;
Expand Down
1 change: 1 addition & 0 deletions arch/s390/include/uapi/asm/sie.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
{ 0x9c, "DIAG (0x9c) time slice end directed" }, \
{ 0x204, "DIAG (0x204) logical-cpu utilization" }, \
{ 0x258, "DIAG (0x258) page-reference services" }, \
{ 0x288, "DIAG (0x288) watchdog functions" }, \
{ 0x308, "DIAG (0x308) ipl functions" }, \
{ 0x500, "DIAG (0x500) KVM virtio functions" }, \
{ 0x501, "DIAG (0x501) KVM breakpoint" }
Expand Down
53 changes: 38 additions & 15 deletions arch/s390/kvm/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ static int cpu_timer_interrupts_enabled(struct kvm_vcpu *vcpu)

static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu)
{
return (vcpu->arch.sie_block->cputm >> 63) &&
cpu_timer_interrupts_enabled(vcpu);
if (!cpu_timer_interrupts_enabled(vcpu))
return 0;
return kvm_s390_get_cpu_timer(vcpu) >> 63;
}

static inline int is_ioirq(unsigned long irq_type)
Expand Down Expand Up @@ -908,9 +909,35 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
return ckc_irq_pending(vcpu) || cpu_timer_irq_pending(vcpu);
}

static u64 __calculate_sltime(struct kvm_vcpu *vcpu)
{
u64 now, cputm, sltime = 0;

if (ckc_interrupts_enabled(vcpu)) {
now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
/* already expired or overflow? */
if (!sltime || vcpu->arch.sie_block->ckc <= now)
return 0;
if (cpu_timer_interrupts_enabled(vcpu)) {
cputm = kvm_s390_get_cpu_timer(vcpu);
/* already expired? */
if (cputm >> 63)
return 0;
return min(sltime, tod_to_ns(cputm));
}
} else if (cpu_timer_interrupts_enabled(vcpu)) {
sltime = kvm_s390_get_cpu_timer(vcpu);
/* already expired? */
if (sltime >> 63)
return 0;
}
return sltime;
}

int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
{
u64 now, sltime;
u64 sltime;

vcpu->stat.exit_wait_state++;

Expand All @@ -923,22 +950,20 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
return -EOPNOTSUPP; /* disabled wait */
}

if (!ckc_interrupts_enabled(vcpu)) {
if (!ckc_interrupts_enabled(vcpu) &&
!cpu_timer_interrupts_enabled(vcpu)) {
VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer");
__set_cpu_idle(vcpu);
goto no_timer;
}

now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);

/* underflow */
if (vcpu->arch.sie_block->ckc < now)
sltime = __calculate_sltime(vcpu);
if (!sltime)
return 0;

__set_cpu_idle(vcpu);
hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL);
VCPU_EVENT(vcpu, 4, "enabled wait via clock comparator: %llu ns", sltime);
VCPU_EVENT(vcpu, 4, "enabled wait: %llu ns", sltime);
no_timer:
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
kvm_vcpu_block(vcpu);
Expand All @@ -965,18 +990,16 @@ void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
{
struct kvm_vcpu *vcpu;
u64 now, sltime;
u64 sltime;

vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
sltime = __calculate_sltime(vcpu);

/*
* If the monotonic clock runs faster than the tod clock we might be
* woken up too early and have to go back to sleep to avoid deadlocks.
*/
if (vcpu->arch.sie_block->ckc > now &&
hrtimer_forward_now(timer, ns_to_ktime(sltime)))
if (sltime && hrtimer_forward_now(timer, ns_to_ktime(sltime)))
return HRTIMER_RESTART;
kvm_s390_vcpu_wakeup(vcpu);
return HRTIMER_NORESTART;
Expand Down
Loading

0 comments on commit f958ee7

Please sign in to comment.