diff options
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r-- | arch/s390/kvm/interrupt.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 040745b23224..9faaa8f96fc3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -249,6 +249,25 @@ static inline int gisa_set_iam(struct kvm_s390_gisa *gisa, u8 iam) | |||
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | 251 | ||
252 | /** | ||
253 | * gisa_clear_ipm - clear the GISA interruption pending mask | ||
254 | * | ||
255 | * @gisa: gisa to operate on | ||
256 | * | ||
257 | * Clear the IPM atomically with the next alert address and the IAM | ||
258 | * of the GISA unconditionally. All three fields are located in the | ||
259 | * first long word of the GISA. | ||
260 | */ | ||
261 | static inline void gisa_clear_ipm(struct kvm_s390_gisa *gisa) | ||
262 | { | ||
263 | u64 word, _word; | ||
264 | |||
265 | do { | ||
266 | word = READ_ONCE(gisa->u64.word[0]); | ||
267 | _word = word & ~(0xffUL << 24); | ||
268 | } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); | ||
269 | } | ||
270 | |||
252 | static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) | 271 | static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) |
253 | { | 272 | { |
254 | set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); | 273 | set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); |
@@ -2926,8 +2945,7 @@ void kvm_s390_gisa_clear(struct kvm *kvm) | |||
2926 | 2945 | ||
2927 | if (!gi->origin) | 2946 | if (!gi->origin) |
2928 | return; | 2947 | return; |
2929 | memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); | 2948 | gisa_clear_ipm(gi->origin); |
2930 | gi->origin->next_alert = (u32)(u64)gi->origin; | ||
2931 | VM_EVENT(kvm, 3, "gisa 0x%pK cleared", gi->origin); | 2949 | VM_EVENT(kvm, 3, "gisa 0x%pK cleared", gi->origin); |
2932 | } | 2950 | } |
2933 | 2951 | ||
@@ -2940,7 +2958,8 @@ void kvm_s390_gisa_init(struct kvm *kvm) | |||
2940 | gi->origin = &kvm->arch.sie_page2->gisa; | 2958 | gi->origin = &kvm->arch.sie_page2->gisa; |
2941 | gi->alert.mask = 0; | 2959 | gi->alert.mask = 0; |
2942 | spin_lock_init(&gi->alert.ref_lock); | 2960 | spin_lock_init(&gi->alert.ref_lock); |
2943 | kvm_s390_gisa_clear(kvm); | 2961 | memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); |
2962 | gi->origin->next_alert = (u32)(u64)gi->origin; | ||
2944 | VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); | 2963 | VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); |
2945 | } | 2964 | } |
2946 | 2965 | ||