aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2016-02-01 11:18:10 +0530
committerAlexey Kardashevskiy <aik@ozlabs.ru>2016-02-08 16:40:39 +1100
commitf83299621cde03cd406cbb665fc5eb1f348afc9b (patch)
tree0fa0c612e57f74bbbe15490a560888dc0563ccb0 /lib
parent69a2f9ae1a191743acb3f68e6e0514eb65beb576 (diff)
downloadSLOF-f83299621cde03cd406cbb665fc5eb1f348afc9b.zip
SLOF-f83299621cde03cd406cbb665fc5eb1f348afc9b.tar.gz
SLOF-f83299621cde03cd406cbb665fc5eb1f348afc9b.tar.bz2
virtio: add and enable 1.0 device setup
Introduce parsing routines for virtio capabilities. This would also determine whether we need to function in legacy mode or virtio 1.0. Update routine to start using the base address from the updated legacy structure. With the removal for base address setting in the Forth code and most of the device setup happening in C code, code in virtio.fs is redundant. Remove virtio.fs and move the allocation of the virtio_device structure to the C code instead of the Forth code in individual files. Also, drop the packed attribute for the virtio_{device,cap} structure. The structure is not shared anymore. Drivers need to negotiate the 1.0 feature capability before starting to use 1.0. Disable it in all the drivers until 1.0 is enabled. Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Diffstat (limited to 'lib')
-rw-r--r--lib/libvirtio/virtio-9p.c3
-rw-r--r--lib/libvirtio/virtio-blk.c3
-rw-r--r--lib/libvirtio/virtio-net.c3
-rw-r--r--lib/libvirtio/virtio-scsi.c3
-rw-r--r--lib/libvirtio/virtio.c143
-rw-r--r--lib/libvirtio/virtio.code5
-rw-r--r--lib/libvirtio/virtio.h7
-rw-r--r--lib/libvirtio/virtio.in2
8 files changed, 151 insertions, 18 deletions
diff --git a/lib/libvirtio/virtio-9p.c b/lib/libvirtio/virtio-9p.c
index f975af0..fc5db91 100644
--- a/lib/libvirtio/virtio-9p.c
+++ b/lib/libvirtio/virtio-9p.c
@@ -176,6 +176,9 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
dprintf("%s : device at %p\n", __func__, dev->base);
dprintf("%s : type is %04x\n", __func__, dev->type);
+ /* Keep it disabled until the driver is 1.0 capable */
+ dev->is_modern = false;
+
virtio_reset_device(dev);
/* Acknowledge device. */
diff --git a/lib/libvirtio/virtio-blk.c b/lib/libvirtio/virtio-blk.c
index 7ced1c7..1778e8f 100644
--- a/lib/libvirtio/virtio-blk.c
+++ b/lib/libvirtio/virtio-blk.c
@@ -33,6 +33,9 @@ virtioblk_init(struct virtio_device *dev)
int features;
int status = VIRTIO_STAT_ACKNOWLEDGE;
+ /* Keep it disabled until the driver is 1.0 capable */
+ dev->is_modern = false;
+
/* Reset device */
virtio_reset_device(dev);
diff --git a/lib/libvirtio/virtio-net.c b/lib/libvirtio/virtio-net.c
index 6eeb076..cce0bd7 100644
--- a/lib/libvirtio/virtio-net.c
+++ b/lib/libvirtio/virtio-net.c
@@ -68,7 +68,8 @@ static int virtionet_init_pci(struct virtio_device *dev)
if (!dev)
return -1;
- virtiodev.base = dev->base;
+ /* Keep it disabled until the driver is 1.0 capable */
+ virtiodev.is_modern = false;
/* Reset device */
virtio_reset_device(&virtiodev);
diff --git a/lib/libvirtio/virtio-scsi.c b/lib/libvirtio/virtio-scsi.c
index 095a436..fd65a03 100644
--- a/lib/libvirtio/virtio-scsi.c
+++ b/lib/libvirtio/virtio-scsi.c
@@ -98,6 +98,9 @@ int virtioscsi_init(struct virtio_device *dev)
int qsize = 0;
int status = VIRTIO_STAT_ACKNOWLEDGE;
+ /* Keep it disabled until the driver is 1.0 capable */
+ dev->is_modern = false;
+
/* Reset device */
// XXX That will clear the virtq base. We need to move
// initializing it to here anyway
diff --git a/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c
index 276d69f..f189941 100644
--- a/lib/libvirtio/virtio.c
+++ b/lib/libvirtio/virtio.c
@@ -14,6 +14,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <stddef.h>
#include <cpu.h>
#include <cache.h>
#include <byteorder.h>
@@ -31,6 +32,36 @@
#define VIRTIOHDR_ISR_STATUS 19
#define VIRTIOHDR_DEVICE_CONFIG 20
+/* PCI defines */
+#define PCI_BASE_ADDR_SPACE_IO 0x01
+#define PCI_BASE_ADDR_SPACE_64BIT 0x04
+#define PCI_BASE_ADDR_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDR_IO_MASK (~0x03UL)
+
+#define PCI_BASE_ADDR_REG_0 0x10
+#define PCI_CONFIG_CAP_REG 0x34
+
+#define PCI_CAP_ID_VNDR 0x9
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+#define VIRTIO_PCI_CAP_VNDR 0 /* Generic PCI field: PCI_CAP_ID_VNDR */
+#define VIRTIO_PCI_CAP_NEXT 1 /* Generic PCI field: next ptr. */
+#define VIRTIO_PCI_CAP_LEN 2 /* Generic PCI field: capability length */
+#define VIRTIO_PCI_CAP_CFG_TYPE 3 /* Identifies the structure. */
+#define VIRTIO_PCI_CAP_BAR 4 /* Where to find it. */
+#define VIRTIO_PCI_CAP_OFFSET 8 /* Offset within bar. */
+#define VIRTIO_PCI_CAP_LENGTH 12 /* Length of the structure, in bytes. */
+
struct virtio_dev_common {
le32 dev_features_sel;
le32 dev_features;
@@ -76,6 +107,92 @@ static uint64_t virtio_pci_read64(void *addr)
return (hi << 32) | lo;
}
+static void virtio_cap_set_base_addr(struct virtio_cap *cap, uint32_t offset)
+{
+ uint64_t addr;
+
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar);
+ if (addr & PCI_BASE_ADDR_SPACE_IO) {
+ addr = addr & PCI_BASE_ADDR_IO_MASK;
+ cap->is_io = 1;
+ } else {
+ if (addr & PCI_BASE_ADDR_SPACE_64BIT)
+ addr |= SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32;
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ cap->is_io = 0;
+ }
+ addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+ cap->addr = (void *)addr + offset;
+}
+
+static void virtio_process_cap(struct virtio_device *dev, uint8_t cap_ptr)
+{
+ struct virtio_cap *cap;
+ uint8_t cfg_type, bar;
+ uint32_t offset;
+
+ cfg_type = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_CFG_TYPE);
+ bar = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_BAR);
+ offset = SLOF_pci_config_read32(cap_ptr + VIRTIO_PCI_CAP_OFFSET);
+
+ switch(cfg_type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ cap = &dev->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ cap = &dev->notify;
+ dev->notify_off_mul = SLOF_pci_config_read32(cap_ptr + sizeof(struct virtio_cap));
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ cap = &dev->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ cap = &dev->device;
+ break;
+ default:
+ return;
+ }
+
+ cap->bar = bar;
+ virtio_cap_set_base_addr(cap, offset);
+ cap->cap_id = cfg_type;
+}
+
+/**
+ * Reads the virtio device capabilities, gets called from SLOF routines The
+ * function determines legacy or modern device and sets up driver registers
+ */
+struct virtio_device *virtio_setup_vd(void)
+{
+ uint8_t cap_ptr, cap_vndr;
+ struct virtio_device *dev;
+
+ dev = SLOF_alloc_mem(sizeof(struct virtio_device));
+ if (!dev) {
+ printf("Failed to allocate memory");
+ return NULL;
+ }
+
+ cap_ptr = SLOF_pci_config_read8(PCI_CONFIG_CAP_REG);
+ while (cap_ptr != 0) {
+ cap_vndr = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_VNDR);
+ if (cap_vndr == PCI_CAP_ID_VNDR)
+ virtio_process_cap(dev, cap_ptr);
+ cap_ptr = SLOF_pci_config_read8(cap_ptr+VIRTIO_PCI_CAP_NEXT);
+ }
+
+ if (dev->common.cap_id && dev->notify.cap_id &&
+ dev->isr.cap_id && dev->device.cap_id) {
+ dev->is_modern = 1;
+ } else {
+ dev->is_modern = 0;
+ dev->legacy.cap_id = 0;
+ dev->legacy.bar = 0;
+ virtio_cap_set_base_addr(&dev->legacy, 0);
+ }
+ return dev;
+}
+
/**
* Calculate ring size according to queue size number
*/
@@ -106,10 +223,10 @@ unsigned int virtio_get_qsize(struct virtio_device *dev, int queue)
size = le16_to_cpu(ci_read_16(addr));
}
else {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
- size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
+ size = le16_to_cpu(ci_read_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SIZE));
}
return size;
@@ -134,11 +251,11 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
eieio();
desc = (void *)(virtio_pci_read64(q_desc));
} else {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
desc = (void*)(4096L *
- le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
+ le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS)));
}
return desc;
@@ -236,7 +353,7 @@ void virtio_queue_notify(struct virtio_device *dev, int queue)
addr = dev->notify.addr + q_notify_off * dev->notify_off_mul;
ci_write_16(addr, cpu_to_le16(queue));
} else {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
}
}
@@ -260,10 +377,10 @@ void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr)
} else {
uint32_t val = qaddr;
val = val >> 12;
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
- ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS,
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS,
cpu_to_le32(val));
}
}
@@ -293,7 +410,7 @@ void virtio_set_status(struct virtio_device *dev, int status)
ci_write_8(dev->common.addr +
offset_of(struct virtio_dev_common, dev_status), status);
} else {
- ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
+ ci_write_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS, status);
}
}
@@ -306,7 +423,7 @@ void virtio_get_status(struct virtio_device *dev, int *status)
*status = ci_read_8(dev->common.addr +
offset_of(struct virtio_dev_common, dev_status));
} else {
- *status = ci_read_8(dev->base+VIRTIOHDR_DEVICE_STATUS);
+ *status = ci_read_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS);
}
}
@@ -331,7 +448,7 @@ void virtio_set_guest_features(struct virtio_device *dev, uint64_t features)
ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features),
cpu_to_le32(f0));
} else {
- ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, cpu_to_le32(features));
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_GUEST_FEATURES, cpu_to_le32(features));
}
}
@@ -357,7 +474,7 @@ uint64_t virtio_get_host_features(struct virtio_device *dev)
features = ((uint64_t)le32_to_cpu(f1) << 32) | le32_to_cpu(f0);
} else {
- features = le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES));
+ features = le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_DEVICE_FEATURES));
}
return features;
}
@@ -405,7 +522,7 @@ uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
if (dev->is_modern)
confbase = dev->device.addr;
else
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
switch (size) {
case 1:
@@ -450,7 +567,7 @@ int __virtio_read_config(struct virtio_device *dev, void *dst,
if (dev->is_modern)
confbase = dev->device.addr;
else
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
for (i = 0; i < len; i++)
buf[i] = ci_read_8(confbase + offset + i);
diff --git a/lib/libvirtio/virtio.code b/lib/libvirtio/virtio.code
index 0c22ecc..8eec8f0 100644
--- a/lib/libvirtio/virtio.code
+++ b/lib/libvirtio/virtio.code
@@ -18,6 +18,11 @@
/******** core virtio ********/
+// : virtio-setup-vd ( -- dev )
+PRIM(virtio_X2d_setup_X2d_vd)
+ PUSH; TOS.a = virtio_setup_vd();
+MIRP
+
// : virtio-vring-size ( queuesize -- ringsize )
PRIM(virtio_X2d_vring_X2d_size)
TOS.u = virtio_vring_size(TOS.u);
diff --git a/lib/libvirtio/virtio.h b/lib/libvirtio/virtio.h
index 3ff2bac..0fee4ba 100644
--- a/lib/libvirtio/virtio.h
+++ b/lib/libvirtio/virtio.h
@@ -76,11 +76,9 @@ struct virtio_cap {
uint8_t bar;
uint8_t is_io;
uint8_t cap_id;
- uint8_t pad[5];
-} __attribute__ ((packed));
+};
struct virtio_device {
- void *base; /* base address */
uint32_t is_modern; /* Indicates whether to use virtio 1.0 */
struct virtio_cap legacy;
struct virtio_cap common;
@@ -89,7 +87,7 @@ struct virtio_device {
struct virtio_cap device;
struct virtio_cap pci;
uint32_t notify_off_mul;
-} __attribute__ ((packed));
+};
struct vqs {
uint64_t id; /* Queue ID */
@@ -113,6 +111,7 @@ extern void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
uint16_t flags, uint16_t next);
extern int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id);
+extern struct virtio_device *virtio_setup_vd(void);
extern void virtio_reset_device(struct virtio_device *dev);
extern void virtio_queue_notify(struct virtio_device *dev, int queue);
extern void virtio_set_status(struct virtio_device *dev, int status);
diff --git a/lib/libvirtio/virtio.in b/lib/libvirtio/virtio.in
index c36d127..195840e 100644
--- a/lib/libvirtio/virtio.in
+++ b/lib/libvirtio/virtio.in
@@ -10,6 +10,8 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+cod(virtio-setup-vd)
+
cod(virtio-vring-size)
cod(virtio-get-qsize)
cod(virtio-get-config)