* [PATCH 0/10 v4] MSI/MSI-X capability in userspace
@ 2009-03-02 8:29 Sheng Yang
2009-03-02 8:29 ` [PATCH 01/10] kvm: Replace force type convert with container_of() Sheng Yang
` (9 more replies)
0 siblings, 10 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm
OK, just resend the patchset...
Patch 1-4 is a frame work for capability report in QEmu.
Patch 5-7 is to expose MSI capability to the guest.
Patch 8-10 is to expose MSI-X capability to the guest.
I know it's huge, comments are welcome!
Thanks!
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 01/10] kvm: Replace force type convert with container_of()
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 02/10] Make device assignment depend on libpci Sheng Yang
` (8 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/device-assignment.c | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index b7cbcec..c9a3b8e 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -144,7 +144,7 @@ static uint32_t assigned_dev_ioport_readl(void *opaque, uint32_t addr)
static void assigned_dev_iomem_map(PCIDevice *pci_dev, int region_num,
uint32_t e_phys, uint32_t e_size, int type)
{
- AssignedDevice *r_dev = (AssignedDevice *) pci_dev;
+ AssignedDevice *r_dev = container_of(pci_dev, AssignedDevice, dev);
AssignedDevRegion *region = &r_dev->v_addrs[region_num];
uint32_t old_ephys = region->e_physbase;
uint32_t old_esize = region->e_size;
@@ -175,7 +175,7 @@ static void assigned_dev_iomem_map(PCIDevice *pci_dev, int region_num,
static void assigned_dev_ioport_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
- AssignedDevice *r_dev = (AssignedDevice *) pci_dev;
+ AssignedDevice *r_dev = container_of(pci_dev, AssignedDevice, dev);
AssignedDevRegion *region = &r_dev->v_addrs[region_num];
int first_map = (region->e_size == 0);
CPUState *env;
@@ -224,6 +224,7 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
{
int fd;
ssize_t ret;
+ AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
@@ -245,7 +246,7 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
(uint16_t) address, val, len);
- fd = ((AssignedDevice *)d)->real_device.config_fd;
+ fd = pci_dev->real_device.config_fd;
again:
ret = pwrite(fd, &val, len, address);
@@ -266,6 +267,7 @@ static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
uint32_t val = 0;
int fd;
ssize_t ret;
+ AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
if ((address >= 0x10 && address <= 0x24) || address == 0x34 ||
address == 0x3c || address == 0x3d) {
@@ -279,7 +281,7 @@ static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
if (address == 0xFC)
goto do_log;
- fd = ((AssignedDevice *)d)->real_device.config_fd;
+ fd = pci_dev->real_device.config_fd;
again:
ret = pread(fd, &val, len, address);
@@ -610,16 +612,18 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
{
int r;
AssignedDevice *dev;
+ PCIDevice *pci_dev;
uint8_t e_device, e_intx;
struct kvm_assigned_pci_dev assigned_dev_data;
DEBUG("Registering real physical device %s (bus=%x dev=%x func=%x)\n",
adev->name, adev->bus, adev->dev, adev->func);
- dev = (AssignedDevice *)
- pci_register_device(bus, adev->name, sizeof(AssignedDevice),
- -1, assigned_dev_pci_read_config,
- assigned_dev_pci_write_config);
+ pci_dev = pci_register_device(bus, adev->name,
+ sizeof(AssignedDevice), -1, assigned_dev_pci_read_config,
+ assigned_dev_pci_write_config);
+ dev = container_of(pci_dev, AssignedDevice, dev);
+
if (NULL == dev) {
fprintf(stderr, "%s: Error: Couldn't register real device %s\n",
__func__, adev->name);
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 02/10] Make device assignment depend on libpci
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
2009-03-02 8:29 ` [PATCH 01/10] kvm: Replace force type convert with container_of() Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 03/10] Figure out device capability Sheng Yang
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Which is used later for capability detection.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/Makefile.target | 1 +
qemu/configure | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index efcbe0a..5b6fad4 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -638,6 +638,7 @@ OBJS += msmouse.o
ifeq ($(USE_KVM_DEVICE_ASSIGNMENT), 1)
OBJS+= device-assignment.o
+LIBS+=-lpci
endif
ifeq ($(TARGET_BASE_ARCH), i386)
diff --git a/qemu/configure b/qemu/configure
index 902bba3..b6aa7d7 100755
--- a/qemu/configure
+++ b/qemu/configure
@@ -792,6 +792,26 @@ EOF
fi
fi
+# libpci probe for kvm_cap_device_assignment
+if test $kvm_cap_device_assignment = "yes" ; then
+cat > $TMPC << EOF
+#include <pci/pci.h>
+#ifndef PCI_VENDOR_ID
+#error NO LIBPCI
+#endif
+int main(void) { return 0; }
+EOF
+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC 2>/dev/null ; then
+ :
+ else
+ echo
+ echo "Error: libpci check failed"
+ echo "Disable KVM Device Assignment capability."
+ echo
+ kvm_cap_device_assignment="no"
+ fi
+fi
+
##########################################
# zlib check
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 03/10] Figure out device capability
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
2009-03-02 8:29 ` [PATCH 01/10] kvm: Replace force type convert with container_of() Sheng Yang
2009-03-02 8:29 ` [PATCH 02/10] Make device assignment depend on libpci Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-03 12:50 ` Marcelo Tosatti
2009-03-02 8:29 ` [PATCH 04/10] Support for " Sheng Yang
` (6 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang, Allen Kay
Try to figure out device capability in update_dev_cap(). Now we are only care
about MSI capability.
The function pci_find_cap_offset original function wrote by Allen for Xen.
Notice the function need root privilege to work. This depends on libpci to work.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/device-assignment.c | 29 +++++++++++++++++++++++++++++
qemu/hw/device-assignment.h | 1 +
2 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index c9a3b8e..fc05ac7 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -219,6 +219,35 @@ static void assigned_dev_ioport_map(PCIDevice *pci_dev, int region_num,
(r_dev->v_addrs + region_num));
}
+static uint8_t pci_find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
+{
+ int id;
+ int max_cap = 48;
+ int pos = PCI_CAPABILITY_LIST;
+ int status;
+
+ status = pci_read_byte(pci_dev, PCI_STATUS);
+ if ((status & PCI_STATUS_CAP_LIST) == 0)
+ return 0;
+
+ while (max_cap--) {
+ pos = pci_read_byte(pci_dev, pos);
+ if (pos < 0x40)
+ break;
+
+ pos &= ~3;
+ id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);
+
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+
+ pos += PCI_CAP_LIST_NEXT;
+ }
+ return 0;
+}
+
static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
uint32_t val, int len)
{
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index da775d7..0fd78de 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -29,6 +29,7 @@
#define __DEVICE_ASSIGNMENT_H__
#include <sys/mman.h>
+#include <pci/pci.h>
#include "qemu-common.h"
#include "sys-queue.h"
#include "pci.h"
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 04/10] Support for device capability
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (2 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 03/10] Figure out device capability Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-03 12:42 ` Marcelo Tosatti
2009-03-02 8:29 ` [PATCH 05/10] kvm: user interface for MSI type irq routing Sheng Yang
` (5 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
This framework can be easily extended to support device capability, like
MSI/MSI-x.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/pci.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qemu/hw/pci.h | 30 ++++++++++++++++++++
2 files changed, 115 insertions(+), 0 deletions(-)
diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c
index ccb4cfa..2225669 100644
--- a/qemu/hw/pci.c
+++ b/qemu/hw/pci.c
@@ -427,11 +427,65 @@ static void pci_update_mappings(PCIDevice *d)
}
}
+int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len)
+{
+ if (pci_dev->cap.supported && address >= pci_dev->cap.start &&
+ (address + len) < pci_dev->cap.start + pci_dev->cap.length)
+ return 1;
+ return 0;
+}
+
+uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
+ uint32_t address, int len)
+{
+ uint32_t val = 0;
+
+ if (pci_access_cap_config(pci_dev, address, len)) {
+ switch(len) {
+ default:
+ case 4:
+ if (address < pci_dev->cap.start + pci_dev->cap.length - 4) {
+ val = le32_to_cpu(*(uint32_t *)(pci_dev->cap.config
+ + address - pci_dev->cap.start));
+ break;
+ }
+ /* fall through */
+ case 2:
+ if (address < pci_dev->cap.start + pci_dev->cap.length - 2) {
+ val = le16_to_cpu(*(uint16_t *)(pci_dev->cap.config
+ + address - pci_dev->cap.start));
+ break;
+ }
+ /* fall through */
+ case 1:
+ val = pci_dev->cap.config[address - pci_dev->cap.start];
+ break;
+ }
+ }
+ return val;
+}
+
+void pci_default_cap_write_config(PCIDevice *pci_dev,
+ uint32_t address, uint32_t val, int len)
+{
+ if (pci_access_cap_config(pci_dev, address, len)) {
+ int i;
+ for (i = 0; i < len; i++) {
+ pci_dev->cap.config[address + i - pci_dev->cap.start] = val;
+ val >>= 8;
+ }
+ return;
+ }
+}
+
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len)
{
uint32_t val;
+ if (pci_access_cap_config(d, address, len))
+ return d->cap.config_read(d, address, len);
+
switch(len) {
default:
case 4:
@@ -485,6 +539,11 @@ void pci_default_write_config(PCIDevice *d,
return;
}
default_config:
+ if (pci_access_cap_config(d, address, len)) {
+ d->cap.config_write(d, address, val, len);
+ return;
+ }
+
/* not efficient, but simple */
addr = address;
for(i = 0; i < len; i++) {
@@ -903,3 +962,29 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
s->bus = pci_register_secondary_bus(&s->dev, map_irq);
return s->bus;
}
+
+void pci_enable_capability_support(PCIDevice *pci_dev,
+ uint32_t config_start,
+ PCICapConfigReadFunc *config_read,
+ PCICapConfigWriteFunc *config_write,
+ PCICapConfigInitFunc *config_init)
+{
+ if (!pci_dev)
+ return;
+
+ if (config_start >= 0x40 && config_start < 0xff)
+ pci_dev->cap.start = config_start;
+ else
+ pci_dev->cap.start = PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR;
+ if (config_read)
+ pci_dev->cap.config_read = config_read;
+ else
+ pci_dev->cap.config_read = pci_default_cap_read_config;
+ if (config_write)
+ pci_dev->cap.config_write = config_write;
+ else
+ pci_dev->cap.config_write = pci_default_cap_write_config;
+ pci_dev->cap.supported = 1;
+ pci_dev->config[0x34] = pci_dev->cap.start;
+ config_init(pci_dev);
+}
diff --git a/qemu/hw/pci.h b/qemu/hw/pci.h
index 227da6e..7f3548b 100644
--- a/qemu/hw/pci.h
+++ b/qemu/hw/pci.h
@@ -133,6 +133,12 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type);
typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
+typedef void PCICapConfigWriteFunc(PCIDevice *pci_dev,
+ uint32_t address, uint32_t val, int len);
+typedef uint32_t PCICapConfigReadFunc(PCIDevice *pci_dev,
+ uint32_t address, int len);
+typedef void PCICapConfigInitFunc(PCIDevice *pci_dev);
+
#define PCI_ADDRESS_SPACE_MEM 0x00
#define PCI_ADDRESS_SPACE_IO 0x01
#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08
@@ -183,6 +189,10 @@ typedef struct PCIIORegion {
#define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
+#define PCI_CAPABILITY_CONFIG_MAX_LENGTH 0x60
+#define PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR 0x40
+#define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
+
struct PCIDevice {
/* PCI config space */
uint8_t config[256];
@@ -205,6 +215,15 @@ struct PCIDevice {
/* Current IRQ levels. Used internally by the generic PCI code. */
int irq_state[4];
+
+ /* Device capability configuration space */
+ struct {
+ int supported;
+ uint8_t config[PCI_CAPABILITY_CONFIG_MAX_LENGTH];
+ unsigned int start, length;
+ PCICapConfigReadFunc *config_read;
+ PCICapConfigWriteFunc *config_write;
+ } cap;
};
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -217,6 +236,12 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
uint32_t size, int type,
PCIMapIORegionFunc *map_func);
+void pci_enable_capability_support(PCIDevice *pci_dev,
+ uint32_t config_start,
+ PCICapConfigReadFunc *config_read,
+ PCICapConfigWriteFunc *config_write,
+ PCICapConfigInitFunc *config_init);
+
int pci_map_irq(PCIDevice *pci_dev, int pin);
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
@@ -224,6 +249,11 @@ void pci_default_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len);
void pci_device_save(PCIDevice *s, QEMUFile *f);
int pci_device_load(PCIDevice *s, QEMUFile *f);
+uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
+ uint32_t address, int len);
+void pci_default_cap_write_config(PCIDevice *pci_dev,
+ uint32_t address, uint32_t val, int len);
+int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len);
typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 05/10] kvm: user interface for MSI type irq routing
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (3 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 04/10] Support for " Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 06/10] kvm: libkvm: allocate unused gsi for " Sheng Yang
` (4 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
libkvm/libkvm.c | 98 ++++++++++++++++++++++++++++++++++++++++++++-----------
libkvm/libkvm.h | 22 ++++++++++++
2 files changed, 101 insertions(+), 19 deletions(-)
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index 0ac1c28..050eacd 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -1229,11 +1229,12 @@ int kvm_clear_gsi_routes(kvm_context_t kvm)
#endif
}
-int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+int kvm_add_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry)
{
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *z;
- struct kvm_irq_routing_entry *e;
+ struct kvm_irq_routing_entry *new;
int n, size;
if (kvm->irq_routes->nr == kvm->nr_allocated_irq_routes) {
@@ -1241,7 +1242,7 @@ int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
if (n < 64)
n = 64;
size = sizeof(struct kvm_irq_routing);
- size += n * sizeof(*e);
+ size += n * sizeof(*new);
z = realloc(kvm->irq_routes, size);
if (!z)
return -ENOMEM;
@@ -1249,34 +1250,77 @@ int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
kvm->irq_routes = z;
}
n = kvm->irq_routes->nr++;
- e = &kvm->irq_routes->entries[n];
- memset(e, 0, sizeof(*e));
- e->gsi = gsi;
- e->type = KVM_IRQ_ROUTING_IRQCHIP;
- e->flags = 0;
- e->u.irqchip.irqchip = irqchip;
- e->u.irqchip.pin = pin;
+ new = &kvm->irq_routes->entries[n];
+ memset(new, 0, sizeof(*new));
+ new->gsi = entry->gsi;
+ new->type = entry->type;
+ new->flags = entry->flags;
+ new->u = entry->u;
return 0;
#else
return -ENOSYS;
#endif
}
-int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+ struct kvm_irq_routing_entry e;
+
+ e.gsi = gsi;
+ e.type = KVM_IRQ_ROUTING_IRQCHIP;
+ e.flags = 0;
+ e.u.irqchip.irqchip = irqchip;
+ e.u.irqchip.pin = pin;
+ return kvm_add_routing_entry(kvm, &e);
+#else
+ return -ENOSYS;
+#endif
+}
+
+int kvm_del_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry)
{
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing_entry *e, *p;
- int i;
+ int i, found = 0;
for (i = 0; i < kvm->irq_routes->nr; ++i) {
e = &kvm->irq_routes->entries[i];
- if (e->type == KVM_IRQ_ROUTING_IRQCHIP
- && e->gsi == gsi
- && e->u.irqchip.irqchip == irqchip
- && e->u.irqchip.pin == pin) {
- p = &kvm->irq_routes->entries[--kvm->irq_routes->nr];
- *e = *p;
- return 0;
+ if (e->type == entry->type
+ && e->gsi == entry->gsi) {
+ switch (e->type)
+ {
+ case KVM_IRQ_ROUTING_IRQCHIP: {
+ if (e->u.irqchip.irqchip ==
+ entry->u.irqchip.irqchip
+ && e->u.irqchip.pin ==
+ entry->u.irqchip.pin) {
+ p = &kvm->irq_routes->
+ entries[--kvm->irq_routes->nr];
+ *e = *p;
+ found = 1;
+ }
+ break;
+ }
+ case KVM_IRQ_ROUTING_MSI: {
+ if (e->u.msi.address_lo ==
+ entry->u.msi.address_lo
+ && e->u.msi.address_hi ==
+ entry->u.msi.address_hi
+ && e->u.msi.data == entry->u.msi.data) {
+ p = &kvm->irq_routes->
+ entries[--kvm->irq_routes->nr];
+ *e = *p;
+ found = 1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (found)
+ return 0;
}
}
return -ESRCH;
@@ -1285,6 +1329,22 @@ int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
#endif
}
+int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+ struct kvm_irq_routing_entry e;
+
+ e.gsi = gsi;
+ e.type = KVM_IRQ_ROUTING_IRQCHIP;
+ e.flags = 0;
+ e.u.irqchip.irqchip = irqchip;
+ e.u.irqchip.pin = pin;
+ return kvm_del_routing_entry(kvm, &e);
+#else
+ return -ENOSYS;
+#endif
+}
+
int kvm_commit_irq_routes(kvm_context_t kvm)
{
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index 0239cb6..d9b3ce1 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -803,6 +803,28 @@ int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
/*!
+ * \brief Adds a routing entry to the temporary irq routing table
+ *
+ * Adds a filled routing entry to the temporary irq routing table. Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_add_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry);
+
+/*!
+ * \brief Removes a routing from the temporary irq routing table
+ *
+ * Remove a routing to the temporary irq routing table. Nothing is
+ * committed to the running VM.
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_del_routing_entry(kvm_context_t kvm,
+ struct kvm_irq_routing_entry* entry);
+
+/*!
* \brief Commit the temporary irq routing table
*
* Commit the temporary irq routing table to the running VM.
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 06/10] kvm: libkvm: allocate unused gsi for irq routing
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (4 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 05/10] kvm: user interface for MSI type irq routing Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 07/10] kvm: expose MSI capability to guest Sheng Yang
` (3 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Notice here is a simple solution, can be replaced later.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
libkvm/kvm-common.h | 1 +
libkvm/libkvm.c | 10 ++++++++++
libkvm/libkvm.h | 8 ++++++++
3 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/libkvm/kvm-common.h b/libkvm/kvm-common.h
index de1ada2..70a95c2 100644
--- a/libkvm/kvm-common.h
+++ b/libkvm/kvm-common.h
@@ -66,6 +66,7 @@ struct kvm_context {
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
+ int max_used_gsi;
#endif
};
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index 050eacd..58ac995 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -1256,6 +1256,9 @@ int kvm_add_routing_entry(kvm_context_t kvm,
new->type = entry->type;
new->flags = entry->flags;
new->u = entry->u;
+
+ if (entry->gsi > kvm->max_used_gsi)
+ kvm->max_used_gsi = entry->gsi;
return 0;
#else
return -ENOSYS;
@@ -1359,3 +1362,10 @@ int kvm_commit_irq_routes(kvm_context_t kvm)
return -ENOSYS;
#endif
}
+
+int kvm_get_irq_route_gsi(kvm_context_t kvm)
+{
+ return (kvm->max_used_gsi >= KVM_IOAPIC_NUM_PINS) ?
+ (kvm->max_used_gsi + 1) : KVM_IOAPIC_NUM_PINS;
+}
+
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index d9b3ce1..65c4e75 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -833,4 +833,12 @@ int kvm_del_routing_entry(kvm_context_t kvm,
*/
int kvm_commit_irq_routes(kvm_context_t kvm);
+/*!
+ * \brief Get unused GSI number for irq routing table
+ *
+ * Get unused GSI number for irq routing table
+ *
+ * \param kvm Pointer to the current kvm_context
+ */
+int kvm_get_irq_route_gsi(kvm_context_t kvm);
#endif
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 07/10] kvm: expose MSI capability to guest
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (5 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 06/10] kvm: libkvm: allocate unused gsi for " Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 08/10] Add MSI-X related macro to pci.c Sheng Yang
` (2 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/device-assignment.c | 112 ++++++++++++++++++++++++++++++++++++++++---
qemu/hw/device-assignment.h | 7 +++
2 files changed, 112 insertions(+), 7 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index fc05ac7..089c5b7 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -265,7 +265,8 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
}
if ((address >= 0x10 && address <= 0x24) || address == 0x34 ||
- address == 0x3c || address == 0x3d) {
+ address == 0x3c || address == 0x3d ||
+ pci_access_cap_config(d, address, len)) {
/* used for update-mappings (BAR emulation) */
pci_default_write_config(d, address, val, len);
return;
@@ -299,7 +300,8 @@ static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
if ((address >= 0x10 && address <= 0x24) || address == 0x34 ||
- address == 0x3c || address == 0x3d) {
+ address == 0x3c || address == 0x3d ||
+ pci_access_cap_config(d, address, len)) {
val = pci_default_read_config(d, address, len);
DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
(d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
@@ -328,11 +330,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;
}
@@ -637,6 +641,96 @@ void assigned_dev_update_irqs()
}
}
+#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
+{
+ struct kvm_assigned_irq assigned_irq_data;
+ struct kvm_irq_routing_entry gsi_entry;
+ AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+ uint8_t ctrl_byte = pci_dev->cap.config[ctrl_pos];
+
+ 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);
+
+ if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
+ gsi_entry.u.msi.address_lo = *(uint32_t *)(pci_dev->cap.config +
+ PCI_MSI_ADDRESS_LO);
+ gsi_entry.u.msi.address_hi = 0;
+ gsi_entry.u.msi.data = *(uint16_t *)(pci_dev->cap.config +
+ PCI_MSI_DATA_32);
+ gsi_entry.type = KVM_IRQ_ROUTING_MSI;
+ gsi_entry.gsi = kvm_get_irq_route_gsi(kvm_context);
+ kvm_add_routing_entry(kvm_context, &gsi_entry);
+ if (kvm_commit_irq_routes(kvm_context) < 0) {
+ perror("assigned_dev_enable_msi: kvm_commit_irq_routes");
+ assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSI_ENABLED;
+ return;
+ }
+ assigned_irq_data.guest_irq = gsi_entry.gsi;
+ assigned_irq_data.flags = KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
+ } else {
+ assigned_irq_data.guest_irq = assigned_dev->girq;
+ }
+
+ if (kvm_assign_irq(kvm_context, &assigned_irq_data) < 0)
+ perror("assigned_dev_enable_msi");
+ if (assigned_irq_data.flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
+ assigned_dev->cap.state |= ASSIGNED_DEVICE_MSI_ENABLED;
+ pci_dev->cap.config[ctrl_pos] |= PCI_MSI_FLAGS_ENABLE;
+ } else {
+ assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSI_ENABLED;
+ pci_dev->cap.config[ctrl_pos] &= ~PCI_MSI_FLAGS_ENABLE;
+ }
+}
+#endif
+
+void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
+ uint32_t val, int len)
+{
+ AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+ unsigned int pos = pci_dev->cap.start, ctrl_pos;
+
+ pci_default_cap_write_config(pci_dev, address, val, len);
+#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+ if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+ ctrl_pos = pos + PCI_MSI_FLAGS;
+ if (address <= ctrl_pos && address + len > ctrl_pos)
+ assigned_dev_update_msi(pci_dev, ctrl_pos - pci_dev->cap.start);
+ pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ }
+#endif
+ return;
+}
+
+static void assigned_device_pci_cap_init(PCIDevice *pci_dev)
+{
+ AssignedDevice *dev = container_of(pci_dev, AssignedDevice, dev);
+ int next_cap_pt;
+ struct pci_access *pacc;
+ int h_bus, h_dev, h_func;
+
+ pci_dev->cap.length = 0;
+ h_bus = dev->h_busnr;
+ h_dev = dev->h_devfn >> 3;
+ h_func = dev->h_devfn & 0x07;
+ pacc = pci_alloc();
+ pci_init(pacc);
+ dev->pdev = pci_get_dev(pacc, 0, h_bus, h_dev, h_func);
+ pci_cleanup(pacc);
+#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+ /* Expose MSI capability
+ * MSI capability is the 1st capability in cap.config */
+ if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSI)) {
+ dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
+ pci_dev->cap.config[pci_dev->cap.length] = PCI_CAP_ID_MSI;
+ pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ next_cap_pt = 1;
+ }
+#endif
+}
+
struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
{
int r;
@@ -692,6 +786,10 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
if (r < 0)
goto assigned_out;
+ pci_enable_capability_support(pci_dev, 0, NULL,
+ assigned_device_pci_cap_write_config,
+ assigned_device_pci_cap_init);
+
return &dev->dev;
assigned_out:
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index 0fd78de..39d73d9 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -81,6 +81,13 @@ typedef struct {
unsigned char h_busnr;
unsigned int h_devfn;
int bound;
+ struct pci_dev *pdev;
+ struct {
+#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+ uint32_t available;
+#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+ uint32_t state;
+ } cap;
} AssignedDevice;
typedef struct AssignedDevInfo AssignedDevInfo;
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 08/10] Add MSI-X related macro to pci.c
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (6 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 07/10] kvm: expose MSI capability to guest Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 09/10] kvm: add ioctl KVM_SET_MSIX_ENTRY_NR and KVM_SET_MSIX_ENTRY Sheng Yang
2009-03-02 8:29 ` [PATCH 10/10] kvm: enable MSI-X capabilty for assigned device Sheng Yang
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/pci.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/qemu/hw/pci.h b/qemu/hw/pci.h
index 7f3548b..0d988da 100644
--- a/qemu/hw/pci.h
+++ b/qemu/hw/pci.h
@@ -192,6 +192,7 @@ typedef struct PCIIORegion {
#define PCI_CAPABILITY_CONFIG_MAX_LENGTH 0x60
#define PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR 0x40
#define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
+#define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
struct PCIDevice {
/* PCI config space */
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 09/10] kvm: add ioctl KVM_SET_MSIX_ENTRY_NR and KVM_SET_MSIX_ENTRY
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (7 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 08/10] Add MSI-X related macro to pci.c Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 10/10] kvm: enable MSI-X capabilty for assigned device Sheng Yang
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
libkvm/libkvm.c | 25 +++++++++++++++++++++++++
libkvm/libkvm.h | 7 +++++++
2 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index 58ac995..bec1d4a 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -1369,3 +1369,28 @@ int kvm_get_irq_route_gsi(kvm_context_t kvm)
(kvm->max_used_gsi + 1) : KVM_IOAPIC_NUM_PINS;
}
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+ struct kvm_assigned_msix_nr *msix_nr)
+{
+ int ret;
+
+ ret = ioctl(kvm->vm_fd, KVM_ASSIGN_SET_MSIX_NR, msix_nr);
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+ struct kvm_assigned_msix_entry *entry)
+{
+ int ret;
+
+ ret = ioctl(kvm->vm_fd, KVM_ASSIGN_SET_MSIX_ENTRY, entry);
+ if (ret < 0)
+ return -errno;
+
+ return ret;
+}
+#endif
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index 65c4e75..f288dad 100644
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -841,4 +841,11 @@ int kvm_commit_irq_routes(kvm_context_t kvm);
* \param kvm Pointer to the current kvm_context
*/
int kvm_get_irq_route_gsi(kvm_context_t kvm);
+
+#ifdef KVM_CAP_DEVICE_MSIX
+int kvm_assign_set_msix_nr(kvm_context_t kvm,
+ struct kvm_assigned_msix_nr *msix_nr);
+int kvm_assign_set_msix_entry(kvm_context_t kvm,
+ struct kvm_assigned_msix_entry *entry);
+#endif
#endif
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 10/10] kvm: enable MSI-X capabilty for assigned device
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
` (8 preceding siblings ...)
2009-03-02 8:29 ` [PATCH 09/10] kvm: add ioctl KVM_SET_MSIX_ENTRY_NR and KVM_SET_MSIX_ENTRY Sheng Yang
@ 2009-03-02 8:29 ` Sheng Yang
9 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-02 8:29 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti, Anthony Liguori; +Cc: kvm, Sheng Yang
The most important part here, is we emulate a page of MMIO region using a
page of memory. That's because MSI-X table was put in the region and we have to
intercept it.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/device-assignment.c | 286 ++++++++++++++++++++++++++++++++++++++++++-
qemu/hw/device-assignment.h | 6 +
2 files changed, 286 insertions(+), 6 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index 089c5b7..4eb48d0 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -146,6 +146,7 @@ static void assigned_dev_iomem_map(PCIDevice *pci_dev, int region_num,
{
AssignedDevice *r_dev = container_of(pci_dev, AssignedDevice, dev);
AssignedDevRegion *region = &r_dev->v_addrs[region_num];
+ PCIRegion *real_region = &r_dev->real_device.regions[region_num];
uint32_t old_ephys = region->e_physbase;
uint32_t old_esize = region->e_size;
int first_map = (region->e_size == 0);
@@ -161,10 +162,27 @@ static void assigned_dev_iomem_map(PCIDevice *pci_dev, int region_num,
kvm_destroy_phys_mem(kvm_context, old_ephys,
TARGET_PAGE_ALIGN(old_esize));
- if (e_size > 0)
+ if (e_size > 0) {
+ /* deal with MSI-X MMIO page */
+ if (real_region->base_addr <= r_dev->msix_table_addr &&
+ real_region->base_addr + real_region->size >=
+ r_dev->msix_table_addr) {
+ int offset = r_dev->msix_table_addr - real_region->base_addr;
+ ret = munmap(region->u.r_virtbase + offset, TARGET_PAGE_SIZE);
+ if (ret == 0)
+ DEBUG("munmap done, virt_base 0x%p\n",
+ region->u.r_virtbase + offset);
+ else {
+ fprintf(stderr, "%s: fail munmap msix table!\n", __func__);
+ exit(1);
+ }
+ cpu_register_physical_memory(e_phys + offset,
+ TARGET_PAGE_SIZE, r_dev->mmio_index);
+ }
ret = kvm_register_phys_mem(kvm_context, e_phys,
region->u.r_virtbase,
TARGET_PAGE_ALIGN(e_size), 0);
+ }
if (ret != 0) {
fprintf(stderr, "%s: Error: create new mapping failed\n", __func__);
@@ -641,7 +659,9 @@ void assigned_dev_update_irqs()
}
}
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+#ifdef KVM_CAP_IRQ_ROUTING
+
+#ifdef KVM_CAP_DEVICE_MSI
static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
{
struct kvm_assigned_irq assigned_irq_data;
@@ -686,14 +706,146 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
}
#endif
-void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
+#ifdef KVM_CAP_DEVICE_MSIX
+static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
+{
+ AssignedDevice *adev = container_of(pci_dev, AssignedDevice, dev);
+ u16 entries_nr = 0, entries_max_nr;
+ int pos = 0, i, r = 0;
+ u32 msg_addr, msg_upper_addr, msg_data, msg_ctrl;
+ struct kvm_assigned_msix_nr msix_nr;
+ struct kvm_assigned_msix_entry msix_entry;
+ struct kvm_irq_routing_entry routing_entry;
+ void *va = adev->msix_table_page;
+
+ if (adev->cap.available & ASSIGNED_DEVICE_CAP_MSI)
+ pos = PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ entries_max_nr = pci_dev->cap.config[pos + 2];
+ entries_max_nr &= PCI_MSIX_TABSIZE;
+
+ /* Get the usable entry number for allocating */
+ for (i = 0; i < entries_max_nr; i++) {
+ memcpy(&msg_ctrl, va + i * 16 + 12, 4);
+ /* 0x1 is mask bit for per vector */
+ if (msg_ctrl & 0x1)
+ continue;
+ memcpy(&msg_data, va + i * 16 + 8, 4);
+ /* Ignore unused entry even it's unmasked */
+ if (msg_data == 0)
+ continue;
+ entries_nr ++;
+ }
+
+ if (entries_nr == 0) {
+ fprintf(stderr, "MSI-X entry number is zero!\n");
+ return -EINVAL;
+ }
+ msix_nr.assigned_dev_id = calc_assigned_dev_id(adev->h_busnr,
+ (uint8_t)adev->h_devfn);
+ msix_nr.entry_nr = entries_nr;
+ r = kvm_assign_set_msix_nr(kvm_context, &msix_nr);
+ if (r != 0) {
+ fprintf(stderr, "fail to set MSI-X entry number for MSIX! %s\n",
+ strerror(-r));
+ return r;
+ }
+
+ msix_entry.assigned_dev_id = msix_nr.assigned_dev_id;
+ entries_nr = 0;
+ for (i = 0; i < entries_max_nr; i++) {
+ if (entries_nr >= msix_nr.entry_nr)
+ break;
+ memcpy(&msg_ctrl, va + i * 16 + 12, 4);
+ if (msg_ctrl & 0x1)
+ continue;
+ memcpy(&msg_data, va + i * 16 + 8, 4);
+ if (msg_data == 0)
+ continue;
+
+ memcpy(&msg_addr, va + i * 16, 4);
+ memcpy(&msg_upper_addr, va + i * 16 + 4, 4);
+
+ routing_entry.gsi = kvm_get_irq_route_gsi(kvm_context);
+ routing_entry.type = KVM_IRQ_ROUTING_MSI;
+ routing_entry.flags = 0;
+ routing_entry.u.msi.address_lo = msg_addr;
+ routing_entry.u.msi.address_hi = msg_upper_addr;
+ routing_entry.u.msi.data = msg_data;
+ DEBUG("MSI-X data 0x%x, MSI-X addr_lo 0x%x\n!", msg_data, msg_addr);
+ kvm_add_routing_entry(kvm_context, &routing_entry);
+
+ msix_entry.gsi = routing_entry.gsi;
+ msix_entry.entry = i;
+ r = kvm_assign_set_msix_entry(kvm_context, &msix_entry);
+ if (r) {
+ fprintf(stderr, "fail to set MSI-X entry! %s\n", strerror(-r));
+ break;
+ }
+ DEBUG("MSI-X entry gsi 0x%x, entry %d\n!",
+ msix_entry.gsi, msix_entry.entry);
+ entries_nr ++;
+ }
+
+ if (r == 0 && kvm_commit_irq_routes(kvm_context) < 0) {
+ perror("assigned_dev_update_msix_mmio: kvm_commit_irq_routes");
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+static void assigned_dev_update_msix(PCIDevice *pci_dev, unsigned int ctrl_pos)
+{
+ struct kvm_assigned_irq assigned_irq_data;
+ AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+ uint16_t *ctrl_word = (uint16_t *)(pci_dev->cap.config + ctrl_pos);
+
+ 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);
+
+ if (*ctrl_word & PCI_MSIX_ENABLE) {
+ assigned_irq_data.flags = KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX;
+ if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
+ perror("assigned_dev_update_msix_mmio");
+ }
+ }
+ if (*ctrl_word & PCI_MSIX_MASK)
+ assigned_irq_data.flags |= KVM_DEV_IRQ_ASSIGN_MASK_MSIX;
+
+ if ((*ctrl_word & PCI_MSIX_ENABLE) !=
+ (assigned_dev->cap.state & ASSIGNED_DEVICE_MSIX_ENABLED))
+ if (kvm_assign_irq(kvm_context, &assigned_irq_data) < 0)
+ perror("assigned_dev_enable_msix");
+
+ if (assigned_irq_data.flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX) {
+ assigned_dev->cap.state |= ASSIGNED_DEVICE_MSIX_ENABLED;
+ *ctrl_word |= PCI_MSIX_ENABLE;
+ } else {
+ assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSIX_ENABLED;
+ *ctrl_word &= ~PCI_MSIX_ENABLE;
+ }
+ if (assigned_irq_data.flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX) {
+ assigned_dev->cap.state |= ASSIGNED_DEVICE_MSIX_MASKED;
+ *ctrl_word |= PCI_MSIX_MASK;
+ } else {
+ assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSIX_MASKED;
+ *ctrl_word &= ~PCI_MSIX_MASK;
+ }
+}
+#endif
+#endif
+
+static void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
uint32_t val, int len)
{
AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
unsigned int pos = pci_dev->cap.start, ctrl_pos;
pci_default_cap_write_config(pci_dev, address, val, len);
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+#ifdef KVM_CAP_IRQ_ROUTING
+#ifdef KVM_CAP_DEVICE_MSI
if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
ctrl_pos = pos + PCI_MSI_FLAGS;
if (address <= ctrl_pos && address + len > ctrl_pos)
@@ -701,13 +853,25 @@ void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
}
#endif
+#ifdef KVM_CAP_DEVICE_MSIX
+ if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
+ ctrl_pos = pos + 3;
+ if (address <= ctrl_pos && address + len > ctrl_pos) {
+ ctrl_pos--; /* control is word long */
+ assigned_dev_update_msix(pci_dev, ctrl_pos - pci_dev->cap.start);
+ }
+ pos += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+ }
+#endif
+#endif
return;
}
static void assigned_device_pci_cap_init(PCIDevice *pci_dev)
{
AssignedDevice *dev = container_of(pci_dev, AssignedDevice, dev);
- int next_cap_pt;
+ PCIRegion *pci_region = dev->real_device.regions;
+ int next_cap_pt = 0;
struct pci_access *pacc;
int h_bus, h_dev, h_func;
@@ -719,7 +883,8 @@ static void assigned_device_pci_cap_init(PCIDevice *pci_dev)
pci_init(pacc);
dev->pdev = pci_get_dev(pacc, 0, h_bus, h_dev, h_func);
pci_cleanup(pacc);
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_IRQ_ROUTING)
+#ifdef KVM_CAP_IRQ_ROUTING
+#ifdef KVM_CAP_DEVICE_MSI
/* Expose MSI capability
* MSI capability is the 1st capability in cap.config */
if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSI)) {
@@ -729,6 +894,110 @@ static void assigned_device_pci_cap_init(PCIDevice *pci_dev)
next_cap_pt = 1;
}
#endif
+#ifdef KVM_CAP_DEVICE_MSIX
+ /* Expose MSI-X capability */
+ if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX)) {
+ int pos, entry_nr, bar_nr;
+ u32 msix_table_entry;
+ dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
+ pos = pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX);
+ entry_nr = pci_read_word(dev->pdev, pos + 2) & PCI_MSIX_TABSIZE;
+ pci_dev->cap.config[pci_dev->cap.length] = 0x11;
+ pci_dev->cap.config[pci_dev->cap.length + 2] = entry_nr;
+ msix_table_entry = pci_read_long(dev->pdev, pos + PCI_MSIX_TABLE);
+ *(uint32_t *)(pci_dev->cap.config +
+ pci_dev->cap.length + PCI_MSIX_TABLE) = msix_table_entry;
+ *(uint32_t *)(pci_dev->cap.config +
+ pci_dev->cap.length + PCI_MSIX_PBA) =
+ pci_read_long(dev->pdev, pos + PCI_MSIX_PBA);
+ bar_nr = msix_table_entry & PCI_MSIX_BIR;
+ msix_table_entry &= ~PCI_MSIX_BIR;
+ dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
+ if (next_cap_pt != 0) {
+ pci_dev->cap.config[next_cap_pt] =
+ pci_dev->cap.start + pci_dev->cap.length;
+ next_cap_pt += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ } else
+ next_cap_pt = 1;
+ pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+ }
+#endif
+#endif
+}
+
+static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ AssignedDevice *adev = opaque;
+ unsigned int offset = addr & 0xfff;
+ void *page = adev->msix_table_page;
+ uint32_t val = 0;
+
+ DEBUG("read from MSI-X entry table mmio 0x%lx", addr);
+ memcpy(&val, (void *)((char *)page + offset), 4);
+
+ return val;
+}
+
+static uint32_t msix_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ return ((msix_mmio_readl(opaque, addr & ~3)) >>
+ (8 * (addr & 3))) & 0xff;
+}
+
+static uint32_t msix_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ return ((msix_mmio_readl(opaque, addr & ~3)) >>
+ (8 * (addr & 3))) & 0xffff;
+}
+
+static void msix_mmio_writel(void *opaque,
+ target_phys_addr_t addr, uint32_t val)
+{
+ AssignedDevice *adev = opaque;
+ unsigned int offset = addr & 0xfff;
+ void *page = adev->msix_table_page;
+
+ DEBUG("write to MSI-X entry table mmio offset 0x%lx, val 0x%lx\n",
+ addr, val);
+ memcpy((void *)((char *)page + offset), &val, 4);
+}
+
+static void msix_mmio_writew(void *opaque,
+ target_phys_addr_t addr, uint32_t val)
+{
+ msix_mmio_writel(opaque, addr & ~3,
+ (val & 0xffff) << (8*(addr & 3)));
+}
+
+static void msix_mmio_writeb(void *opaque,
+ target_phys_addr_t addr, uint32_t val)
+{
+ msix_mmio_writel(opaque, addr & ~3,
+ (val & 0xff) << (8*(addr & 3)));
+}
+
+static CPUWriteMemoryFunc *msix_mmio_write[] = {
+ msix_mmio_writeb, msix_mmio_writew, msix_mmio_writel
+};
+
+static CPUReadMemoryFunc *msix_mmio_read[] = {
+ msix_mmio_readb, msix_mmio_readw, msix_mmio_readl
+};
+
+static int assigned_dev_register_msix_mmio(AssignedDevice *dev)
+{
+ dev->msix_table_page = mmap(NULL, 0x1000,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
+ memset(dev->msix_table_page, 0, 0x1000);
+ if (dev->msix_table_page == MAP_FAILED) {
+ fprintf(stderr, "fail allocate msix_table_page! %s\n",
+ strerror(errno));
+ return -EFAULT;
+ }
+ dev->mmio_index = cpu_register_io_memory(0,
+ msix_mmio_read, msix_mmio_write, dev);
+ return 0;
}
struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
@@ -790,6 +1059,11 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
assigned_device_pci_cap_write_config,
assigned_device_pci_cap_init);
+ /* intercept MSI-X entry page in the MMIO */
+ if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX)
+ if (assigned_dev_register_msix_mmio(dev))
+ return NULL;
+
return &dev->dev;
assigned_out:
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index 39d73d9..fc1af8f 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -84,10 +84,16 @@ typedef struct {
struct pci_dev *pdev;
struct {
#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
uint32_t available;
#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
+#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
uint32_t state;
} cap;
+ void *msix_table_page;
+ target_phys_addr_t msix_table_addr;
+ int mmio_index;
} AssignedDevice;
typedef struct AssignedDevInfo AssignedDevInfo;
--
1.5.4.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 04/10] Support for device capability
2009-03-02 8:29 ` [PATCH 04/10] Support for " Sheng Yang
@ 2009-03-03 12:42 ` Marcelo Tosatti
2009-03-04 2:56 ` Sheng Yang
0 siblings, 1 reply; 16+ messages in thread
From: Marcelo Tosatti @ 2009-03-03 12:42 UTC (permalink / raw)
To: Sheng Yang; +Cc: Avi Kivity, Anthony Liguori, kvm
Hi Sheng,
On Mon, Mar 02, 2009 at 04:29:27PM +0800, Sheng Yang wrote:
> This framework can be easily extended to support device capability, like
> MSI/MSI-x.
>
> Signed-off-by: Sheng Yang <sheng@linux.intel.com>
> ---
> qemu/hw/pci.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> qemu/hw/pci.h | 30 ++++++++++++++++++++
> 2 files changed, 115 insertions(+), 0 deletions(-)
>
> @@ -205,6 +215,15 @@ struct PCIDevice {
>
> /* Current IRQ levels. Used internally by the generic PCI code. */
> int irq_state[4];
> +
> + /* Device capability configuration space */
> + struct {
> + int supported;
> + uint8_t config[PCI_CAPABILITY_CONFIG_MAX_LENGTH];
> + unsigned int start, length;
> + PCICapConfigReadFunc *config_read;
> + PCICapConfigWriteFunc *config_write;
> + } cap;
> };
Why do you have a copy of the capabilities config space? Why not just
access PCIDevice->config directly?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 03/10] Figure out device capability
2009-03-02 8:29 ` [PATCH 03/10] Figure out device capability Sheng Yang
@ 2009-03-03 12:50 ` Marcelo Tosatti
2009-03-04 3:04 ` Sheng Yang
0 siblings, 1 reply; 16+ messages in thread
From: Marcelo Tosatti @ 2009-03-03 12:50 UTC (permalink / raw)
To: Sheng Yang; +Cc: Avi Kivity, Anthony Liguori, kvm, Allen Kay
On Mon, Mar 02, 2009 at 04:29:26PM +0800, Sheng Yang wrote:
> Try to figure out device capability in update_dev_cap(). Now we are only care
> about MSI capability.
>
> The function pci_find_cap_offset original function wrote by Allen for Xen.
> Notice the function need root privilege to work. This depends on libpci to work.
>
> Signed-off-by: Allen Kay <allen.m.kay@intel.com>
> Signed-off-by: Sheng Yang <sheng@linux.intel.com>
> ---
> qemu/hw/device-assignment.c | 29 +++++++++++++++++++++++++++++
> qemu/hw/device-assignment.h | 1 +
> 2 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
> index c9a3b8e..fc05ac7 100644
> --- a/qemu/hw/device-assignment.c
> +++ b/qemu/hw/device-assignment.c
> @@ -219,6 +219,35 @@ static void assigned_dev_ioport_map(PCIDevice *pci_dev, int region_num,
> (r_dev->v_addrs + region_num));
> }
>
> +static uint8_t pci_find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
> +{
> + int id;
> + int max_cap = 48;
> + int pos = PCI_CAPABILITY_LIST;
Don't you need to handle cardbus capability list offset?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 04/10] Support for device capability
2009-03-03 12:42 ` Marcelo Tosatti
@ 2009-03-04 2:56 ` Sheng Yang
2009-03-04 13:57 ` Marcelo Tosatti
0 siblings, 1 reply; 16+ messages in thread
From: Sheng Yang @ 2009-03-04 2:56 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: Avi Kivity, Anthony Liguori, kvm
On Tuesday 03 March 2009 20:42:07 Marcelo Tosatti wrote:
> Hi Sheng,
>
> On Mon, Mar 02, 2009 at 04:29:27PM +0800, Sheng Yang wrote:
> > This framework can be easily extended to support device capability, like
> > MSI/MSI-x.
> >
> > Signed-off-by: Sheng Yang <sheng@linux.intel.com>
> > ---
> > qemu/hw/pci.c | 85
> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu/hw/pci.h |
> > 30 ++++++++++++++++++++
> > 2 files changed, 115 insertions(+), 0 deletions(-)
> >
> >
> > @@ -205,6 +215,15 @@ struct PCIDevice {
> >
> > /* Current IRQ levels. Used internally by the generic PCI code. */
> > int irq_state[4];
> > +
> > + /* Device capability configuration space */
> > + struct {
> > + int supported;
> > + uint8_t config[PCI_CAPABILITY_CONFIG_MAX_LENGTH];
> > + unsigned int start, length;
> > + PCICapConfigReadFunc *config_read;
> > + PCICapConfigWriteFunc *config_write;
> > + } cap;
> > };
>
> Why do you have a copy of the capabilities config space? Why not just
> access PCIDevice->config directly?
I am not sure upstream would accept which. Separate the logic seems more clear
and easy to accept to me...
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 03/10] Figure out device capability
2009-03-03 12:50 ` Marcelo Tosatti
@ 2009-03-04 3:04 ` Sheng Yang
0 siblings, 0 replies; 16+ messages in thread
From: Sheng Yang @ 2009-03-04 3:04 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: Avi Kivity, Anthony Liguori, kvm, Allen Kay
On Tuesday 03 March 2009 20:50:16 Marcelo Tosatti wrote:
> On Mon, Mar 02, 2009 at 04:29:26PM +0800, Sheng Yang wrote:
> > Try to figure out device capability in update_dev_cap(). Now we are only
> > care about MSI capability.
> >
> > The function pci_find_cap_offset original function wrote by Allen for
> > Xen. Notice the function need root privilege to work. This depends on
> > libpci to work.
> >
> > Signed-off-by: Allen Kay <allen.m.kay@intel.com>
> > Signed-off-by: Sheng Yang <sheng@linux.intel.com>
> > ---
> > qemu/hw/device-assignment.c | 29 +++++++++++++++++++++++++++++
> > qemu/hw/device-assignment.h | 1 +
> > 2 files changed, 30 insertions(+), 0 deletions(-)
> >
> > diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
> > index c9a3b8e..fc05ac7 100644
> > --- a/qemu/hw/device-assignment.c
> > +++ b/qemu/hw/device-assignment.c
> > @@ -219,6 +219,35 @@ static void assigned_dev_ioport_map(PCIDevice
> > *pci_dev, int region_num, (r_dev->v_addrs + region_num));
> > }
> >
> > +static uint8_t pci_find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
> > +{
> > + int id;
> > + int max_cap = 48;
> > + int pos = PCI_CAPABILITY_LIST;
>
> Don't you need to handle cardbus capability list offset?
I think cardbus and PCI bridge are out of our scope for now... Maybe we should
prohibit from assigning them.
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 04/10] Support for device capability
2009-03-04 2:56 ` Sheng Yang
@ 2009-03-04 13:57 ` Marcelo Tosatti
0 siblings, 0 replies; 16+ messages in thread
From: Marcelo Tosatti @ 2009-03-04 13:57 UTC (permalink / raw)
To: Sheng Yang; +Cc: Avi Kivity, Anthony Liguori, kvm
On Wed, Mar 04, 2009 at 10:56:36AM +0800, Sheng Yang wrote:
> On Tuesday 03 March 2009 20:42:07 Marcelo Tosatti wrote:
> > Hi Sheng,
> >
> > On Mon, Mar 02, 2009 at 04:29:27PM +0800, Sheng Yang wrote:
> > > This framework can be easily extended to support device capability, like
> > > MSI/MSI-x.
> > >
> > > Signed-off-by: Sheng Yang <sheng@linux.intel.com>
> > > ---
> > > qemu/hw/pci.c | 85
> > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu/hw/pci.h |
> > > 30 ++++++++++++++++++++
> > > 2 files changed, 115 insertions(+), 0 deletions(-)
> > >
> > >
> > > @@ -205,6 +215,15 @@ struct PCIDevice {
> > >
> > > /* Current IRQ levels. Used internally by the generic PCI code. */
> > > int irq_state[4];
> > > +
> > > + /* Device capability configuration space */
> > > + struct {
> > > + int supported;
> > > + uint8_t config[PCI_CAPABILITY_CONFIG_MAX_LENGTH];
> > > + unsigned int start, length;
> > > + PCICapConfigReadFunc *config_read;
> > > + PCICapConfigWriteFunc *config_write;
> > > + } cap;
> > > };
> >
> > Why do you have a copy of the capabilities config space? Why not just
> > access PCIDevice->config directly?
>
> I am not sure upstream would accept which. Separate the logic seems more clear
> and easy to accept to me...
You have to maintain two copies of the same data. Whats the point? The
logic can be separate with a unified config space, no?
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2009-03-04 13:58 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-02 8:29 [PATCH 0/10 v4] MSI/MSI-X capability in userspace Sheng Yang
2009-03-02 8:29 ` [PATCH 01/10] kvm: Replace force type convert with container_of() Sheng Yang
2009-03-02 8:29 ` [PATCH 02/10] Make device assignment depend on libpci Sheng Yang
2009-03-02 8:29 ` [PATCH 03/10] Figure out device capability Sheng Yang
2009-03-03 12:50 ` Marcelo Tosatti
2009-03-04 3:04 ` Sheng Yang
2009-03-02 8:29 ` [PATCH 04/10] Support for " Sheng Yang
2009-03-03 12:42 ` Marcelo Tosatti
2009-03-04 2:56 ` Sheng Yang
2009-03-04 13:57 ` Marcelo Tosatti
2009-03-02 8:29 ` [PATCH 05/10] kvm: user interface for MSI type irq routing Sheng Yang
2009-03-02 8:29 ` [PATCH 06/10] kvm: libkvm: allocate unused gsi for " Sheng Yang
2009-03-02 8:29 ` [PATCH 07/10] kvm: expose MSI capability to guest Sheng Yang
2009-03-02 8:29 ` [PATCH 08/10] Add MSI-X related macro to pci.c Sheng Yang
2009-03-02 8:29 ` [PATCH 09/10] kvm: add ioctl KVM_SET_MSIX_ENTRY_NR and KVM_SET_MSIX_ENTRY Sheng Yang
2009-03-02 8:29 ` [PATCH 10/10] kvm: enable MSI-X capabilty for assigned device Sheng Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox