From: Keir Fraser Date: Wed, 16 Jul 2008 10:16:48 +0000 (+0100) Subject: ioemu: Fix issues when passthrough device is hot-removed from HVM domain. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14188^2~9 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=004670e3ca847ff84fd8b4a76dae094b8220f8e4;p=xen.git ioemu: Fix issues when passthrough device is hot-removed from HVM domain. 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 --- diff --git a/tools/ioemu/hw/pass-through.c b/tools/ioemu/hw/pass-through.c index 3120c2bc76..0e17af915e 100644 --- a/tools/ioemu/hw/pass-through.c +++ b/tools/ioemu/hw/pass-through.c @@ -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); diff --git a/tools/ioemu/hw/pt-msi.c b/tools/ioemu/hw/pt-msi.c index f4077b06c8..1936677335 100644 --- a/tools/ioemu/hw/pt-msi.c +++ b/tools/ioemu/hw/pt-msi.c @@ -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); +} diff --git a/tools/ioemu/hw/pt-msi.h b/tools/ioemu/hw/pt-msi.h index ab284de4d8..d2f3e11269 100644 --- a/tools/ioemu/hw/pt-msi.h +++ b/tools/ioemu/hw/pt-msi.h @@ -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