diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-01-13 12:07:42 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-01-19 17:17:50 +1100 |
commit | ca610c931e2b0004c44f748cb813580b09c60489 (patch) | |
tree | cf17ebaa02078827068b534bb95d4540bd848678 /lib/libvirtio/virtio.c | |
parent | adde61dfebe5ba4c519b120e8b33f1f8a3c93151 (diff) | |
download | SLOF-ca610c931e2b0004c44f748cb813580b09c60489.zip SLOF-ca610c931e2b0004c44f748cb813580b09c60489.tar.gz SLOF-ca610c931e2b0004c44f748cb813580b09c60489.tar.bz2 |
Move virtio to a separate library
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'lib/libvirtio/virtio.c')
-rw-r--r-- | lib/libvirtio/virtio.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c new file mode 100644 index 0000000..4e70053 --- /dev/null +++ b/lib/libvirtio/virtio.c @@ -0,0 +1,191 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ + +#include <cpu.h> +#include <cache.h> +#include <byteorder.h> +#include "virtio.h" + +/* PCI virtio header offsets */ +#define VIRTIOHDR_DEVICE_FEATURES 0 +#define VIRTIOHDR_GUEST_FEATURES 4 +#define VIRTIOHDR_QUEUE_ADDRESS 8 +#define VIRTIOHDR_QUEUE_SIZE 12 +#define VIRTIOHDR_QUEUE_SELECT 14 +#define VIRTIOHDR_QUEUE_NOTIFY 16 +#define VIRTIOHDR_DEVICE_STATUS 18 +#define VIRTIOHDR_ISR_STATUS 19 +#define VIRTIOHDR_DEVICE_CONFIG 20 + + +/** + * Calculate ring size according to queue size number + */ +unsigned long virtio_vring_size(unsigned int qsize) +{ + return VQ_ALIGN(sizeof(struct vring_desc) * qsize + 2 * (2 + qsize)) + + VQ_ALIGN(sizeof(struct vring_used_elem) * qsize); +} + + +/** + * Get number of elements in a vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return number of elements + */ +int virtio_get_qsize(struct virtio_device *dev, int queue) +{ + int size = 0; + + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE)); + } + + return size; +} + + +/** + * Get address of descriptor vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the descriptor ring + */ +struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue) +{ + struct vring_desc *desc = 0; + + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + desc = (void*)(4096L * + le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS))); + } + + return desc; +} + + +/** + * Get address of "available" vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the "available" ring + */ +struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue) +{ + return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) + + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc)); +} + + +/** + * Get address of "used" vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the "used" ring + */ +struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue) +{ + return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue) + + virtio_get_qsize(dev, queue) + * sizeof(struct vring_avail)); +} + + +/** + * Reset virtio device + */ +void virtio_reset_device(struct virtio_device *dev) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0); + } +} + + +/** + * Notify hypervisor about queue update + */ +void virtio_queue_notify(struct virtio_device *dev, int queue) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue)); + } +} + + +/** + * Set device status bits + */ +void virtio_set_status(struct virtio_device *dev, int status) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status); + } +} + + +/** + * Set guest feature bits + */ +void virtio_set_guest_features(struct virtio_device *dev, int features) + +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, features); + } +} + + +/** + * Get additional config values + */ +uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size) +{ + uint64_t val = ~0ULL; + void *confbase; + + switch (dev->type) { + case VIRTIO_TYPE_PCI: + confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG; + break; + default: + return ~0ULL; + } + switch (size) { + case 1: + val = ci_read_8(confbase+offset); + break; + case 2: + val = ci_read_16(confbase+offset); + break; + case 4: + val = ci_read_32(confbase+offset); + break; + case 8: + /* We don't support 8 bytes PIO accesses + * in qemu and this is all PIO + */ + val = ci_read_32(confbase+offset); + val <<= 32; + val |= ci_read_32(confbase+offset+4); + break; + } + + return val; +} |