diff mbox

device-assignment: be more selective in interrupt disabling

Message ID 20100617174948.4792.54699.stgit@localhost.localdomain (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Williamson June 17, 2010, 5:51 p.m. UTC
None
diff mbox

Patch

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index ba02157..85cd414 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -1031,13 +1031,20 @@  static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
         calc_assigned_dev_id(assigned_dev->h_segnr, assigned_dev->h_busnr,
                 (uint8_t)assigned_dev->h_devfn);
 
-    if (assigned_dev->irq_requested_type) {
-	    assigned_irq_data.flags = assigned_dev->irq_requested_type;
-	    free_dev_irq_entries(assigned_dev);
-	    r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
-	    /* -ENXIO means no assigned irq */
-	    if (r && r != -ENXIO)
-		    perror("assigned_dev_update_msi: deassign irq");
+    /* Some guests gratuitously disable MSI even if they're not using it,
+     * try to catch this by only deassigning irqs if the guest is using
+     * MSI or intends to start. */
+    if ((assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSI) ||
+        (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
+
+        assigned_irq_data.flags = assigned_dev->irq_requested_type;
+        free_dev_irq_entries(assigned_dev);
+        r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
+        /* -ENXIO means no assigned irq */
+        if (r && r != -ENXIO)
+            perror("assigned_dev_update_msi: deassign irq");
+
+        assigned_irq_data.flags = 0;
     }
 
     if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
@@ -1188,17 +1195,26 @@  static void assigned_dev_update_msix(PCIDevice *pci_dev, unsigned int ctrl_pos)
             calc_assigned_dev_id(assigned_dev->h_segnr, assigned_dev->h_busnr,
                     (uint8_t)assigned_dev->h_devfn);
 
-    if (assigned_dev->irq_requested_type) {
+    /* Some guests gratuitously disable MSIX even if they're not using it,
+     * try to catch this by only deassigning irqs if the guest is using
+     * MSIX or intends to start. */
+    if ((assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSIX) ||
+        (*ctrl_word & PCI_MSIX_ENABLE)) {
+
         assigned_irq_data.flags = assigned_dev->irq_requested_type;
         free_dev_irq_entries(assigned_dev);
         r = kvm_deassign_irq(kvm_context, &assigned_irq_data);
         /* -ENXIO means no assigned irq */
         if (r && r != -ENXIO)
             perror("assigned_dev_update_msix: deassign irq");
+
+        assigned_irq_data.flags = 0;
     }
-    assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSIX | KVM_DEV_IRQ_GUEST_MSIX;
 
     if (*ctrl_word & PCI_MSIX_ENABLE) {
+        assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSIX |
+                                  KVM_DEV_IRQ_GUEST_MSIX;
+
         if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
             perror("assigned_dev_update_msix_mmio");
             return;