* [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM
@ 2008-11-24 11:50 Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 1/5] kvm: Replace force type convert with container_of() Sheng Yang
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm, qemu-devel
Hi Avi & Anthony
Here is the userspace for MSI support of KVM.
Main change from v1:
Make device assignment depends on libpci.
Move capability framework to pci.c (this patch may can be accepted by QEmu).
Thanks!
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 1/5] kvm: Replace force type convert with container_of()
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
@ 2008-11-24 11:50 ` Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 2/5] Make device assignment depend on libpci Sheng Yang
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: Sheng Yang, kvm, qemu-devel
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 9a790c6..786b2f0 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;
@@ -172,7 +172,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;
@@ -221,6 +221,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),
@@ -242,7 +243,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);
@@ -263,6 +264,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) {
@@ -276,7 +278,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);
@@ -489,16 +491,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] 8+ messages in thread
* [Qemu-devel] [PATCH 2/5] Make device assignment depend on libpci
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 1/5] kvm: Replace force type convert with container_of() Sheng Yang
@ 2008-11-24 11:50 ` Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 3/5] Figure out device capability Sheng Yang
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: Sheng Yang, kvm, qemu-devel
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 05ace8e..59653ba 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -735,6 +735,7 @@ OBJS += device-hotplug.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 18ef980..bdde5ed 100755
--- a/qemu/configure
+++ b/qemu/configure
@@ -808,6 +808,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] 8+ messages in thread
* [Qemu-devel] [PATCH 3/5] Figure out device capability
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 1/5] kvm: Replace force type convert with container_of() Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 2/5] Make device assignment depend on libpci Sheng Yang
@ 2008-11-24 11:50 ` Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 4/5] Support for " Sheng Yang
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: Sheng Yang, Allen Kay, kvm, qemu-devel
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 | 50 +++++++++++++++++++++++++++++++++++++++++++
qemu/hw/device-assignment.h | 5 ++++
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index 786b2f0..d3105bc 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -216,6 +216,35 @@ static void assigned_dev_ioport_map(PCIDevice *pci_dev, int region_num,
(r_dev->v_addrs + region_num));
}
+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)
{
@@ -367,6 +396,25 @@ static int assigned_dev_register_regions(PCIRegion *io_regions,
return 0;
}
+static void update_dev_cap(AssignedDevice *pci_dev, uint8_t r_bus,
+ uint8_t r_dev, uint8_t r_func)
+{
+#ifdef KVM_CAP_DEVICE_MSI
+ struct pci_access *pacc;
+ struct pci_dev *pdev;
+ int r;
+
+ pacc = pci_alloc();
+ pci_init(pacc);
+ pdev = pci_get_dev(pacc, 0, r_bus, r_dev, r_func);
+ pci_cleanup(pacc);
+ r = pci_find_cap_offset(pdev, PCI_CAP_ID_MSI);
+ if (r)
+ pci_dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
+ pci_free_dev(pdev);
+#endif
+}
+
static int get_real_device(AssignedDevice *pci_dev, uint8_t r_bus,
uint8_t r_dev, uint8_t r_func)
{
@@ -436,6 +484,8 @@ again:
fclose(f);
dev->region_number = r;
+
+ update_dev_cap(pci_dev, r_bus, r_dev, r_func);
return 0;
}
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index d6caa67..de60988 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"
@@ -80,6 +81,10 @@ typedef struct {
unsigned char h_busnr;
unsigned int h_devfn;
int bound;
+ struct {
+#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+ int available;
+ } cap;
} AssignedDevice;
typedef struct AssignedDevInfo AssignedDevInfo;
--
1.5.4.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 4/5] Support for device capability
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
` (2 preceding siblings ...)
2008-11-24 11:50 ` [Qemu-devel] [PATCH 3/5] Figure out device capability Sheng Yang
@ 2008-11-24 11:50 ` Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 5/5] kvm: expose MSI capability to guest Sheng Yang
2008-11-27 2:12 ` [Qemu-devel] Re: [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: Sheng Yang, kvm, qemu-devel
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 75bc9a9..73f73da 100644
--- a/qemu/hw/pci.c
+++ b/qemu/hw/pci.c
@@ -339,11 +339,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:
@@ -397,6 +451,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++) {
@@ -802,3 +861,29 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
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 e11fbbf..86b4ae5 100644
--- a/qemu/hw/pci.h
+++ b/qemu/hw/pci.h
@@ -19,6 +19,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
@@ -46,6 +52,10 @@ typedef struct PCIIORegion {
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
+#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];
@@ -68,6 +78,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,
@@ -81,6 +100,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);
@@ -88,6 +113,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] 8+ messages in thread
* [Qemu-devel] [PATCH 5/5] kvm: expose MSI capability to guest
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
` (3 preceding siblings ...)
2008-11-24 11:50 ` [Qemu-devel] [PATCH 4/5] Support for " Sheng Yang
@ 2008-11-24 11:50 ` Sheng Yang
2008-11-27 3:51 ` [Qemu-devel] " Sheng Yang
2008-11-27 2:12 ` [Qemu-devel] Re: [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
5 siblings, 1 reply; 8+ messages in thread
From: Sheng Yang @ 2008-11-24 11:50 UTC (permalink / raw)
To: Avi Kivity; +Cc: Sheng Yang, kvm, qemu-devel
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
qemu/hw/device-assignment.c | 90 +++++++++++++++++++++++++++++++++++++++---
qemu/hw/device-assignment.h | 2 +
2 files changed, 85 insertions(+), 7 deletions(-)
diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index d3105bc..67bd6b3 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -262,7 +262,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;
@@ -296,7 +297,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);
@@ -325,11 +327,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;
}
@@ -537,6 +541,73 @@ void assigned_dev_update_irq(PCIDevice *d)
}
}
+#ifdef KVM_CAP_DEVICE_MSI
+static void assigned_dev_enable_msi(PCIDevice *pci_dev)
+{
+ int r;
+ struct kvm_assigned_irq assigned_irq_data;
+ AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+
+ 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 *)
+ (pci_dev->cap.config + 4);
+ assigned_irq_data.guest_msi.data = *(uint16_t *)
+ (pci_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(pci_dev);
+ }
+}
+#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);
+ uint32_t pos = pci_dev->cap.start;
+ uint8_t target_byte, target_position;
+
+ pci_default_cap_write_config(pci_dev, address, val, len);
+#ifdef KVM_CAP_DEVICE_MSI
+ /* Check if guest want to enable MSI */
+ if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+ target_position = pos + 2;
+ if (address <= target_position && address + len > target_position) {
+ target_byte = (uint8_t)(val >> (target_position - address));
+ if (target_byte == 1) {
+ assigned_dev->cap.enabled |= ASSIGNED_DEVICE_MSI_ENABLED;
+ assigned_dev_enable_msi(pci_dev);
+ if (!assigned_dev->cap.enabled & ASSIGNED_DEVICE_MSI_ENABLED)
+ pci_dev->cap.config[target_position - pos] = 0;
+ }
+ }
+ pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ }
+#endif
+ return;
+}
+
+void assigned_device_pci_cap_init(PCIDevice *pci_dev)
+{
+ AssignedDevice *dev = container_of(pci_dev, AssignedDevice, dev);
+
+#ifdef KVM_CAP_DEVICE_MSI
+ /* Expose MSI capability
+ * MSI capability is the 1st capability in cap.config */
+ if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+ pci_dev->cap.config[0] = 0x5;
+ pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
+ }
+#endif
+}
+
struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
{
int r;
@@ -580,6 +651,11 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
dev->h_busnr = adev->bus;
dev->h_devfn = PCI_DEVFN(adev->dev, adev->func);
+ if (dev->cap.available)
+ pci_enable_capability_support(pci_dev, 0, NULL,
+ assigned_device_pci_cap_write_config,
+ assigned_device_pci_cap_init);
+
memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
assigned_dev_data.assigned_dev_id =
calc_assigned_dev_id(dev->h_busnr, (uint32_t)dev->h_devfn);
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index de60988..da8e7e1 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -84,6 +84,8 @@ typedef struct {
struct {
#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
int available;
+#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+ int enabled;
} cap;
} AssignedDevice;
--
1.5.4.5
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] Re: [PATCH 0/5][v2] Userspace for MSI support of KVM
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
` (4 preceding siblings ...)
2008-11-24 11:50 ` [Qemu-devel] [PATCH 5/5] kvm: expose MSI capability to guest Sheng Yang
@ 2008-11-27 2:12 ` Sheng Yang
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-27 2:12 UTC (permalink / raw)
To: kvm; +Cc: Avi Kivity, qemu-devel
On Monday 24 November 2008 19:50:30 Sheng Yang wrote:
> Hi Avi & Anthony
>
> Here is the userspace for MSI support of KVM.
>
> Main change from v1:
> Make device assignment depends on libpci.
> Move capability framework to pci.c (this patch may can be accepted by
> QEmu).
Avi & Anthony
Any comments?
Can QEmu upstream accept "[PATCH 4/5] Support for device capability"?
Thanks!
--
regards
Yang, Sheng
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] Re: [PATCH 5/5] kvm: expose MSI capability to guest
2008-11-24 11:50 ` [Qemu-devel] [PATCH 5/5] kvm: expose MSI capability to guest Sheng Yang
@ 2008-11-27 3:51 ` Sheng Yang
0 siblings, 0 replies; 8+ messages in thread
From: Sheng Yang @ 2008-11-27 3:51 UTC (permalink / raw)
To: kvm; +Cc: Avi Kivity, qemu-devel
On Monday 24 November 2008 19:50:35 Sheng Yang wrote:
> Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Oh, hold this one for a moment...
I don't want to deal with compatible problem of deliver msi_msg, so I would
send out gsi->msi mapping patch and update the userspace patch.
--
regards
Yang, Sheng
> ---
> qemu/hw/device-assignment.c | 90
> +++++++++++++++++++++++++++++++++++++++--- qemu/hw/device-assignment.h |
> 2 +
> 2 files changed, 85 insertions(+), 7 deletions(-)
>
> diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
> index d3105bc..67bd6b3 100644
> --- a/qemu/hw/device-assignment.c
> +++ b/qemu/hw/device-assignment.c
> @@ -262,7 +262,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;
> @@ -296,7 +297,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); @@ -325,11 +327,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;
> }
> @@ -537,6 +541,73 @@ void assigned_dev_update_irq(PCIDevice *d)
> }
> }
>
> +#ifdef KVM_CAP_DEVICE_MSI
> +static void assigned_dev_enable_msi(PCIDevice *pci_dev)
> +{
> + int r;
> + struct kvm_assigned_irq assigned_irq_data;
> + AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice,
> dev); +
> + 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 *)
> + (pci_dev->cap.config + 4);
> + assigned_irq_data.guest_msi.data = *(uint16_t *)
> + (pci_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(pci_dev);
> + }
> +}
> +#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); + uint32_t pos = pci_dev->cap.start;
> + uint8_t target_byte, target_position;
> +
> + pci_default_cap_write_config(pci_dev, address, val, len);
> +#ifdef KVM_CAP_DEVICE_MSI
> + /* Check if guest want to enable MSI */
> + if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
> + target_position = pos + 2;
> + if (address <= target_position && address + len > target_position)
> { + target_byte = (uint8_t)(val >> (target_position - address));
> + if (target_byte == 1) {
> + assigned_dev->cap.enabled |= ASSIGNED_DEVICE_MSI_ENABLED;
> + assigned_dev_enable_msi(pci_dev);
> + if (!assigned_dev->cap.enabled &
> ASSIGNED_DEVICE_MSI_ENABLED) +
> pci_dev->cap.config[target_position - pos] = 0; + }
> + }
> + pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
> + }
> +#endif
> + return;
> +}
> +
> +void assigned_device_pci_cap_init(PCIDevice *pci_dev)
> +{
> + AssignedDevice *dev = container_of(pci_dev, AssignedDevice, dev);
> +
> +#ifdef KVM_CAP_DEVICE_MSI
> + /* Expose MSI capability
> + * MSI capability is the 1st capability in cap.config */
> + if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
> + pci_dev->cap.config[0] = 0x5;
> + pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
> + }
> +#endif
> +}
> +
> struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
> {
> int r;
> @@ -580,6 +651,11 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo
> *adev, PCIBus *bus) dev->h_busnr = adev->bus;
> dev->h_devfn = PCI_DEVFN(adev->dev, adev->func);
>
> + if (dev->cap.available)
> + pci_enable_capability_support(pci_dev, 0, NULL,
> +
> assigned_device_pci_cap_write_config, +
> assigned_device_pci_cap_init); +
> memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
> assigned_dev_data.assigned_dev_id =
> calc_assigned_dev_id(dev->h_busnr, (uint32_t)dev->h_devfn);
> diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
> index de60988..da8e7e1 100644
> --- a/qemu/hw/device-assignment.h
> +++ b/qemu/hw/device-assignment.h
> @@ -84,6 +84,8 @@ typedef struct {
> struct {
> #define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
> int available;
> +#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
> + int enabled;
> } cap;
> } AssignedDevice;
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-11-27 3:51 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-24 11:50 [Qemu-devel] [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 1/5] kvm: Replace force type convert with container_of() Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 2/5] Make device assignment depend on libpci Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 3/5] Figure out device capability Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 4/5] Support for " Sheng Yang
2008-11-24 11:50 ` [Qemu-devel] [PATCH 5/5] kvm: expose MSI capability to guest Sheng Yang
2008-11-27 3:51 ` [Qemu-devel] " Sheng Yang
2008-11-27 2:12 ` [Qemu-devel] Re: [PATCH 0/5][v2] Userspace for MSI support of KVM Sheng Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).