[SLOF] [PATCH v2 16/19] virtio: add and enable 1.0 capability parsing

Nikunj A Dadhania nikunj at linux.vnet.ibm.com
Wed Jan 20 23:10:30 AEDT 2016


Introcduce 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      | 118 ++++++++++++++++++++++++++++++++++++++++++++
 lib/libvirtio/virtio.code   |   6 +++
 lib/libvirtio/virtio.h      |   1 +
 lib/libvirtio/virtio.in     |   2 +
 9 files changed, 140 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 f1595c7..2337ab9 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 98c1a80..9587c4d 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;
 	uint32_t 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 6f0e44d..aad7f9b 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 9c064f0..21c6d2b 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;
 	uint32_t 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 0b939fc..12d1b2e 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,93 @@ static uint64_t virtio_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:
+		cap = NULL;
+	}
+
+	if (cap && cfg_type) {
+		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) |
+				(SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32);
+			addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+			addr = addr & PCI_BASE_ADDR_MEM_MASK;
+		} else {
+			cap->is_io = 0;
+			addr = addr & PCI_BASE_ADDR_MEM_MASK;
+		}
+		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;
+		}
+		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..c3cb4de 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 011732d..95ee316 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, uint32_t 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