aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/kvm.h3
-rw-r--r--virt/kvm/kvm_main.c81
2 files changed, 78 insertions, 6 deletions
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index bb283c388a24..0997e6f5490c 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -392,6 +392,9 @@ struct kvm_trace_rec {
392#endif 392#endif
393#define KVM_CAP_IOMMU 18 393#define KVM_CAP_IOMMU 18
394#define KVM_CAP_NMI 19 394#define KVM_CAP_NMI 19
395#if defined(CONFIG_X86)
396#define KVM_CAP_DEVICE_MSI 20
397#endif
395 398
396/* 399/*
397 * ioctls for VM fds 400 * ioctls for VM fds
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 228c1d18a614..bf36ae9ae7df 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -159,9 +159,15 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
159 * finer-grained lock, update this 159 * finer-grained lock, update this
160 */ 160 */
161 mutex_lock(&assigned_dev->kvm->lock); 161 mutex_lock(&assigned_dev->kvm->lock);
162 kvm_set_irq(assigned_dev->kvm, 162 if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_INTX)
163 assigned_dev->irq_source_id, 163 kvm_set_irq(assigned_dev->kvm,
164 assigned_dev->guest_irq, 1); 164 assigned_dev->irq_source_id,
165 assigned_dev->guest_irq, 1);
166 else if (assigned_dev->irq_requested_type &
167 KVM_ASSIGNED_DEV_GUEST_MSI) {
168 assigned_device_msi_dispatch(assigned_dev);
169 enable_irq(assigned_dev->host_irq);
170 }
165 mutex_unlock(&assigned_dev->kvm->lock); 171 mutex_unlock(&assigned_dev->kvm->lock);
166 kvm_put_kvm(assigned_dev->kvm); 172 kvm_put_kvm(assigned_dev->kvm);
167} 173}
@@ -197,6 +203,8 @@ static void kvm_free_assigned_device(struct kvm *kvm,
197{ 203{
198 if (irqchip_in_kernel(kvm) && assigned_dev->irq_requested_type) 204 if (irqchip_in_kernel(kvm) && assigned_dev->irq_requested_type)
199 free_irq(assigned_dev->host_irq, (void *)assigned_dev); 205 free_irq(assigned_dev->host_irq, (void *)assigned_dev);
206 if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
207 pci_disable_msi(assigned_dev->dev);
200 208
201 kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier); 209 kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier);
202 kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id); 210 kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
@@ -242,6 +250,11 @@ static int assigned_device_update_intx(struct kvm *kvm,
242 return 0; 250 return 0;
243 251
244 if (irqchip_in_kernel(kvm)) { 252 if (irqchip_in_kernel(kvm)) {
253 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) {
254 free_irq(adev->host_irq, (void *)kvm);
255 pci_disable_msi(adev->dev);
256 }
257
245 if (!capable(CAP_SYS_RAWIO)) 258 if (!capable(CAP_SYS_RAWIO))
246 return -EPERM; 259 return -EPERM;
247 260
@@ -265,6 +278,41 @@ static int assigned_device_update_intx(struct kvm *kvm,
265 return 0; 278 return 0;
266} 279}
267 280
281#ifdef CONFIG_X86
282static int assigned_device_update_msi(struct kvm *kvm,
283 struct kvm_assigned_dev_kernel *adev,
284 struct kvm_assigned_irq *airq)
285{
286 int r;
287
288 /* x86 don't care upper address of guest msi message addr */
289 adev->guest_msi.address_lo = airq->guest_msi.addr_lo;
290 adev->guest_msi.data = airq->guest_msi.data;
291 adev->ack_notifier.gsi = -1;
292
293 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
294 return 0;
295
296 if (irqchip_in_kernel(kvm)) {
297 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_INTX)
298 free_irq(adev->host_irq, (void *)adev);
299
300 r = pci_enable_msi(adev->dev);
301 if (r)
302 return r;
303
304 adev->host_irq = adev->dev->irq;
305 if (request_irq(adev->host_irq, kvm_assigned_dev_intr, 0,
306 "kvm_assigned_msi_device", (void *)adev))
307 return -EIO;
308 }
309
310 adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_MSI |
311 KVM_ASSIGNED_DEV_HOST_MSI;
312 return 0;
313}
314#endif
315
268static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, 316static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
269 struct kvm_assigned_irq 317 struct kvm_assigned_irq
270 *assigned_irq) 318 *assigned_irq)
@@ -301,9 +349,30 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
301 } 349 }
302 } 350 }
303 351
304 r = assigned_device_update_intx(kvm, match, assigned_irq); 352 if (assigned_irq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
305 if (r) 353#ifdef CONFIG_X86
306 goto out_release; 354 r = assigned_device_update_msi(kvm, match, assigned_irq);
355 if (r) {
356 printk(KERN_WARNING "kvm: failed to enable "
357 "MSI device!\n");
358 goto out_release;
359 }
360#else
361 r = -ENOTTY;
362#endif
363 } else if (assigned_irq->host_irq == 0 && match->dev->irq == 0) {
364 /* Host device IRQ 0 means don't support INTx */
365 printk(KERN_WARNING "kvm: wait device to enable MSI!\n");
366 r = 0;
367 } else {
368 /* Non-sharing INTx mode */
369 r = assigned_device_update_intx(kvm, match, assigned_irq);
370 if (r) {
371 printk(KERN_WARNING "kvm: failed to enable "
372 "INTx device!\n");
373 goto out_release;
374 }
375 }
307 376
308 mutex_unlock(&kvm->lock); 377 mutex_unlock(&kvm->lock);
309 return r; 378 return r;