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@xxxxxxxxxxxxxxx>
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@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|