diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8966fd13e848..ef2f03cf42c0 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -176,6 +176,41 @@ void kvm_free_all_assigned_devices(struct kvm *kvm) | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | static int assigned_device_update_intx(struct kvm *kvm, | ||
180 | struct kvm_assigned_dev_kernel *adev, | ||
181 | struct kvm_assigned_irq *airq) | ||
182 | { | ||
183 | if (adev->irq_requested) { | ||
184 | adev->guest_irq = airq->guest_irq; | ||
185 | adev->ack_notifier.gsi = airq->guest_irq; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | if (irqchip_in_kernel(kvm)) { | ||
190 | if (!capable(CAP_SYS_RAWIO)) | ||
191 | return -EPERM; | ||
192 | |||
193 | if (airq->host_irq) | ||
194 | adev->host_irq = airq->host_irq; | ||
195 | else | ||
196 | adev->host_irq = adev->dev->irq; | ||
197 | adev->guest_irq = airq->guest_irq; | ||
198 | adev->ack_notifier.gsi = airq->guest_irq; | ||
199 | |||
200 | /* Even though this is PCI, we don't want to use shared | ||
201 | * interrupts. Sharing host devices with guest-assigned devices | ||
202 | * on the same interrupt line is not a happy situation: there | ||
203 | * are going to be long delays in accepting, acking, etc. | ||
204 | */ | ||
205 | if (request_irq(adev->host_irq, kvm_assigned_dev_intr, | ||
206 | 0, "kvm_assigned_intx_device", (void *)adev)) | ||
207 | return -EIO; | ||
208 | } | ||
209 | |||
210 | adev->irq_requested = true; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
179 | static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, | 214 | static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, |
180 | struct kvm_assigned_irq | 215 | struct kvm_assigned_irq |
181 | *assigned_irq) | 216 | *assigned_irq) |
@@ -210,39 +245,12 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, | |||
210 | else | 245 | else |
211 | match->irq_source_id = r; | 246 | match->irq_source_id = r; |
212 | } | 247 | } |
213 | } else { | ||
214 | match->guest_irq = assigned_irq->guest_irq; | ||
215 | match->ack_notifier.gsi = assigned_irq->guest_irq; | ||
216 | mutex_unlock(&kvm->lock); | ||
217 | return 0; | ||
218 | } | 248 | } |
219 | 249 | ||
220 | if (irqchip_in_kernel(kvm)) { | 250 | r = assigned_device_update_intx(kvm, match, assigned_irq); |
221 | if (!capable(CAP_SYS_RAWIO)) { | 251 | if (r) |
222 | r = -EPERM; | 252 | goto out_release; |
223 | goto out_release; | ||
224 | } | ||
225 | |||
226 | if (assigned_irq->host_irq) | ||
227 | match->host_irq = assigned_irq->host_irq; | ||
228 | else | ||
229 | match->host_irq = match->dev->irq; | ||
230 | match->guest_irq = assigned_irq->guest_irq; | ||
231 | match->ack_notifier.gsi = assigned_irq->guest_irq; | ||
232 | |||
233 | /* Even though this is PCI, we don't want to use shared | ||
234 | * interrupts. Sharing host devices with guest-assigned devices | ||
235 | * on the same interrupt line is not a happy situation: there | ||
236 | * are going to be long delays in accepting, acking, etc. | ||
237 | */ | ||
238 | if (request_irq(match->host_irq, kvm_assigned_dev_intr, 0, | ||
239 | "kvm_assigned_device", (void *)match)) { | ||
240 | r = -EIO; | ||
241 | goto out_release; | ||
242 | } | ||
243 | } | ||
244 | 253 | ||
245 | match->irq_requested = true; | ||
246 | mutex_unlock(&kvm->lock); | 254 | mutex_unlock(&kvm->lock); |
247 | return r; | 255 | return r; |
248 | out_release: | 256 | out_release: |