Yuji Shimada
2009-Apr-08 08:32 UTC
[Xen-devel] [PATCH] ioemu: Fix error handling when interrupt hypercall fails.
This patch fixes error handling when interrupt hypercall fails. This patch makes Interrupt Disable bit emulate type. The policy of this patch is the following. INTx interrupt: Initialize(register_real_device) Map INTx(xc_physdev_map_pirq): <fail> - Set real Interrupt Disable bit to ''1''. - Set machine_irq and assigned_device->machine_irq to ''0''. * Don''t bind INTx. Bind INTx(xc_domain_bind_pt_pci_irq): <fail> - Set real Interrupt Disable bit to ''1''. - Unmap INTx. - Decrement mapped_machine_irq[machine_irq] - Set assigned_device->machine_irq to ''0''. Write to Interrupt Disable bit by guest software(pt_cmd_reg_write) Write ''0'' <ptdev->msi_trans_en is false> - Set real bit to ''0'' if assigned_device->machine_irq isn''t ''0''. Write ''1'' <ptdev->msi_trans_en is false> - Set real bit to ''1''. MSI-INTx translation. Initialize(xc_physdev_map_pirq_msi/pt_msi_setup) Bind MSI-INTx(xc_domain_bind_pt_irq) <fail> - Unmap MSI. <success> - Set dev->msi->pirq to ''-1''. <fail> - Do nothing. Write to Interrupt Disable bit by guest software(pt_cmd_reg_write) Write ''0'' <ptdev->msi_trans_en is true> - Set MSI Enable bit to ''1''. Write ''1'' <ptdev->msi_trans_en is true> - Set MSI Enable bit to ''0''. MSI interrupt: Initialize MSI register(pt_msi_setup, pt_msi_update) Bind MSI(xc_domain_update_msi_irq) <fail> - Unmap MSI. - Set dev->msi->pirq to ''-1''. MSI-X interrupt: Initialize MSI-X register(pt_msix_update_one) Bind MSI-X(xc_domain_update_msi_irq) <fail> - Unmap MSI-X. - Set entry->pirq to ''-1''. Thanks, -- Yuji Shimada Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp> diff --git a/hw/pass-through.c b/hw/pass-through.c index 95b4a47..1b9b461 100644 --- a/hw/pass-through.c +++ b/hw/pass-through.c @@ -208,7 +208,7 @@ static struct pt_reg_info_tbl pt_emu_reg_header0_tbl[] = { .size = 2, .init_val = 0x0000, .ro_mask = 0xF880, - .emu_mask = 0x0340, + .emu_mask = 0x0740, .init = pt_common_reg_init, .u.w.read = pt_cmd_reg_read, .u.w.write = pt_cmd_reg_write, @@ -2945,6 +2945,23 @@ static int pt_cmd_reg_write(struct pt_dev *ptdev, /* create value for writing to I/O device register */ throughable_mask = ~emu_mask & valid_mask; + + if (*value & PCI_COMMAND_DISABLE_INTx) + { + if (ptdev->msi_trans_en) + msi_set_enable(ptdev, 0); + else + throughable_mask |= PCI_COMMAND_DISABLE_INTx; + } + else + { + if (ptdev->msi_trans_en) + msi_set_enable(ptdev, 1); + else + if (ptdev->machine_irq) + throughable_mask |= PCI_COMMAND_DISABLE_INTx; + } + *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask); /* mapping BAR */ @@ -3312,8 +3329,12 @@ static int pt_msgctrl_reg_write(struct pt_dev *ptdev, return 0; } } - pt_msi_update(ptdev); - + if (pt_msi_update(ptdev)) + { + *value &= ~PCI_MSI_FLAGS_ENABLE; + PT_LOG("Warning: Can not bind MSI for dev %x\n", pd->devfn); + return 0; + } ptdev->msi->flags &= ~MSI_FLAG_UNINIT; ptdev->msi->flags |= PT_MSI_MAPPED; } @@ -3543,6 +3564,11 @@ static int pt_cmd_reg_restore(struct pt_dev *ptdev, restorable_mask = reg->emu_mask & ~PCI_COMMAND_FAST_BACK; *value = PT_MERGE_VALUE(*value, dev_value, restorable_mask); + if (!ptdev->machine_irq) + *value |= PCI_COMMAND_DISABLE_INTx; + else + *value &= ~PCI_COMMAND_DISABLE_INTx; + return 0; } @@ -3756,8 +3782,14 @@ static struct pt_dev * register_real_device(PCIBus *e_bus, if ( rc ) { - /* TBD: unregister device in case of an error */ PT_LOG("Error: Mapping irq failed, rc = %d\n", rc); + + /* Disable PCI intx assertion (turn on bit10 of devctl) */ + pci_write_word(pci_dev, PCI_COMMAND, + *(uint16_t *)(&assigned_device->dev.config[PCI_COMMAND]) + | PCI_COMMAND_DISABLE_INTx); + machine_irq = 0; + assigned_device->machine_irq = 0; } else { @@ -3781,16 +3813,23 @@ static struct pt_dev * register_real_device(PCIBus *e_bus, e_device, e_intx); if ( rc < 0 ) { - /* TBD: unregister device in case of an error */ PT_LOG("Error: Binding of interrupt failed! rc=%d\n", rc); + + /* Disable PCI intx assertion (turn on bit10 of devctl) */ + pci_write_word(pci_dev, PCI_COMMAND, + *(uint16_t *)(&assigned_device->dev.config[PCI_COMMAND]) + | PCI_COMMAND_DISABLE_INTx); + mapped_machine_irq[machine_irq]--; + + if (mapped_machine_irq[machine_irq] == 0) + { + if (xc_physdev_unmap_pirq(xc_handle, domid, machine_irq)) + PT_LOG("Error: Unmapping of interrupt failed! rc=%d\n", + rc); + } + assigned_device->machine_irq = 0; } } - else { - /* Disable PCI intx assertion (turn on bit10 of devctl) */ - assigned_device->dev.config[0x05] |= 0x04; - pci_write_word(pci_dev, 0x04, - *(uint16_t *)(&assigned_device->dev.config[0x04])); - } out: PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n" diff --git a/hw/pass-through.h b/hw/pass-through.h index 3132387..a503e80 100644 --- a/hw/pass-through.h +++ b/hw/pass-through.h @@ -51,6 +51,11 @@ /* because the current version of libpci (2.2.0) doesn''t define these ID, * so we define Capability ID here. */ +#ifndef PCI_COMMAND_DISABLE_INTx +/* Disable INTx interrupts */ +#define PCI_COMMAND_DISABLE_INTx 0x400 +#endif + #ifndef PCI_CAP_ID_HOTPLUG /* SHPC Capability List Item reg group */ #define PCI_CAP_ID_HOTPLUG 0x0C diff --git a/hw/pt-msi.c b/hw/pt-msi.c index d28038a..4a54ba3 100644 --- a/hw/pt-msi.c +++ b/hw/pt-msi.c @@ -22,7 +22,7 @@ #include "pt-msi.h" #include <sys/mman.h> -static void msi_set_enable(struct pt_dev *dev, int en) +void msi_set_enable(struct pt_dev *dev, int en) { uint16_t val = 0; uint32_t address = 0; @@ -119,6 +119,7 @@ int pt_msi_update(struct pt_dev *d) uint8_t gvec = 0; uint32_t gflags = 0; uint64_t addr = 0; + int ret = 0; /* get vector, address, flags info, etc. */ gvec = d->msi->data & 0xFF; @@ -126,8 +127,20 @@ int pt_msi_update(struct pt_dev *d) gflags = __get_msi_gflags(d->msi->data, addr); PT_LOG("Update msi with pirq %x gvec %x\n", d->msi->pirq, gvec); - return xc_domain_update_msi_irq(xc_handle, domid, gvec, + + ret = xc_domain_update_msi_irq(xc_handle, domid, gvec, d->msi->pirq, gflags, 0); + + if (ret) + { + PT_LOG("Error: Binding of MSI failed.\n"); + + if (xc_physdev_unmap_pirq(xc_handle, domid, d->msi->pirq)) + PT_LOG("Error: Unmapping of MSI failed.\n"); + d->msi->pirq = -1; + return ret; + } + return 0; } void pt_msi_disable(struct pt_dev *dev) @@ -222,6 +235,10 @@ int pt_enable_msi_translate(struct pt_dev* dev) e_device, e_intx, 0)) { PT_LOG("Error: MSI-INTx translation bind failed, fallback\n"); + + if (xc_physdev_unmap_pirq(xc_handle, domid, dev->msi->pirq)) + PT_LOG("Error: Unmapping of MSI failed.\n"); + dev->msi->pirq = -1; return -1; } @@ -302,6 +319,10 @@ static int pt_msix_update_one(struct pt_dev *dev, int entry_nr) if ( ret ) { PT_LOG("Error: Updating msix irq info for entry %d\n", entry_nr); + + if (xc_physdev_unmap_pirq(xc_handle, domid, entry->pirq)) + PT_LOG("Error: Unmapping of MSI-X failed.\n"); + entry->pirq = -1; return ret; } diff --git a/hw/pt-msi.h b/hw/pt-msi.h index 585f607..9664f89 100644 --- a/hw/pt-msi.h +++ b/hw/pt-msi.h @@ -76,6 +76,9 @@ #define GLFAGS_SHIFT_DELIV_MODE 12 #define GLFAGS_SHIFT_TRG_MODE 15 +void +msi_set_enable(struct pt_dev *dev, int en); + int pt_msi_setup(struct pt_dev *dev); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel