summaryrefslogtreecommitdiffstats
path: root/hw/pci
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2016-01-13 14:59:09 +0000
committerTimothy Pearson <tpearson@raptorengineering.com>2019-11-29 19:31:49 -0600
commit1e6f6ac48258d06b1f8820db84727d13a23f2c50 (patch)
treeadbf057298bc055c83ed74ad6bbe19062fefe12f /hw/pci
parent7289a9c819f6993be7c92a3d0de5699d4d874cdb (diff)
downloadhqemu-1e6f6ac48258d06b1f8820db84727d13a23f2c50.zip
hqemu-1e6f6ac48258d06b1f8820db84727d13a23f2c50.tar.gz
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')
-rw-r--r--hw/pci/msi.c9
-rw-r--r--hw/pci/msix.c12
2 files changed, 18 insertions, 3 deletions
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index 8efa23d..85f21b8 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);
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 4fea7ed..eb4ef11 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -19,6 +19,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci.h"
+#include "hw/xen/xen.h"
#include "qemu/range.h"
#define MSIX_CAP_LENGTH 12
@@ -78,8 +79,15 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask)
{
- unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
- return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ unsigned offset = vector * PCI_MSIX_ENTRY_SIZE;
+ uint32_t *data = (uint32_t *)&dev->msix_table[offset + PCI_MSIX_ENTRY_DATA];
+ /* MSIs on Xen can be remapped into pirqs. In those cases, masking
+ * and unmasking go through the PV evtchn path. */
+ if (xen_is_pirq_msi(*data)) {
+ return false;
+ }
+ return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] &
+ PCI_MSIX_ENTRY_CTRL_MASKBIT;
}
bool msix_is_masked(PCIDevice *dev, unsigned int vector)
OpenPOWER on IntegriCloud