aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/irq.h1
-rw-r--r--arch/s390/include/asm/isc.h1
-rw-r--r--arch/s390/include/asm/kvm_host.h3
-rw-r--r--arch/s390/kernel/irq.c1
-rw-r--r--arch/s390/kvm/interrupt.c169
-rw-r--r--arch/s390/kvm/kvm-s390.c2
6 files changed, 175 insertions, 2 deletions
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 2f7f27e5493f..afaf5e3c57fd 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -62,6 +62,7 @@ enum interruption_class {
62 IRQIO_MSI, 62 IRQIO_MSI,
63 IRQIO_VIR, 63 IRQIO_VIR,
64 IRQIO_VAI, 64 IRQIO_VAI,
65 IRQIO_GAL,
65 NMI_NMI, 66 NMI_NMI,
66 CPU_RST, 67 CPU_RST,
67 NR_ARCH_IRQS 68 NR_ARCH_IRQS
diff --git a/arch/s390/include/asm/isc.h b/arch/s390/include/asm/isc.h
index 6cb9e2ed05b6..b2cc1ec78d06 100644
--- a/arch/s390/include/asm/isc.h
+++ b/arch/s390/include/asm/isc.h
@@ -21,6 +21,7 @@
21/* Adapter interrupts. */ 21/* Adapter interrupts. */
22#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ 22#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */
23#define PCI_ISC 2 /* PCI I/O subchannels */ 23#define PCI_ISC 2 /* PCI I/O subchannels */
24#define GAL_ISC 5 /* GIB alert */
24#define AP_ISC 6 /* adjunct processor (crypto) devices */ 25#define AP_ISC 6 /* adjunct processor (crypto) devices */
25 26
26/* Functions for registration of I/O interruption subclasses */ 27/* Functions for registration of I/O interruption subclasses */
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 2cfff617cb21..c5f51566ecd6 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -825,6 +825,9 @@ struct kvm_s390_gisa_iam {
825struct kvm_s390_gisa_interrupt { 825struct kvm_s390_gisa_interrupt {
826 struct kvm_s390_gisa *origin; 826 struct kvm_s390_gisa *origin;
827 struct kvm_s390_gisa_iam alert; 827 struct kvm_s390_gisa_iam alert;
828 struct hrtimer timer;
829 u64 expires;
830 DECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);
828}; 831};
829 832
830struct kvm_arch{ 833struct kvm_arch{
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 0e8d68bac82c..0cd5a5f96729 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -88,6 +88,7 @@ static const struct irq_class irqclass_sub_desc[] = {
88 {.irq = IRQIO_MSI, .name = "MSI", .desc = "[I/O] MSI Interrupt" }, 88 {.irq = IRQIO_MSI, .name = "MSI", .desc = "[I/O] MSI Interrupt" },
89 {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"}, 89 {.irq = IRQIO_VIR, .name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
90 {.irq = IRQIO_VAI, .name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"}, 90 {.irq = IRQIO_VAI, .name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"},
91 {.irq = IRQIO_GAL, .name = "GAL", .desc = "[I/O] GIB Alert"},
91 {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"}, 92 {.irq = NMI_NMI, .name = "NMI", .desc = "[NMI] Machine Check"},
92 {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"}, 93 {.irq = CPU_RST, .name = "RST", .desc = "[CPU] CPU Restart"},
93}; 94};
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 9faaa8f96fc3..dc446203e5a4 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -26,6 +26,7 @@
26#include <asm/gmap.h> 26#include <asm/gmap.h>
27#include <asm/switch_to.h> 27#include <asm/switch_to.h>
28#include <asm/nmi.h> 28#include <asm/nmi.h>
29#include <asm/airq.h>
29#include "kvm-s390.h" 30#include "kvm-s390.h"
30#include "gaccess.h" 31#include "gaccess.h"
31#include "trace-s390.h" 32#include "trace-s390.h"
@@ -268,6 +269,38 @@ static inline void gisa_clear_ipm(struct kvm_s390_gisa *gisa)
268 } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); 269 } while (cmpxchg(&gisa->u64.word[0], word, _word) != word);
269} 270}
270 271
272/**
273 * gisa_get_ipm_or_restore_iam - return IPM or restore GISA IAM
274 *
275 * @gi: gisa interrupt struct to work on
276 *
277 * Atomically restores the interruption alert mask if none of the
278 * relevant ISCs are pending and return the IPM.
279 *
280 * Returns: the relevant pending ISCs
281 */
282static inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi)
283{
284 u8 pending_mask, alert_mask;
285 u64 word, _word;
286
287 do {
288 word = READ_ONCE(gi->origin->u64.word[0]);
289 alert_mask = READ_ONCE(gi->alert.mask);
290 pending_mask = (u8)(word >> 24) & alert_mask;
291 if (pending_mask)
292 return pending_mask;
293 _word = (word & ~0xffUL) | alert_mask;
294 } while (cmpxchg(&gi->origin->u64.word[0], word, _word) != word);
295
296 return 0;
297}
298
299static inline int gisa_in_alert_list(struct kvm_s390_gisa *gisa)
300{
301 return READ_ONCE(gisa->next_alert) != (u32)(u64)gisa;
302}
303
271static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) 304static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)
272{ 305{
273 set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); 306 set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
@@ -1141,6 +1174,7 @@ static u64 __calculate_sltime(struct kvm_vcpu *vcpu)
1141 1174
1142int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) 1175int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
1143{ 1176{
1177 struct kvm_s390_gisa_interrupt *gi = &vcpu->kvm->arch.gisa_int;
1144 u64 sltime; 1178 u64 sltime;
1145 1179
1146 vcpu->stat.exit_wait_state++; 1180 vcpu->stat.exit_wait_state++;
@@ -1154,6 +1188,11 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
1154 return -EOPNOTSUPP; /* disabled wait */ 1188 return -EOPNOTSUPP; /* disabled wait */
1155 } 1189 }
1156 1190
1191 if (gi->origin &&
1192 (gisa_get_ipm_or_restore_iam(gi) &
1193 vcpu->arch.sie_block->gcr[6] >> 24))
1194 return 0;
1195
1157 if (!ckc_interrupts_enabled(vcpu) && 1196 if (!ckc_interrupts_enabled(vcpu) &&
1158 !cpu_timer_interrupts_enabled(vcpu)) { 1197 !cpu_timer_interrupts_enabled(vcpu)) {
1159 VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); 1198 VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer");
@@ -2939,6 +2978,93 @@ int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
2939 return n; 2978 return n;
2940} 2979}
2941 2980
2981static void __airqs_kick_single_vcpu(struct kvm *kvm, u8 deliverable_mask)
2982{
2983 int vcpu_id, online_vcpus = atomic_read(&kvm->online_vcpus);
2984 struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int;
2985 struct kvm_vcpu *vcpu;
2986
2987 for_each_set_bit(vcpu_id, kvm->arch.idle_mask, online_vcpus) {
2988 vcpu = kvm_get_vcpu(kvm, vcpu_id);
2989 if (psw_ioint_disabled(vcpu))
2990 continue;
2991 deliverable_mask &= (u8)(vcpu->arch.sie_block->gcr[6] >> 24);
2992 if (deliverable_mask) {
2993 /* lately kicked but not yet running */
2994 if (test_and_set_bit(vcpu_id, gi->kicked_mask))
2995 return;
2996 kvm_s390_vcpu_wakeup(vcpu);
2997 return;
2998 }
2999 }
3000}
3001
3002static enum hrtimer_restart gisa_vcpu_kicker(struct hrtimer *timer)
3003{
3004 struct kvm_s390_gisa_interrupt *gi =
3005 container_of(timer, struct kvm_s390_gisa_interrupt, timer);
3006 struct kvm *kvm =
3007 container_of(gi->origin, struct sie_page2, gisa)->kvm;
3008 u8 pending_mask;
3009
3010 pending_mask = gisa_get_ipm_or_restore_iam(gi);
3011 if (pending_mask) {
3012 __airqs_kick_single_vcpu(kvm, pending_mask);
3013 hrtimer_forward_now(timer, ns_to_ktime(gi->expires));
3014 return HRTIMER_RESTART;
3015 };
3016
3017 return HRTIMER_NORESTART;
3018}
3019
3020#define NULL_GISA_ADDR 0x00000000UL
3021#define NONE_GISA_ADDR 0x00000001UL
3022#define GISA_ADDR_MASK 0xfffff000UL
3023
3024static void process_gib_alert_list(void)
3025{
3026 struct kvm_s390_gisa_interrupt *gi;
3027 struct kvm_s390_gisa *gisa;
3028 struct kvm *kvm;
3029 u32 final, origin = 0UL;
3030
3031 do {
3032 /*
3033 * If the NONE_GISA_ADDR is still stored in the alert list
3034 * origin, we will leave the outer loop. No further GISA has
3035 * been added to the alert list by millicode while processing
3036 * the current alert list.
3037 */
3038 final = (origin & NONE_GISA_ADDR);
3039 /*
3040 * Cut off the alert list and store the NONE_GISA_ADDR in the
3041 * alert list origin to avoid further GAL interruptions.
3042 * A new alert list can be build up by millicode in parallel
3043 * for guests not in the yet cut-off alert list. When in the
3044 * final loop, store the NULL_GISA_ADDR instead. This will re-
3045 * enable GAL interruptions on the host again.
3046 */
3047 origin = xchg(&gib->alert_list_origin,
3048 (!final) ? NONE_GISA_ADDR : NULL_GISA_ADDR);
3049 /*
3050 * Loop through the just cut-off alert list and start the
3051 * gisa timers to kick idle vcpus to consume the pending
3052 * interruptions asap.
3053 */
3054 while (origin & GISA_ADDR_MASK) {
3055 gisa = (struct kvm_s390_gisa *)(u64)origin;
3056 origin = gisa->next_alert;
3057 gisa->next_alert = (u32)(u64)gisa;
3058 kvm = container_of(gisa, struct sie_page2, gisa)->kvm;
3059 gi = &kvm->arch.gisa_int;
3060 if (hrtimer_active(&gi->timer))
3061 hrtimer_cancel(&gi->timer);
3062 hrtimer_start(&gi->timer, 0, HRTIMER_MODE_REL);
3063 }
3064 } while (!final);
3065
3066}
3067
2942void kvm_s390_gisa_clear(struct kvm *kvm) 3068void kvm_s390_gisa_clear(struct kvm *kvm)
2943{ 3069{
2944 struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 3070 struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int;
@@ -2958,6 +3084,9 @@ void kvm_s390_gisa_init(struct kvm *kvm)
2958 gi->origin = &kvm->arch.sie_page2->gisa; 3084 gi->origin = &kvm->arch.sie_page2->gisa;
2959 gi->alert.mask = 0; 3085 gi->alert.mask = 0;
2960 spin_lock_init(&gi->alert.ref_lock); 3086 spin_lock_init(&gi->alert.ref_lock);
3087 gi->expires = 50 * 1000; /* 50 usec */
3088 hrtimer_init(&gi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
3089 gi->timer.function = gisa_vcpu_kicker;
2961 memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); 3090 memset(gi->origin, 0, sizeof(struct kvm_s390_gisa));
2962 gi->origin->next_alert = (u32)(u64)gi->origin; 3091 gi->origin->next_alert = (u32)(u64)gi->origin;
2963 VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); 3092 VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin);
@@ -2965,7 +3094,17 @@ void kvm_s390_gisa_init(struct kvm *kvm)
2965 3094
2966void kvm_s390_gisa_destroy(struct kvm *kvm) 3095void kvm_s390_gisa_destroy(struct kvm *kvm)
2967{ 3096{
2968 kvm->arch.gisa_int.origin = NULL; 3097 struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int;
3098
3099 if (!gi->origin)
3100 return;
3101 if (gi->alert.mask)
3102 KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x",
3103 kvm, gi->alert.mask);
3104 while (gisa_in_alert_list(gi->origin))
3105 cpu_relax();
3106 hrtimer_cancel(&gi->timer);
3107 gi->origin = NULL;
2969} 3108}
2970 3109
2971/** 3110/**
@@ -3051,11 +3190,23 @@ out:
3051} 3190}
3052EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister); 3191EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister);
3053 3192
3193static void gib_alert_irq_handler(struct airq_struct *airq)
3194{
3195 inc_irq_stat(IRQIO_GAL);
3196 process_gib_alert_list();
3197}
3198
3199static struct airq_struct gib_alert_irq = {
3200 .handler = gib_alert_irq_handler,
3201 .lsi_ptr = &gib_alert_irq.lsi_mask,
3202};
3203
3054void kvm_s390_gib_destroy(void) 3204void kvm_s390_gib_destroy(void)
3055{ 3205{
3056 if (!gib) 3206 if (!gib)
3057 return; 3207 return;
3058 chsc_sgib(0); 3208 chsc_sgib(0);
3209 unregister_adapter_interrupt(&gib_alert_irq);
3059 free_page((unsigned long)gib); 3210 free_page((unsigned long)gib);
3060 gib = NULL; 3211 gib = NULL;
3061} 3212}
@@ -3075,16 +3226,30 @@ int kvm_s390_gib_init(u8 nisc)
3075 goto out; 3226 goto out;
3076 } 3227 }
3077 3228
3229 gib_alert_irq.isc = nisc;
3230 if (register_adapter_interrupt(&gib_alert_irq)) {
3231 pr_err("Registering the GIB alert interruption handler failed\n");
3232 rc = -EIO;
3233 goto out_free_gib;
3234 }
3235
3078 gib->nisc = nisc; 3236 gib->nisc = nisc;
3079 if (chsc_sgib((u32)(u64)gib)) { 3237 if (chsc_sgib((u32)(u64)gib)) {
3080 pr_err("Associating the GIB with the AIV facility failed\n"); 3238 pr_err("Associating the GIB with the AIV facility failed\n");
3081 free_page((unsigned long)gib); 3239 free_page((unsigned long)gib);
3082 gib = NULL; 3240 gib = NULL;
3083 rc = -EIO; 3241 rc = -EIO;
3084 goto out; 3242 goto out_unreg_gal;
3085 } 3243 }
3086 3244
3087 KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); 3245 KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc);
3246 goto out;
3247
3248out_unreg_gal:
3249 unregister_adapter_interrupt(&gib_alert_irq);
3250out_free_gib:
3251 free_page((unsigned long)gib);
3252 gib = NULL;
3088out: 3253out:
3089 return rc; 3254 return rc;
3090} 3255}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 0de062e989e2..0099fbda2e98 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3460,6 +3460,8 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
3460 kvm_s390_patch_guest_per_regs(vcpu); 3460 kvm_s390_patch_guest_per_regs(vcpu);
3461 } 3461 }
3462 3462
3463 clear_bit(vcpu->vcpu_id, vcpu->kvm->arch.gisa_int.kicked_mask);
3464
3463 vcpu->arch.sie_block->icptcode = 0; 3465 vcpu->arch.sie_block->icptcode = 0;
3464 cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags); 3466 cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags);
3465 VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags); 3467 VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags);