aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFan Zhang <zhangfan@linux.vnet.ibm.com>2015-05-13 04:58:41 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2015-08-04 08:38:37 -0400
commitfdf036507f1fc036d5a06753e9e8b13f46de73e8 (patch)
treeb9533136fecbd73e24f9e955edcd261060ee5957
parent554726d33c20791653dbd1c047c83f93459bc586 (diff)
KVM: s390: host STP toleration for VMs
If the host has STP enabled, the TOD of the host will be changed during synchronization phases. These are performed during a stop_machine() call. As the guest TOD is based on the host TOD, we have to make sure that: - no VCPU is in the SIE (implicitly guaranteed via stop_machine()) - manual guest TOD calculations are not affected "Epoch" is the guest TOD clock delta to the host TOD clock. We have to adjust that value during the STP synchronization and make sure that code that accesses the epoch won't get interrupted in between (via disabling preemption). Signed-off-by: Fan Zhang <zhangfan@linux.vnet.ibm.com> Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/etr.h3
-rw-r--r--arch/s390/kernel/time.c16
-rw-r--r--arch/s390/kvm/interrupt.c10
-rw-r--r--arch/s390/kvm/kvm-s390.c38
-rw-r--r--arch/s390/kvm/priv.c2
5 files changed, 65 insertions, 4 deletions
diff --git a/arch/s390/include/asm/etr.h b/arch/s390/include/asm/etr.h
index 629b79a93165..f7e5c36688c3 100644
--- a/arch/s390/include/asm/etr.h
+++ b/arch/s390/include/asm/etr.h
@@ -214,6 +214,9 @@ static inline int etr_ptff(void *ptff_block, unsigned int func)
214void etr_switch_to_local(void); 214void etr_switch_to_local(void);
215void etr_sync_check(void); 215void etr_sync_check(void);
216 216
217/* notifier for syncs */
218extern struct atomic_notifier_head s390_epoch_delta_notifier;
219
217/* STP interruption parameter */ 220/* STP interruption parameter */
218struct stp_irq_parm { 221struct stp_irq_parm {
219 unsigned int _pad0 : 14; 222 unsigned int _pad0 : 14;
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 9e733d965e08..627887b075a7 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -58,6 +58,9 @@ EXPORT_SYMBOL_GPL(sched_clock_base_cc);
58 58
59static DEFINE_PER_CPU(struct clock_event_device, comparators); 59static DEFINE_PER_CPU(struct clock_event_device, comparators);
60 60
61ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
62EXPORT_SYMBOL(s390_epoch_delta_notifier);
63
61/* 64/*
62 * Scheduler clock - returns current time in nanosec units. 65 * Scheduler clock - returns current time in nanosec units.
63 */ 66 */
@@ -752,7 +755,7 @@ static void clock_sync_cpu(struct clock_sync_data *sync)
752static int etr_sync_clock(void *data) 755static int etr_sync_clock(void *data)
753{ 756{
754 static int first; 757 static int first;
755 unsigned long long clock, old_clock, delay, delta; 758 unsigned long long clock, old_clock, clock_delta, delay, delta;
756 struct clock_sync_data *etr_sync; 759 struct clock_sync_data *etr_sync;
757 struct etr_aib *sync_port, *aib; 760 struct etr_aib *sync_port, *aib;
758 int port; 761 int port;
@@ -789,6 +792,9 @@ static int etr_sync_clock(void *data)
789 delay = (unsigned long long) 792 delay = (unsigned long long)
790 (aib->edf2.etv - sync_port->edf2.etv) << 32; 793 (aib->edf2.etv - sync_port->edf2.etv) << 32;
791 delta = adjust_time(old_clock, clock, delay); 794 delta = adjust_time(old_clock, clock, delay);
795 clock_delta = clock - old_clock;
796 atomic_notifier_call_chain(&s390_epoch_delta_notifier, 0,
797 &clock_delta);
792 etr_sync->fixup_cc = delta; 798 etr_sync->fixup_cc = delta;
793 fixup_clock_comparator(delta); 799 fixup_clock_comparator(delta);
794 /* Verify that the clock is properly set. */ 800 /* Verify that the clock is properly set. */
@@ -1526,7 +1532,7 @@ void stp_island_check(void)
1526static int stp_sync_clock(void *data) 1532static int stp_sync_clock(void *data)
1527{ 1533{
1528 static int first; 1534 static int first;
1529 unsigned long long old_clock, delta; 1535 unsigned long long old_clock, delta, new_clock, clock_delta;
1530 struct clock_sync_data *stp_sync; 1536 struct clock_sync_data *stp_sync;
1531 int rc; 1537 int rc;
1532 1538
@@ -1551,7 +1557,11 @@ static int stp_sync_clock(void *data)
1551 old_clock = get_tod_clock(); 1557 old_clock = get_tod_clock();
1552 rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0); 1558 rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0);
1553 if (rc == 0) { 1559 if (rc == 0) {
1554 delta = adjust_time(old_clock, get_tod_clock(), 0); 1560 new_clock = get_tod_clock();
1561 delta = adjust_time(old_clock, new_clock, 0);
1562 clock_delta = new_clock - old_clock;
1563 atomic_notifier_call_chain(&s390_epoch_delta_notifier,
1564 0, &clock_delta);
1555 fixup_clock_comparator(delta); 1565 fixup_clock_comparator(delta);
1556 rc = chsc_sstpi(stp_page, &stp_info, 1566 rc = chsc_sstpi(stp_page, &stp_info,
1557 sizeof(struct stp_sstpi)); 1567 sizeof(struct stp_sstpi));
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index a5781404b83f..b277d50dcf76 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -71,9 +71,13 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
71 71
72static int ckc_irq_pending(struct kvm_vcpu *vcpu) 72static int ckc_irq_pending(struct kvm_vcpu *vcpu)
73{ 73{
74 preempt_disable();
74 if (!(vcpu->arch.sie_block->ckc < 75 if (!(vcpu->arch.sie_block->ckc <
75 get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) 76 get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) {
77 preempt_enable();
76 return 0; 78 return 0;
79 }
80 preempt_enable();
77 return ckc_interrupts_enabled(vcpu); 81 return ckc_interrupts_enabled(vcpu);
78} 82}
79 83
@@ -856,7 +860,9 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
856 goto no_timer; 860 goto no_timer;
857 } 861 }
858 862
863 preempt_disable();
859 now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch; 864 now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
865 preempt_enable();
860 sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); 866 sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
861 867
862 /* underflow */ 868 /* underflow */
@@ -895,7 +901,9 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
895 u64 now, sltime; 901 u64 now, sltime;
896 902
897 vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer); 903 vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
904 preempt_disable();
898 now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch; 905 now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
906 preempt_enable();
899 sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); 907 sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
900 908
901 /* 909 /*
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 924b1ae86caf..4bdb860b5c49 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -28,6 +28,7 @@
28#include <linux/vmalloc.h> 28#include <linux/vmalloc.h>
29#include <asm/asm-offsets.h> 29#include <asm/asm-offsets.h>
30#include <asm/lowcore.h> 30#include <asm/lowcore.h>
31#include <asm/etr.h>
31#include <asm/pgtable.h> 32#include <asm/pgtable.h>
32#include <asm/nmi.h> 33#include <asm/nmi.h>
33#include <asm/switch_to.h> 34#include <asm/switch_to.h>
@@ -138,16 +139,47 @@ int kvm_arch_hardware_enable(void)
138 139
139static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address); 140static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
140 141
142/*
143 * This callback is executed during stop_machine(). All CPUs are therefore
144 * temporarily stopped. In order not to change guest behavior, we have to
145 * disable preemption whenever we touch the epoch of kvm and the VCPUs,
146 * so a CPU won't be stopped while calculating with the epoch.
147 */
148static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val,
149 void *v)
150{
151 struct kvm *kvm;
152 struct kvm_vcpu *vcpu;
153 int i;
154 unsigned long long *delta = v;
155
156 list_for_each_entry(kvm, &vm_list, vm_list) {
157 kvm->arch.epoch -= *delta;
158 kvm_for_each_vcpu(i, vcpu, kvm) {
159 vcpu->arch.sie_block->epoch -= *delta;
160 }
161 }
162 return NOTIFY_OK;
163}
164
165static struct notifier_block kvm_clock_notifier = {
166 .notifier_call = kvm_clock_sync,
167};
168
141int kvm_arch_hardware_setup(void) 169int kvm_arch_hardware_setup(void)
142{ 170{
143 gmap_notifier.notifier_call = kvm_gmap_notifier; 171 gmap_notifier.notifier_call = kvm_gmap_notifier;
144 gmap_register_ipte_notifier(&gmap_notifier); 172 gmap_register_ipte_notifier(&gmap_notifier);
173 atomic_notifier_chain_register(&s390_epoch_delta_notifier,
174 &kvm_clock_notifier);
145 return 0; 175 return 0;
146} 176}
147 177
148void kvm_arch_hardware_unsetup(void) 178void kvm_arch_hardware_unsetup(void)
149{ 179{
150 gmap_unregister_ipte_notifier(&gmap_notifier); 180 gmap_unregister_ipte_notifier(&gmap_notifier);
181 atomic_notifier_chain_unregister(&s390_epoch_delta_notifier,
182 &kvm_clock_notifier);
151} 183}
152 184
153int kvm_arch_init(void *opaque) 185int kvm_arch_init(void *opaque)
@@ -501,11 +533,13 @@ static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
501 return r; 533 return r;
502 534
503 mutex_lock(&kvm->lock); 535 mutex_lock(&kvm->lock);
536 preempt_disable();
504 kvm->arch.epoch = gtod - host_tod; 537 kvm->arch.epoch = gtod - host_tod;
505 kvm_s390_vcpu_block_all(kvm); 538 kvm_s390_vcpu_block_all(kvm);
506 kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm) 539 kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm)
507 cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch; 540 cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch;
508 kvm_s390_vcpu_unblock_all(kvm); 541 kvm_s390_vcpu_unblock_all(kvm);
542 preempt_enable();
509 mutex_unlock(&kvm->lock); 543 mutex_unlock(&kvm->lock);
510 VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx\n", gtod); 544 VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx\n", gtod);
511 return 0; 545 return 0;
@@ -553,7 +587,9 @@ static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
553 if (r) 587 if (r)
554 return r; 588 return r;
555 589
590 preempt_disable();
556 gtod = host_tod + kvm->arch.epoch; 591 gtod = host_tod + kvm->arch.epoch;
592 preempt_enable();
557 if (copy_to_user((void __user *)attr->addr, &gtod, sizeof(gtod))) 593 if (copy_to_user((void __user *)attr->addr, &gtod, sizeof(gtod)))
558 return -EFAULT; 594 return -EFAULT;
559 VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx\n", gtod); 595 VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx\n", gtod);
@@ -1314,7 +1350,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
1314void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) 1350void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
1315{ 1351{
1316 mutex_lock(&vcpu->kvm->lock); 1352 mutex_lock(&vcpu->kvm->lock);
1353 preempt_disable();
1317 vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch; 1354 vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
1355 preempt_enable();
1318 mutex_unlock(&vcpu->kvm->lock); 1356 mutex_unlock(&vcpu->kvm->lock);
1319 if (!kvm_is_ucontrol(vcpu->kvm)) 1357 if (!kvm_is_ucontrol(vcpu->kvm))
1320 vcpu->arch.gmap = vcpu->kvm->arch.gmap; 1358 vcpu->arch.gmap = vcpu->kvm->arch.gmap;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index afefa3bb2f13..4d21dc4d1a84 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -57,8 +57,10 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
57 val = (val - hostclk) & ~0x3fUL; 57 val = (val - hostclk) & ~0x3fUL;
58 58
59 mutex_lock(&vcpu->kvm->lock); 59 mutex_lock(&vcpu->kvm->lock);
60 preempt_disable();
60 kvm_for_each_vcpu(i, cpup, vcpu->kvm) 61 kvm_for_each_vcpu(i, cpup, vcpu->kvm)
61 cpup->arch.sie_block->epoch = val; 62 cpup->arch.sie_block->epoch = val;
63 preempt_enable();
62 mutex_unlock(&vcpu->kvm->lock); 64 mutex_unlock(&vcpu->kvm->lock);
63 65
64 kvm_s390_set_psw_cc(vcpu, 0); 66 kvm_s390_set_psw_cc(vcpu, 0);