lkml.org 
[lkml]   [2011]   [Nov]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC 5/5] kvm tools: Support new virtio-pci configuration layout
Date
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
tools/kvm/include/kvm/pci.h | 13 ++-
tools/kvm/include/kvm/virtio-pci.h | 4 +
tools/kvm/virtio/pci.c | 248 ++++++++++++++++++++++++++++++++++--
3 files changed, 254 insertions(+), 11 deletions(-)

diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
index f71af0b..4f5a09f 100644
--- a/tools/kvm/include/kvm/pci.h
+++ b/tools/kvm/include/kvm/pci.h
@@ -39,6 +39,16 @@ struct msix_cap {
u32 pba_offset;
};

+struct virtio_cap {
+ u8 cap;
+ u8 next;
+ u8 cap_len;
+ u8 structure_id;
+ u8 bir;
+ u32 size:24;
+ u32 offset;
+};
+
struct pci_device_header {
u16 vendor_id;
u16 device_id;
@@ -63,7 +73,8 @@ struct pci_device_header {
u8 min_gnt;
u8 max_lat;
struct msix_cap msix;
- u8 empty[136]; /* Rest of PCI config space */
+ struct virtio_cap virtio[4];
+ u8 empty[90]; /* Rest of PCI config space */
u32 bar_size[6];
};

diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h
index 73f7486..fc3c03f 100644
--- a/tools/kvm/include/kvm/virtio-pci.h
+++ b/tools/kvm/include/kvm/virtio-pci.h
@@ -19,6 +19,7 @@ struct virtio_pci_ioevent_param {
struct virtio_pci {
struct pci_device_header pci_hdr;
void *dev;
+ struct kvm *kvm;

u16 base_addr;
u8 status;
@@ -36,6 +37,9 @@ struct virtio_pci {
/* virtio queue */
u16 queue_selector;
struct virtio_pci_ioevent_param ioeventfds[VIRTIO_PCI_MAX_VQ];
+
+ u32 virtio_mmio;
+ u16 virtio_pio;
};

int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev,
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
index da38ba5..8606d87 100644
--- a/tools/kvm/virtio/pci.c
+++ b/tools/kvm/virtio/pci.c
@@ -40,7 +40,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_trans *vtra
};

ioevent = (struct ioevent) {
- .io_addr = vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
+ .io_addr = vpci->virtio_pio,
.io_len = sizeof(u16),
.fn = virtio_pci__ioevent_callback,
.fn_ptr = &vpci->ioeventfds[vq],
@@ -59,7 +59,7 @@ static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
return vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_ENABLE;
}

-static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_trans *vtrans, u16 port,
+static bool virtio_pci_legacy__specific_io_in(struct kvm *kvm, struct virtio_trans *vtrans, u16 port,
void *data, int size, int offset)
{
u32 config_offset;
@@ -89,7 +89,8 @@ static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_trans *vtr
return false;
}

-static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool virtio_pci_legacy__io_in(struct ioport *ioport, struct kvm *kvm,
+ u16 port, void *data, int size)
{
unsigned long offset;
bool ret = true;
@@ -124,15 +125,15 @@ static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port,
vpci->isr = VIRTIO_IRQ_LOW;
break;
default:
- ret = virtio_pci__specific_io_in(kvm, vtrans, port, data, size, offset);
+ ret = virtio_pci_legacy__specific_io_in(kvm, vtrans, port, data, size, offset);
break;
};

return ret;
}

-static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_trans *vtrans, u16 port,
- void *data, int size, int offset)
+static bool virtio_pci_legacy__specific_io_out(struct kvm *kvm, struct virtio_trans *vtrans,
+ u16 port, void *data, int size, int offset)
{
struct virtio_pci *vpci = vtrans->virtio;
u32 config_offset, gsi, vec;
@@ -166,7 +167,8 @@ static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_trans *vt
return false;
}

-static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool virtio_pci_legacy__io_out(struct ioport *ioport,
+ struct kvm *kvm, u16 port, void *data, int size)
{
unsigned long offset;
bool ret = true;
@@ -199,7 +201,76 @@ static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port,
vpci->status = ioport__read8(data);
break;
default:
- ret = virtio_pci__specific_io_out(kvm, vtrans, port, data, size, offset);
+ ret = virtio_pci_legacy__specific_io_out(kvm, vtrans, port,
+ data, size, offset);
+ break;
+ };
+
+ return ret;
+}
+
+static struct ioport_operations virtio_pci_legacy__io_ops = {
+ .io_in = virtio_pci_legacy__io_in,
+ .io_out = virtio_pci_legacy__io_out,
+};
+
+static bool virtio_pci__io_out(struct ioport *ioport,
+ struct kvm *kvm, u16 port, void *data, int size)
+{
+ unsigned long offset;
+ bool ret = true;
+ u16 val;
+ struct virtio_pci *vpci;
+ struct virtio_trans *vtrans;
+
+ vtrans = ioport->priv;
+ vpci = vtrans->virtio;
+ offset = port - vpci->virtio_pio;
+
+ /*
+ * 0-1: Notifications
+ * 2: ISR
+ */
+ switch (offset) {
+ case 0:
+ val = ioport__read16(data);
+ vtrans->virtio_ops->notify_vq(kvm, vpci->dev, val);
+ break;
+ case 2:
+ vpci->isr = ioport__read8(data);
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm,
+ u16 port, void *data, int size)
+{
+ unsigned long offset;
+ bool ret = true;
+ struct virtio_pci *vpci;
+
+ vpci = ioport->priv;
+ offset = port - vpci->virtio_pio;
+
+ /*
+ * 0-1: Notifications
+ * 2: ISR
+ */
+ switch (offset) {
+ case 0:
+ /* Shouldn't happen */
+ case 2:
+ ioport__write8(data, vpci->isr);
+ kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
+ vpci->isr = VIRTIO_IRQ_LOW;
+ break;
+ default:
+ ret = false;
break;
};

@@ -231,6 +302,113 @@ static void callback_mmio_table(u64 addr, u8 *data, u32 len, u8 is_write, void *
memcpy(data, table + addr - offset, len);
}

+static void virtio_mmio_dev_specific(u64 addr, u8 *data, u32 len, u8 is_write,
+ struct virtio_trans *vtrans)
+{
+ struct virtio_pci *vpci = vtrans->virtio;
+ u32 i;
+
+ for (i = 0; i < len; i++) {
+ if (is_write)
+ vtrans->virtio_ops->set_config(vpci->kvm, vpci->dev,
+ *(u8 *)data + i, addr + i);
+ else
+ data[i] =
+ vtrans->virtio_ops->get_config(vpci->kvm, vpci->dev, addr + i);
+ }
+}
+
+static void virtio_mmio_in(u64 addr, u8 *data, u32 len, u8 is_write,
+ struct virtio_trans *vtrans)
+{
+ struct virtio_pci *vpci = vtrans->virtio;
+
+ switch (addr) {
+ case VIRTIO_PCI_HOST_FEATURES:
+ *(u32 *)data = vtrans->virtio_ops->get_host_features(vpci->kvm, vpci->dev);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN:
+ *(u32 *)data = vtrans->virtio_ops->get_pfn_vq(vpci->kvm,
+ vpci->dev, vpci->queue_selector);
+ break;
+ case VIRTIO_PCI_QUEUE_NUM:
+ *(u32 *)data = vtrans->virtio_ops->get_size_vq(vpci->kvm,
+ vpci->dev, vpci->queue_selector);
+ break;
+ case VIRTIO_PCI_STATUS:
+ *(u8 *)data = vpci->status;
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ *(u8 *)data = vpci->config_vector;
+ break;
+ case VIRTIO_MSI_QUEUE_VECTOR:
+ *(u8 *)data = vpci->vq_vector[vpci->queue_selector];
+ break;
+ };
+}
+
+static void virtio_mmio_out(u64 addr, u8 *data, u32 len, u8 is_write,
+ struct virtio_trans *vtrans)
+{
+ struct virtio_pci *vpci = vtrans->virtio;
+ u32 val;
+
+ switch (addr) {
+ case VIRTIO_PCI_GUEST_FEATURES:
+ val = *(u32 *)data;
+ vtrans->virtio_ops->set_guest_features(vpci->kvm, vpci, val);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN:
+ val = *(u32 *)data;
+ virtio_pci__init_ioeventfd(vpci->kvm, vtrans, vpci->queue_selector);
+ vtrans->virtio_ops->init_vq(vpci->kvm, vpci->dev, vpci->queue_selector, val);
+ break;
+ case VIRTIO_PCI_QUEUE_SEL:
+ vpci->queue_selector = *(u16 *)data;
+ break;
+ case VIRTIO_PCI_QUEUE_NOTIFY:
+ val = *(u16 *)data;
+ vtrans->virtio_ops->notify_vq(vpci->kvm, vpci->dev, val);
+ break;
+ case VIRTIO_PCI_STATUS:
+ vpci->status = *(u8 *)data;
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR: {
+ u16 vec, gsi;
+
+ vec = *(u16 *)data;
+ gsi = irq__add_msix_route(vpci->kvm, &vpci->msix_table[vec].msg);
+ vpci->config_gsi = gsi;
+ break;
+ }
+ case VIRTIO_MSI_QUEUE_VECTOR: {
+ u16 vec, gsi;
+
+ vec = vpci->vq_vector[vpci->queue_selector] = *(u16 *)data;
+ gsi = irq__add_msix_route(vpci->kvm, &vpci->msix_table[vec].msg);
+ vpci->gsis[vpci->queue_selector] = gsi;
+ break;
+ }
+ };
+}
+
+static void callback_virtio_mmio(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
+{
+ struct virtio_trans *vtrans = ptr;
+ struct virtio_pci *vpci = vtrans->virtio;
+ u32 offset = addr - vpci->virtio_mmio;
+
+ if (offset >= 0x100) {
+ virtio_mmio_dev_specific(offset - 0x100, data, len, is_write, vtrans);
+ return;
+ }
+
+ if (is_write == 0)
+ virtio_mmio_in(offset, data, len, is_write, vtrans);
+ else
+ virtio_mmio_out(offset, data, len, is_write, vtrans);
+}
+
int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_trans *vtrans, u32 vq)
{
struct virtio_pci *vpci = vtrans->virtio;
@@ -282,10 +460,16 @@ int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev,

vpci->dev = dev;
vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
+ vpci->virtio_mmio = pci_get_io_space_block(PCI_IO_SIZE * 2);

- vpci->base_addr = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vtrans);
+ vpci->base_addr = ioport__register(IOPORT_EMPTY,
+ &virtio_pci_legacy__io_ops, IOPORT_SIZE, vtrans);
+ vpci->virtio_pio = ioport__register(IOPORT_EMPTY,
+ &virtio_pci__io_ops, IOPORT_SIZE, vtrans);
kvm__register_mmio(kvm, vpci->msix_io_block, 0x100, callback_mmio_table, vpci);
+ kvm__register_mmio(kvm, vpci->virtio_mmio, 0x200, callback_virtio_mmio, vtrans);

+ vpci->kvm = kvm;
vpci->pci_hdr = (struct pci_device_header) {
.vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
.device_id = device_id,
@@ -296,12 +480,16 @@ int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev,
.subsys_id = subsys_id,
.bar[0] = vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO,
.bar[1] = vpci->msix_io_block | PCI_BASE_ADDRESS_SPACE_MEMORY,
+ .bar[2] = vpci->virtio_mmio | PCI_BASE_ADDRESS_SPACE_MEMORY,
+ .bar_size[2] = PCI_IO_SIZE * 2,
+ .bar[3] = vpci->virtio_pio | PCI_BASE_ADDRESS_SPACE_IO,
+ .bar_size[3] = PCI_IO_SIZE * 2,
.status = PCI_STATUS_CAP_LIST,
.capabilities = (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
};

vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
- vpci->pci_hdr.msix.next = 0;
+ vpci->pci_hdr.msix.next = (void *)&vpci->pci_hdr.virtio[0] - (void *)&vpci->pci_hdr;
/*
* We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
* VIRTIO_PCI_MAX_CONFIG entries for config.
@@ -321,6 +509,46 @@ int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev,
*/
vpci->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */
vpci->pci_hdr.msix.pba_offset = 1 | PCI_IO_SIZE; /* Use BAR 1 with offset */
+
+ vpci->pci_hdr.virtio[0] = (struct virtio_cap) {
+ .cap = PCI_CAP_ID_VNDR,
+ .next = (void *)&vpci->pci_hdr.virtio[1] - (void *)&vpci->pci_hdr,
+ .cap_len = sizeof(struct virtio_cap),
+ .structure_id = VIRTIO_PCI_CAP_COMMON_CFG,
+ .bir = 2,
+ .size = PCI_IO_SIZE,
+ .offset = 0,
+ };
+
+ vpci->pci_hdr.virtio[1] = (struct virtio_cap) {
+ .cap = PCI_CAP_ID_VNDR,
+ .next = (void *)&vpci->pci_hdr.virtio[2] - (void *)&vpci->pci_hdr,
+ .cap_len = sizeof(struct virtio_cap),
+ .structure_id = VIRTIO_PCI_CAP_ISR_CFG,
+ .bir = 3,
+ .size = 1,
+ .offset = 2,
+ };
+
+ vpci->pci_hdr.virtio[2] = (struct virtio_cap) {
+ .cap = PCI_CAP_ID_VNDR,
+ .next = (void *)&vpci->pci_hdr.virtio[3] - (void *)&vpci->pci_hdr,
+ .cap_len = sizeof(struct virtio_cap),
+ .structure_id = VIRTIO_PCI_CAP_NOTIFY_CFG,
+ .bir = 3,
+ .size = 2,
+ .offset = 0,
+ };
+
+ vpci->pci_hdr.virtio[3] = (struct virtio_cap) {
+ .cap = PCI_CAP_ID_VNDR,
+ .next = 0,
+ .cap_len = sizeof(struct virtio_cap),
+ .structure_id = VIRTIO_PCI_CAP_DEVICE_CFG,
+ .bir = 2,
+ .size = PCI_IO_SIZE,
+ .offset = PCI_IO_SIZE,
+ };
vpci->config_vector = 0;

if (irq__register_device(subsys_id, &ndev, &pin, &line) < 0)
--
1.7.8.rc1


\
 
 \ /
  Last update: 2011-11-15 00:49    [W:0.078 / U:12.736 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site