ioemu: Fix issues when passthrough device is hot-removed from HVM domain.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 16 Jul 2008 10:16:48 +0000 (11:16 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 16 Jul 2008 10:16:48 +0000 (11:16 +0100)
When passthrough device is hot removed from HVM domain by "xm
pci-detach" command, following issues occur. The patch fixes them.

   - Allocated memory is not deallocated.
   - Unbind interrupt with invalid interrupt pin.
   - MSI-X memory mapped register area is not unmapped.

Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp>
tools/ioemu/hw/pass-through.c
tools/ioemu/hw/pt-msi.c
tools/ioemu/hw/pt-msi.h

index 3120c2bc766e98ddfe68220650f734fb142009e7..0e17af915e609862b02a7b7dfa571b58dbc5d260 100644 (file)
@@ -1686,6 +1686,33 @@ out:
     return err;
 }
 
+/* delete all emulate register */
+static void pt_config_delete(struct pt_dev *ptdev)
+{
+    struct pt_reg_grp_tbl *reg_grp_entry = NULL;
+    struct pt_reg_tbl *reg_entry = NULL;
+
+    /* free MSI/MSI-X info table */
+    if (ptdev->msix)
+        pt_msix_delete(ptdev);
+    if (ptdev->msi)
+        free(ptdev->msi);
+
+    /* free all register group entry */
+    while ((reg_grp_entry = ptdev->reg_grp_tbl_head.lh_first) != NULL)
+    {
+        /* free all register entry */
+        while ((reg_entry = reg_grp_entry->reg_tbl_head.lh_first) != NULL)
+        {
+            QEMU_LIST_REMOVE(reg_entry, entries);
+            qemu_free(reg_entry);
+        }
+
+        QEMU_LIST_REMOVE(reg_grp_entry, entries);
+        qemu_free(reg_grp_entry);
+    }
+}
+
 /* initialize common register value */
 static uint32_t pt_common_reg_init(struct pt_dev *ptdev,
         struct pt_reg_info_tbl *reg, uint32_t real_offset)
@@ -2821,7 +2848,8 @@ int unregister_real_device(int php_slot)
 
     /* Unbind interrupt */
     e_device = (assigned_device->dev.devfn >> 3) & 0x1f;
-    e_intx = assigned_device->dev.config[0x3d]-1;
+    /* fix virtual interrupt pin to INTA# */
+    e_intx = 0;
     machine_irq = pci_dev->irq;
 
     if ( machine_irq != 0 ) {
@@ -2834,6 +2862,9 @@ int unregister_real_device(int php_slot)
         }
     }
 
+    /* delete all emulated config registers */
+    pt_config_delete(assigned_device);
+
     /* unregister real device's MMIO/PIO BARs */
     pt_unregister_regions(assigned_device);
     
index f4077b06c80b5d36da9e7a04845836e739d356c3..1936677335c771339381889ec07b0930a2c6d757 100644 (file)
@@ -332,3 +332,16 @@ int pt_msix_init(struct pt_dev *dev, int pos)
            (unsigned long)dev->msix->phys_iomem_base);
     return 0;
 }
+
+void pt_msix_delete(struct pt_dev *dev)
+{
+    /* unmap the MSI-X memory mapped register area */
+    if (dev->msix->phys_iomem_base)
+    {
+        PT_LOG("unmapping physical MSI-X table from %lx\n",
+           (unsigned long)dev->msix->phys_iomem_base);
+        munmap(dev->msix->phys_iomem_base, dev->msix->total_entries * 16);
+    }
+
+    free(dev->msix);
+}
index ab284de4d8f46513975905b5df7243541be67dea..d2f3e1126949e743c6b27d59d70daf279df26558 100644 (file)
@@ -94,4 +94,7 @@ add_msix_mapping(struct pt_dev *dev, int bar_index);
 int
 pt_msix_init(struct pt_dev *dev, int pos);
 
+void
+pt_msix_delete(struct pt_dev *dev);
+
 #endif