[SLOF] [PATCH v6 20/23] virtio: add and enable 1.0 device setup

Nikunj A Dadhania nikunj at linux.vnet.ibm.com
Mon Feb 1 16:48:10 AEDT 2016


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 at linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <thuth at redhat.com>
---
 board-qemu/slof/OF.fs           |   4 --
 board-qemu/slof/virtio-block.fs |   3 +-
 board-qemu/slof/virtio-fs.fs    |   3 +-
 board-qemu/slof/virtio-net.fs   |   3 +-
 board-qemu/slof/virtio-scsi.fs  |   3 +-
 board-qemu/slof/virtio.fs       |  35 ----------
 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          | 143 ++++++++++++++++++++++++++++++++++++----
 lib/libvirtio/virtio.code       |   5 ++
 lib/libvirtio/virtio.h          |   7 +-
 lib/libvirtio/virtio.in         |   2 +
 14 files changed, 155 insertions(+), 65 deletions(-)
 delete mode 100644 board-qemu/slof/virtio.fs

diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs
index 561d892..69ee5c1 100644
--- a/board-qemu/slof/OF.fs
+++ b/board-qemu/slof/OF.fs
@@ -134,10 +134,6 @@ check-boot-menu
 \ Grab rtas from qemu
 #include "rtas.fs"
 
-390 cp
-
-#include "virtio.fs"
-
 3f0 cp
 
 #include "tree.fs"
diff --git a/board-qemu/slof/virtio-block.fs b/board-qemu/slof/virtio-block.fs
index ea388fb..bc9013e 100644
--- a/board-qemu/slof/virtio-block.fs
+++ b/board-qemu/slof/virtio-block.fs
@@ -23,8 +23,7 @@ FALSE VALUE initialized?
 
 INSTANCE VARIABLE deblocker
 
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
 
 \ Quiesce the virtqueue of this device so that no more background
 \ transactions can be pending.
diff --git a/board-qemu/slof/virtio-fs.fs b/board-qemu/slof/virtio-fs.fs
index 8632b46..3898d0b 100644
--- a/board-qemu/slof/virtio-fs.fs
+++ b/board-qemu/slof/virtio-fs.fs
@@ -20,8 +20,7 @@ FALSE VALUE initialized?
 
 2000 CONSTANT VIRTFS-BUF-SIZE \ 8k
 
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
 
 \
 \ Support methods.
diff --git a/board-qemu/slof/virtio-net.fs b/board-qemu/slof/virtio-net.fs
index 882b733..b16fffe 100644
--- a/board-qemu/slof/virtio-net.fs
+++ b/board-qemu/slof/virtio-net.fs
@@ -16,8 +16,7 @@ s" network" device-type
 
 INSTANCE VARIABLE obp-tftp-package
 
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
 0 VALUE virtio-net-priv
 0 VALUE open-count
 
diff --git a/board-qemu/slof/virtio-scsi.fs b/board-qemu/slof/virtio-scsi.fs
index ca5fb13..4fedeee 100644
--- a/board-qemu/slof/virtio-scsi.fs
+++ b/board-qemu/slof/virtio-scsi.fs
@@ -22,8 +22,7 @@ FALSE CONSTANT virtio-scsi-debug
 
 FALSE VALUE initialized?
 
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
 
 STRUCT \ virtio-scsi-config
     /l FIELD vs-cfg>num-queues
diff --git a/board-qemu/slof/virtio.fs b/board-qemu/slof/virtio.fs
deleted file mode 100644
index 28700f9..0000000
--- a/board-qemu/slof/virtio.fs
+++ /dev/null
@@ -1,35 +0,0 @@
-\ *****************************************************************************
-\ * Copyright (c) 2011 IBM Corporation
-\ * All rights reserved.
-\ * This program and the accompanying materials
-\ * are made available under the terms of the BSD License
-\ * which accompanies this distribution, and is available at
-\ * http://www.opensource.org/licenses/bsd-license.php
-\ *
-\ * Contributors:
-\ *     IBM Corporation - initial implementation
-\ ****************************************************************************/
-
-\ This struct must match "struct virtio_device" in virtio.h!
-STRUCT
-   /n FIELD vd>base
-   /l FIELD vd>is-modern
-   10 FIELD vd>legacy
-   10 FIELD vd>common
-   10 FIELD vd>notify
-   10 FIELD vd>isr
-   10 FIELD vd>device
-   10 FIELD vd>pci
-   /l FIELD vd>notify_off_mul
-CONSTANT /vd-len
-
-
-\ Initialize virtiodev structure for the current node
-\ This routine gets called from pci device files
-: virtio-setup-vd  ( vdstruct -- )
-   >r
-   \ Set up for PCI device interface
-   s" 10 config-l@ translate-my-address 3 not AND" evaluate
-   ( io-base ) r@ vd>base !
-   r> drop
-;
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)
-- 
2.5.0



More information about the SLOF mailing list