diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2016-01-13 14:59:09 +0000 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-02-06 20:44:10 +0200 |
commit | 428c3ece97179557f2753071fb0ca97a03437267 (patch) | |
tree | 6aa26f91ad4b268c0d51e8b3819bb4381a446fda /hw/pci/msi.c | |
parent | d66b969b0d9c8eefdcbff4b48535b0fe1501d139 (diff) |
fix MSI injection on Xen
On Xen MSIs can be remapped into pirqs, which are a type of event
channels. It's mostly for the benefit of PCI passthrough devices, to
avoid the overhead of interacting with the emulated lapic.
However remapping interrupts and MSIs is also supported for emulated
devices, such as the e1000 and virtio-net.
When an interrupt or an MSI is remapped into a pirq, masking and
unmasking is done by masking and unmasking the event channel. The
masking bit on the PCI config space or MSI-X table should be ignored,
but it isn't at the moment.
As a consequence emulated devices which use MSI or MSI-X, such as
virtio-net, don't work properly (the guest doesn't receive any
notifications). The mechanism was working properly when xen_apic was
introduced, but I haven't narrowed down which commit in particular is
causing the regression.
Fix the issue by ignoring the masking bit for MSI and MSI-X which have
been remapped into pirqs.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci/msi.c')
-rw-r--r-- | hw/pci/msi.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/hw/pci/msi.c b/hw/pci/msi.c index 8efa23d376..85f21b8c4b 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/pci/msi.h" +#include "hw/xen/xen.h" #include "qemu/range.h" /* PCI_MSI_ADDRESS_LO */ @@ -254,13 +255,19 @@ void msi_reset(PCIDevice *dev) static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) { uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - uint32_t mask; + uint32_t mask, data; + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; assert(vector < PCI_MSI_VECTORS_MAX); if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { return false; } + data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); + if (xen_is_pirq_msi(data)) { + return false; + } + mask = pci_get_long(dev->config + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); return mask & (1U << vector); |