qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC][PATCH 11/45] msi: Factor out delivery hook


From: Jan Kiszka
Subject: [Qemu-devel] [RFC][PATCH 11/45] msi: Factor out delivery hook
Date: Mon, 17 Oct 2011 11:27:45 +0200

So far we deliver MSI messages by writing them into the target MMIO
area. This reflects what happens on hardware, but imposes some
limitations on the emulation when introducing KVM in-kernel irqchip
models. For those we will need to track the message origin. Moreover,
different architecture or accelerators may want to overload the delivery
handler.

Therefore, this commit introduces a delivery hook that is called by the
MSI/MSI-X layer when devices send normal messages, but also on spurious
deliveries that ended up on the APIC MMIO handler. Our default delivery
handler for APIC-based PCs then dispatches between real MSIs and other
DMA requests that happened to take the MSI patch.

Signed-off-by: Jan Kiszka <address@hidden>
---
 hw/apic.c |   19 ++++++++++++-------
 hw/apic.h |    1 +
 hw/msi.c  |   10 +++++++++-
 hw/msi.h  |    2 ++
 hw/msix.c |    2 +-
 hw/pc.c   |   11 +++++++++++
 6 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index e43219f..c1d557d 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -19,6 +19,7 @@
 #include "hw.h"
 #include "apic.h"
 #include "ioapic.h"
+#include "msi.h"
 #include "qemu-timer.h"
 #include "host-utils.h"
 #include "sysbus.h"
@@ -803,13 +804,15 @@ static uint32_t apic_mem_readl(void *opaque, 
target_phys_addr_t addr)
     return val;
 }
 
-static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
+void apic_deliver_msi(MSIMessage *msg)
 {
-    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    uint8_t dest =
+        (msg->address & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t vector =
+        (msg->data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+    uint8_t dest_mode = (msg->address >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t trigger_mode = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t delivery = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
     /* XXX: Ignore redirection hint. */
     apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
 }
@@ -825,7 +828,9 @@ static void apic_mem_writel(void *opaque, 
target_phys_addr_t addr, uint32_t val)
          * APIC is connected directly to the CPU.
          * Mapping them on the global bus happens to work because
          * MSI registers are reserved in APIC MMIO and vice versa. */
-        apic_send_msi(addr, val);
+        MSIMessage msg = { .address = addr, .data = val };
+
+        msi_deliver(&msg);
         return;
     }
 
diff --git a/hw/apic.h b/hw/apic.h
index c398c83..fa848fd 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -18,6 +18,7 @@ void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
 uint8_t cpu_get_apic_tpr(DeviceState *s);
 void apic_init_reset(DeviceState *s);
 void apic_sipi(DeviceState *s);
+void apic_deliver_msi(MSIMessage *msg);
 
 /* pc.c */
 int cpu_is_bsp(CPUState *env);
diff --git a/hw/msi.c b/hw/msi.c
index 3c7ebc3..9055155 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -40,6 +40,14 @@
 /* Flag for interrupt controller to declare MSI/MSI-X support */
 bool msi_supported;
 
+static void msi_unsupported(MSIMessage *msg)
+{
+    /* If we get here, the board failed to register a delivery handler. */
+    abort();
+}
+
+void (*msi_deliver)(MSIMessage *msg) = msi_unsupported;
+
 /* If we get rid of cap allocator, we won't need this. */
 static inline uint8_t msi_cap_sizeof(uint16_t flags)
 {
@@ -381,7 +389,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
                    "notify vector 0x%x"
                    " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
                    vector, msg.address, msg.data);
-    stl_le_phys(msg.address, msg.data);
+    msi_deliver(&msg);
 }
 
 /* Normally called by pci_default_write_config(). */
diff --git a/hw/msi.h b/hw/msi.h
index 22e3932..f3152f3 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -46,4 +46,6 @@ static inline bool msi_present(const PCIDevice *dev)
     return dev->cap_present & QEMU_PCI_CAP_MSI;
 }
 
+extern void (*msi_deliver)(MSIMessage *msg);
+
 #endif /* QEMU_MSI_H */
diff --git a/hw/msix.c b/hw/msix.c
index 50fa504..08cc526 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -478,7 +478,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
 
     msix_message_from_vector(dev, vector, &msg);
 
-    stl_le_phys(msg.address, msg.data);
+    msi_deliver(&msg);
 }
 
 void msix_reset(PCIDevice *dev)
diff --git a/hw/pc.c b/hw/pc.c
index 768a20c..7d29a4a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -24,6 +24,7 @@
 #include "hw.h"
 #include "pc.h"
 #include "apic.h"
+#include "msi.h"
 #include "fdc.h"
 #include "ide.h"
 #include "pci.h"
@@ -102,6 +103,15 @@ void isa_irq_handler(void *opaque, int n, int level)
         qemu_set_irq(isa->ioapic[n], level);
 };
 
+static void pc_msi_deliver(MSIMessage *msg)
+{
+    if ((msg->address & 0xfff00000) == MSI_ADDR_BASE) {
+        apic_deliver_msi(msg);
+    } else {
+        stl_phys(msg->address, msg->data);
+    }
+}
+
 static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 {
 }
@@ -889,6 +899,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
            on the global memory bus. */
         /* XXX: what if the base changes? */
         sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        msi_deliver = pc_msi_deliver;
         apic_mapped = 1;
     }
 
-- 
1.7.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]