diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 98 |
1 files changed, 92 insertions, 6 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8bd44d6985c7..3bed82754a5d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -236,13 +236,33 @@ static void kvm_free_assigned_irq(struct kvm *kvm, | |||
236 | * now, the kvm state is still legal for probably we also have to wait | 236 | * now, the kvm state is still legal for probably we also have to wait |
237 | * interrupt_work done. | 237 | * interrupt_work done. |
238 | */ | 238 | */ |
239 | disable_irq_nosync(assigned_dev->host_irq); | 239 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) { |
240 | cancel_work_sync(&assigned_dev->interrupt_work); | 240 | int i; |
241 | for (i = 0; i < assigned_dev->entries_nr; i++) | ||
242 | disable_irq_nosync(assigned_dev-> | ||
243 | host_msix_entries[i].vector); | ||
244 | |||
245 | cancel_work_sync(&assigned_dev->interrupt_work); | ||
241 | 246 | ||
242 | free_irq(assigned_dev->host_irq, (void *)assigned_dev); | 247 | for (i = 0; i < assigned_dev->entries_nr; i++) |
248 | free_irq(assigned_dev->host_msix_entries[i].vector, | ||
249 | (void *)assigned_dev); | ||
243 | 250 | ||
244 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) | 251 | assigned_dev->entries_nr = 0; |
245 | pci_disable_msi(assigned_dev->dev); | 252 | kfree(assigned_dev->host_msix_entries); |
253 | kfree(assigned_dev->guest_msix_entries); | ||
254 | pci_disable_msix(assigned_dev->dev); | ||
255 | } else { | ||
256 | /* Deal with MSI and INTx */ | ||
257 | disable_irq_nosync(assigned_dev->host_irq); | ||
258 | cancel_work_sync(&assigned_dev->interrupt_work); | ||
259 | |||
260 | free_irq(assigned_dev->host_irq, (void *)assigned_dev); | ||
261 | |||
262 | if (assigned_dev->irq_requested_type & | ||
263 | KVM_ASSIGNED_DEV_HOST_MSI) | ||
264 | pci_disable_msi(assigned_dev->dev); | ||
265 | } | ||
246 | 266 | ||
247 | assigned_dev->irq_requested_type = 0; | 267 | assigned_dev->irq_requested_type = 0; |
248 | } | 268 | } |
@@ -373,6 +393,60 @@ static int assigned_device_update_msi(struct kvm *kvm, | |||
373 | } | 393 | } |
374 | #endif | 394 | #endif |
375 | 395 | ||
396 | #ifdef __KVM_HAVE_MSIX | ||
397 | static int assigned_device_update_msix(struct kvm *kvm, | ||
398 | struct kvm_assigned_dev_kernel *adev, | ||
399 | struct kvm_assigned_irq *airq) | ||
400 | { | ||
401 | /* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */ | ||
402 | int i, r; | ||
403 | |||
404 | adev->ack_notifier.gsi = -1; | ||
405 | |||
406 | if (irqchip_in_kernel(kvm)) { | ||
407 | if (airq->flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX) | ||
408 | return -ENOTTY; | ||
409 | |||
410 | if (!(airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX)) { | ||
411 | /* Guest disable MSI-X */ | ||
412 | kvm_free_assigned_irq(kvm, adev); | ||
413 | if (msi2intx) { | ||
414 | pci_enable_msi(adev->dev); | ||
415 | if (adev->dev->msi_enabled) | ||
416 | return assigned_device_update_msi(kvm, | ||
417 | adev, airq); | ||
418 | } | ||
419 | return assigned_device_update_intx(kvm, adev, airq); | ||
420 | } | ||
421 | |||
422 | /* host_msix_entries and guest_msix_entries should have been | ||
423 | * initialized */ | ||
424 | if (adev->entries_nr == 0) | ||
425 | return -EINVAL; | ||
426 | |||
427 | kvm_free_assigned_irq(kvm, adev); | ||
428 | |||
429 | r = pci_enable_msix(adev->dev, adev->host_msix_entries, | ||
430 | adev->entries_nr); | ||
431 | if (r) | ||
432 | return r; | ||
433 | |||
434 | for (i = 0; i < adev->entries_nr; i++) { | ||
435 | r = request_irq((adev->host_msix_entries + i)->vector, | ||
436 | kvm_assigned_dev_intr, 0, | ||
437 | "kvm_assigned_msix_device", | ||
438 | (void *)adev); | ||
439 | if (r) | ||
440 | return r; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | adev->irq_requested_type |= KVM_ASSIGNED_DEV_MSIX; | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | #endif | ||
449 | |||
376 | static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, | 450 | static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, |
377 | struct kvm_assigned_irq | 451 | struct kvm_assigned_irq |
378 | *assigned_irq) | 452 | *assigned_irq) |
@@ -417,12 +491,24 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, | |||
417 | } | 491 | } |
418 | } | 492 | } |
419 | 493 | ||
420 | if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) && | 494 | if (match->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) |
495 | current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX; | ||
496 | else if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) && | ||
421 | (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI)) | 497 | (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI)) |
422 | current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI; | 498 | current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI; |
423 | 499 | ||
424 | changed_flags = assigned_irq->flags ^ current_flags; | 500 | changed_flags = assigned_irq->flags ^ current_flags; |
425 | 501 | ||
502 | #ifdef __KVM_HAVE_MSIX | ||
503 | if (changed_flags & KVM_DEV_IRQ_ASSIGN_MSIX_ACTION) { | ||
504 | r = assigned_device_update_msix(kvm, match, assigned_irq); | ||
505 | if (r) { | ||
506 | printk(KERN_WARNING "kvm: failed to execute " | ||
507 | "MSI-X action!\n"); | ||
508 | goto out_release; | ||
509 | } | ||
510 | } else | ||
511 | #endif | ||
426 | if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) || | 512 | if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) || |
427 | (msi2intx && match->dev->msi_enabled)) { | 513 | (msi2intx && match->dev->msi_enabled)) { |
428 | #ifdef CONFIG_X86 | 514 | #ifdef CONFIG_X86 |