[SLOF] [PATCH v3 18/22] virtio: add and enable 1.0 capability parsing

Nikunj A Dadhania nikunj at linux.vnet.ibm.com
Fri Jan 22 21:55:01 AEDT 2016


Introduce parsing routines for virtio capabilities. This would also
determine whether we need to function in legacy mode or virtio 1.0.

Drivers need to negotiate the 1.0 feature capability before starting to
use 1.0.

Disable all the drivers until 1.0 is enabled.

Signed-off-by: Nikunj A Dadhania <nikunj at linux.vnet.ibm.com>
---
 board-qemu/slof/virtio.fs   |   1 +
 lib/libvirtio/virtio-9p.c   |   3 ++
 lib/libvirtio/virtio-blk.c  |   3 ++
 lib/libvirtio/virtio-net.c  |   3 ++
 lib/libvirtio/virtio-scsi.c |   3 ++
 lib/libvirtio/virtio.c      | 117 ++++++++++++++++++++++++++++++++++++++++++++
 lib/libvirtio/virtio.code   |   6 +++
 lib/libvirtio/virtio.h      |   1 +
 lib/libvirtio/virtio.in     |   2 +
 9 files changed, 139 insertions(+)

diff --git a/board-qemu/slof/virtio.fs b/board-qemu/slof/virtio.fs
index 64381b1..24a8efc 100644
--- a/board-qemu/slof/virtio.fs
+++ b/board-qemu/slof/virtio.fs
@@ -44,6 +44,7 @@ CONSTANT /vd-len
       s" 10 config-l@ translate-my-address 3 not AND" evaluate
       ( io-base ) r@ vd>base !
       0 r@ vd>type l!
+      r@ virtio-parse-capabilities
    ELSE
       ." unsupported virtio interface!" cr
       1 r@ vd>type l!
diff --git a/lib/libvirtio/virtio-9p.c b/lib/libvirtio/virtio-9p.c
index fe1050c..6b6507b 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 bff86b2..83c3244 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 8ae3ae1..a51ea0a 100644
--- a/lib/libvirtio/virtio-net.c
+++ b/lib/libvirtio/virtio-net.c
@@ -71,6 +71,9 @@ static int virtionet_init_pci(struct virtio_device *dev)
 	virtiodev.base = dev->base;
 	virtiodev.type = dev->type;
 
+	/* 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 04d3125..0264baa 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_MEM	0x00
+#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_process_cap(struct virtio_device *dev, uint8_t cap_ptr)
+{
+	struct virtio_cap *cap;
+	uint8_t cfg_type, bar;
+	uint32_t offset;
+	uint64_t addr = 0;
+
+	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;
+	addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar);
+	if (addr & PCI_BASE_ADDR_SPACE_IO) {
+		cap->is_io = 1;
+		addr = addr & PCI_BASE_ADDR_IO_MASK;
+	} else if (addr & 4) {
+		addr |= SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32;
+		addr = addr & PCI_BASE_ADDR_MEM_MASK;
+		addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+	} else {
+		cap->is_io = 0;
+		addr = addr & PCI_BASE_ADDR_MEM_MASK;
+		addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+	}
+	cap->addr = (void *)addr + offset;
+	cap->cap_id = cfg_type;
+	return;
+}
+
+/**
+ * Reads the virtio device capabilities, gets called from SLOF routines The
+ * function determines legacy or modern device and sets up driver registers
+ */
+void virtio_parse_capabilities(struct virtio_device *dev)
+{
+	uint8_t cap_ptr, cap_vndr;
+	uint64_t addr = 0;
+
+	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;
+		addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0);
+		if (addr & PCI_BASE_ADDR_SPACE_IO) {
+			dev->legacy.is_io = 1;
+			addr = addr & PCI_BASE_ADDR_IO_MASK;
+		} else {
+			dev->legacy.is_io = 0;
+			addr = addr & PCI_BASE_ADDR_MEM_MASK;
+			addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+		}
+		dev->legacy.addr = (void *)addr;
+	}
+	return;
+}
+
 /**
  * Calculate ring size according to queue size number
  */
diff --git a/lib/libvirtio/virtio.code b/lib/libvirtio/virtio.code
index 258b9bb..ffd65d0 100644
--- a/lib/libvirtio/virtio.code
+++ b/lib/libvirtio/virtio.code
@@ -18,6 +18,12 @@
 
 /******** core virtio ********/
 
+// : virtio-parse-capabilities  ( dev --  )
+PRIM(virtio_X2d_parse_X2d_capabilities)
+	void *dev = TOS.a; POP;
+	virtio_parse_capabilities(dev);
+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 da37ce2..baf3961 100644
--- a/lib/libvirtio/virtio.h
+++ b/lib/libvirtio/virtio.h
@@ -116,6 +116,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 void virtio_parse_capabilities(struct virtio_device *dev);
 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..bd5485e 100644
--- a/lib/libvirtio/virtio.in
+++ b/lib/libvirtio/virtio.in
@@ -10,6 +10,8 @@
  *     IBM Corporation - initial implementation
  *****************************************************************************/
 
+cod(virtio-parse-capabilities)
+
 cod(virtio-vring-size)
 cod(virtio-get-qsize)
 cod(virtio-get-config)
-- 
2.5.0



More information about the SLOF mailing list