Now QEmu emulate a configuration space of capability region, and provide MSI
capability here.

Signed-off-by: Sheng Yang <[EMAIL PROTECTED]>
---
 qemu/hw/device-assignment.c |   61 +++++++++++++++++++++++++++++++++++++++---
 qemu/hw/device-assignment.h |    3 ++
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index 14b5911..daa0e32 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -254,9 +254,26 @@ static int access_capability_config(AssignedDevice 
*pci_dev,
     return 0;
 }
 
+static void assigned_dev_enable_msi(AssignedDevice *assigned_dev);
+
 static void check_cap_state(AssignedDevice *pci_dev,
                            uint32_t address, uint32_t* val)
 {
+    uint32_t pos = pci_dev->cap.start;
+
+#ifdef KVM_CAP_DEVICE_MSI
+    /* Check if guest want to enable MSI */
+    if (pci_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+       if (address == pos + 2 && (uint8_t)*val == 1) {
+           pci_dev->cap.enabled |= ASSIGNED_DEVICE_MSI_ENABLED;
+           assigned_dev_enable_msi(pci_dev);
+           if (!pci_dev->cap.enabled & ASSIGNED_DEVICE_MSI_ENABLED)
+               *val &= ~1ul;
+           return;
+       }
+       pos += ASSIGNED_DEVICE_CONFIG_MSI_LENGTH;
+    }
+#endif
     return;
 }
 
@@ -401,11 +418,13 @@ do_log:
     DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
           (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
 
-    /* kill the special capabilities */
-    if (address == 4 && len == 4)
-       val &= ~0x100000;
-    else if (address == 6)
-       val &= ~0x10;
+    if (!pci_dev->cap.available) {
+       /* kill the special capabilities */
+       if (address == 4 && len == 4)
+           val &= ~0x100000;
+       else if (address == 6)
+           val &= ~0x10;
+    }
 
     return val;
 }
@@ -583,6 +602,8 @@ void assigned_dev_update_irq(PCIDevice *d)
 
     LIST_FOREACH(adev, &adev_head, next) {
         assigned_dev = adev->assigned_dev;
+       if (assigned_dev->cap.enabled & ASSIGNED_DEVICE_MSI_ENABLED)
+           continue;
         irq = pci_map_irq(&assigned_dev->dev, assigned_dev->intpin);
         irq = piix_get_irq(irq);
 
@@ -613,10 +634,40 @@ void assigned_dev_update_irq(PCIDevice *d)
     }
 }
 
+#ifdef KVM_CAP_DEVICE_MSI
+static void assigned_dev_enable_msi(AssignedDevice *assigned_dev)
+{
+    int r;
+    struct kvm_assigned_irq assigned_irq_data;
+
+    memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
+    assigned_irq_data.assigned_dev_id  =
+           calc_assigned_dev_id(assigned_dev->h_busnr,
+                                (uint8_t)assigned_dev->h_devfn);
+    assigned_irq_data.guest_msi.addr_lo = *(uint32_t *)
+           (assigned_dev->cap.config + 4);
+    assigned_irq_data.guest_msi.data = *(uint16_t *)
+           (assigned_dev->cap.config + 8);
+    assigned_irq_data.flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
+    r = kvm_assign_irq(kvm_context, &assigned_irq_data);
+    if (r < 0) {
+       perror("assigned_dev_enable_msi");
+       assigned_dev->cap.enabled &= ~ASSIGNED_DEVICE_MSI_ENABLED;
+       /* Fail to enable MSI, enable INTx instead */
+       assigned_dev_update_irq((PCIDevice *)assigned_dev);
+    }
+}
+#endif
+
 static void init_dev_cap_config(AssignedDevice *dev)
 {
 #define ASSIGNED_DEVICE_CAPABILITY_START_ADDR 0x40
     dev->cap.start = ASSIGNED_DEVICE_CAPABILITY_START_ADDR;
+#ifdef KVM_CAP_DEVICE_MSI
+    /* Expose MSI capability */
+    dev->cap.config[0] = 0x5;
+    dev->cap.length += ASSIGNED_DEVICE_CONFIG_MSI_LENGTH;
+#endif
 }
 
 struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index 531a489..7e74287 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -86,7 +86,10 @@ typedef struct {
        int available;
 #define ASSIGNED_DEVICE_CAPABILITY_LENGTH 0x60
        uint8_t config[ASSIGNED_DEVICE_CAPABILITY_LENGTH];
+#define ASSIGNED_DEVICE_CONFIG_MSI_LENGTH 0x10
        unsigned int start, length;
+#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+       int enabled;
     } cap;
 } AssignedDevice;
 
-- 
1.5.4.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to