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