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

Thomas Huth thuth at redhat.com
Fri Jan 29 23:43:55 AEDT 2016


On 29.01.2016 12:19, Nikunj A Dadhania wrote:
> 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>
> ---
>  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/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c
> index 276d69f..a9874b4 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) {

Nit: Space after the "if"

> +		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)

Reviewed-by: Thomas Huth <thuth at redhat.com>



More information about the SLOF mailing list