diff options
Diffstat (limited to 'arch/s390/kvm/sigp.c')
-rw-r--r-- | arch/s390/kvm/sigp.c | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 0ef81d6776e9..21897b0f8a36 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * sigp.c - handlinge interprocessor communication | 2 | * sigp.c - handlinge interprocessor communication |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2008 | 4 | * Copyright IBM Corp. 2008,2009 |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License (version 2 only) | 7 | * it under the terms of the GNU General Public License (version 2 only) |
@@ -9,6 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 10 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | 11 | * Christian Borntraeger <borntraeger@de.ibm.com> |
12 | * Christian Ehrhardt <ehrhardt@de.ibm.com> | ||
12 | */ | 13 | */ |
13 | 14 | ||
14 | #include <linux/kvm.h> | 15 | #include <linux/kvm.h> |
@@ -107,46 +108,57 @@ unlock: | |||
107 | return rc; | 108 | return rc; |
108 | } | 109 | } |
109 | 110 | ||
110 | static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) | 111 | static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action) |
111 | { | 112 | { |
112 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
113 | struct kvm_s390_local_interrupt *li; | ||
114 | struct kvm_s390_interrupt_info *inti; | 113 | struct kvm_s390_interrupt_info *inti; |
115 | int rc; | ||
116 | |||
117 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
118 | return 3; /* not operational */ | ||
119 | 114 | ||
120 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | 115 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); |
121 | if (!inti) | 116 | if (!inti) |
122 | return -ENOMEM; | 117 | return -ENOMEM; |
123 | |||
124 | inti->type = KVM_S390_SIGP_STOP; | 118 | inti->type = KVM_S390_SIGP_STOP; |
125 | 119 | ||
126 | spin_lock(&fi->lock); | ||
127 | li = fi->local_int[cpu_addr]; | ||
128 | if (li == NULL) { | ||
129 | rc = 3; /* not operational */ | ||
130 | kfree(inti); | ||
131 | goto unlock; | ||
132 | } | ||
133 | spin_lock_bh(&li->lock); | 120 | spin_lock_bh(&li->lock); |
134 | list_add_tail(&inti->list, &li->list); | 121 | list_add_tail(&inti->list, &li->list); |
135 | atomic_set(&li->active, 1); | 122 | atomic_set(&li->active, 1); |
136 | atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); | 123 | atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); |
137 | if (store) | 124 | li->action_bits |= action; |
138 | li->action_bits |= ACTION_STORE_ON_STOP; | ||
139 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
140 | if (waitqueue_active(&li->wq)) | 125 | if (waitqueue_active(&li->wq)) |
141 | wake_up_interruptible(&li->wq); | 126 | wake_up_interruptible(&li->wq); |
142 | spin_unlock_bh(&li->lock); | 127 | spin_unlock_bh(&li->lock); |
143 | rc = 0; /* order accepted */ | 128 | |
129 | return 0; /* order accepted */ | ||
130 | } | ||
131 | |||
132 | static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action) | ||
133 | { | ||
134 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
135 | struct kvm_s390_local_interrupt *li; | ||
136 | int rc; | ||
137 | |||
138 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
139 | return 3; /* not operational */ | ||
140 | |||
141 | spin_lock(&fi->lock); | ||
142 | li = fi->local_int[cpu_addr]; | ||
143 | if (li == NULL) { | ||
144 | rc = 3; /* not operational */ | ||
145 | goto unlock; | ||
146 | } | ||
147 | |||
148 | rc = __inject_sigp_stop(li, action); | ||
149 | |||
144 | unlock: | 150 | unlock: |
145 | spin_unlock(&fi->lock); | 151 | spin_unlock(&fi->lock); |
146 | VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); | 152 | VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); |
147 | return rc; | 153 | return rc; |
148 | } | 154 | } |
149 | 155 | ||
156 | int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action) | ||
157 | { | ||
158 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
159 | return __inject_sigp_stop(li, action); | ||
160 | } | ||
161 | |||
150 | static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) | 162 | static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) |
151 | { | 163 | { |
152 | int rc; | 164 | int rc; |
@@ -262,11 +274,11 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) | |||
262 | break; | 274 | break; |
263 | case SIGP_STOP: | 275 | case SIGP_STOP: |
264 | vcpu->stat.instruction_sigp_stop++; | 276 | vcpu->stat.instruction_sigp_stop++; |
265 | rc = __sigp_stop(vcpu, cpu_addr, 0); | 277 | rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP); |
266 | break; | 278 | break; |
267 | case SIGP_STOP_STORE_STATUS: | 279 | case SIGP_STOP_STORE_STATUS: |
268 | vcpu->stat.instruction_sigp_stop++; | 280 | vcpu->stat.instruction_sigp_stop++; |
269 | rc = __sigp_stop(vcpu, cpu_addr, 1); | 281 | rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP); |
270 | break; | 282 | break; |
271 | case SIGP_SET_ARCH: | 283 | case SIGP_SET_ARCH: |
272 | vcpu->stat.instruction_sigp_arch++; | 284 | vcpu->stat.instruction_sigp_arch++; |