[SLOF] [PATCH v3 15/22] virtio: make all virtio apis 1.0 aware

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


Convert the following routines:
    virtio_get_qsize
    virtio_vring_desc
    virtio_get_vring_avail
    virtio_get_vring_used
    virtio_set_status: also use it in device reset.
    virtio_queue_notify
    virtio_set_qaddr
    virtio_{get,read}_config
    virtio_fill_desc

Signed-off-by: Nikunj A Dadhania <nikunj at linux.vnet.ibm.com>
---
 lib/libvirtio/virtio.c | 127 +++++++++++++++++++++++++++++++++++++++++--------
 lib/libvirtio/virtio.h |   2 +-
 2 files changed, 108 insertions(+), 21 deletions(-)

diff --git a/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c
index 40bbd37..d07a1e7 100644
--- a/lib/libvirtio/virtio.c
+++ b/lib/libvirtio/virtio.c
@@ -94,11 +94,20 @@ unsigned long virtio_vring_size(unsigned int qsize)
  * @param   queue virtio queue number
  * @return  number of elements
  */
-int virtio_get_qsize(struct virtio_device *dev, int queue)
+unsigned int virtio_get_qsize(struct virtio_device *dev, int queue)
 {
-	int size = 0;
+	unsigned int size = 0;
 
-	if (dev->type == VIRTIO_TYPE_PCI) {
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return 0;
+	if (dev->is_modern) {
+		void *addr = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+		ci_write_16(addr, cpu_to_le16(queue));
+		eieio();
+		addr = dev->common.addr + offset_of(struct virtio_dev_common, q_size);
+		size = le16_to_cpu(ci_read_16(addr));
+	}
+	else {
 		ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
 			    cpu_to_le16(queue));
 		eieio();
@@ -119,7 +128,16 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
 {
 	struct vring_desc *desc = 0;
 
-	if (dev->type == VIRTIO_TYPE_PCI) {
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return NULL;
+	if (dev->is_modern) {
+		void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+		void *q_desc = dev->common.addr + offset_of(struct virtio_dev_common, q_desc);
+
+		ci_write_16(q_sel, cpu_to_le16(queue));
+		eieio();
+		desc = (void *)(virtio_pci_read64(q_desc));
+	} else {
 		ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
 			    cpu_to_le16(queue));
 		eieio();
@@ -139,8 +157,20 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
  */
 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));
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return NULL;
+	if (dev->is_modern) {
+		void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+		void *q_avail = dev->common.addr + offset_of(struct virtio_dev_common, q_avail);
+
+		ci_write_16(q_sel, cpu_to_le16(queue));
+		eieio();
+		return (void *)(virtio_pci_read64(q_avail));
+	}
+	else {
+		return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) +
+			       virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+	}
 }
 
 
@@ -152,9 +182,20 @@ struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
  */
 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));
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return NULL;
+	if (dev->is_modern) {
+		void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+		void *q_used = dev->common.addr + offset_of(struct virtio_dev_common, q_used);
+
+		ci_write_16(q_sel, cpu_to_le16(queue));
+		eieio();
+		return (void *)(virtio_pci_read64(q_used));
+	} else {
+		return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
+				       + virtio_get_qsize(dev, queue)
+				       * sizeof(struct vring_avail));
+	}
 }
 
 /**
@@ -182,9 +223,7 @@ void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
  */
 void virtio_reset_device(struct virtio_device *dev)
 {
-	if (dev->type == VIRTIO_TYPE_PCI) {
-		ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
-	}
+	virtio_set_status(dev, 0);
 }
 
 
@@ -193,7 +232,20 @@ void virtio_reset_device(struct virtio_device *dev)
  */
 void virtio_queue_notify(struct virtio_device *dev, int queue)
 {
-	if (dev->type == VIRTIO_TYPE_PCI) {
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return;
+	if (dev->is_modern) {
+		void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+		void *q_ntfy = dev->common.addr + offset_of(struct virtio_dev_common, q_notify_off);
+		void *addr;
+		uint16_t q_notify_off;
+
+		ci_write_16(q_sel, cpu_to_le16(queue));
+		eieio();
+		q_notify_off = le16_to_cpu(ci_read_16(q_ntfy));
+		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));
 	}
 }
@@ -203,7 +255,21 @@ void virtio_queue_notify(struct virtio_device *dev, int queue)
  */
 void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr)
 {
-	if (dev->type == VIRTIO_TYPE_PCI) {
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return;
+	if (dev->is_modern) {
+		uint64_t q_desc = qaddr;
+		uint64_t q_avail;
+		uint64_t q_used;
+		uint32_t q_size = virtio_get_qsize(dev, queue);
+
+		virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_desc), q_desc);
+		q_avail = q_desc + q_size * sizeof(struct vring_desc);
+		virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_avail), q_avail);
+		q_used = VQ_ALIGN(q_avail + sizeof(struct vring_avail) + sizeof(uint16_t) * q_size);
+		virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_used), q_used);
+		ci_write_16(dev->common.addr + offset_of(struct virtio_dev_common, q_enable), cpu_to_le16(1));
+	} else {
 		uint32_t val = qaddr;
 		val = val >> 12;
 		ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
@@ -235,7 +301,12 @@ int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int
  */
 void virtio_set_status(struct virtio_device *dev, int status)
 {
-	if (dev->type == VIRTIO_TYPE_PCI) {
+	if (dev->type != VIRTIO_TYPE_PCI)
+		return;
+	if (dev->is_modern) {
+		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);
 	}
 }
@@ -270,29 +341,41 @@ void virtio_get_host_features(struct virtio_device *dev, int *features)
 uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
 {
 	uint64_t val = ~0ULL;
+	uint32_t hi, lo;
 	void *confbase;
 
 	if (dev->type != VIRTIO_TYPE_PCI)
 		return val;
 
-	confbase = dev->base + VIRTIOHDR_DEVICE_CONFIG;
+	if (dev->is_modern)
+		confbase = dev->device.addr;
+	else
+		confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+
 	switch (size) {
 	case 1:
 		val = ci_read_8(confbase+offset);
 		break;
 	case 2:
 		val = ci_read_16(confbase+offset);
+		if (dev->is_modern)
+			val = le16_to_cpu(val);
 		break;
 	case 4:
 		val = ci_read_32(confbase+offset);
+		if (dev->is_modern)
+			val = le32_to_cpu(val);
 		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);
+		lo = ci_read_32(confbase+offset);
+		hi = ci_read_32(confbase+offset+4);
+		if (dev->is_modern)
+			val = (uint64_t)le32_to_cpu(hi) << 32 | le32_to_cpu(lo);
+		else
+			val = (uint64_t)hi << 32 | lo;
 		break;
 	}
 
@@ -312,7 +395,11 @@ int __virtio_read_config(struct virtio_device *dev, void *dst,
 	if (dev->type != VIRTIO_TYPE_PCI)
 		return 0;
 
-	confbase = dev->base + VIRTIOHDR_DEVICE_CONFIG;
+	if (dev->is_modern)
+		confbase = dev->device.addr;
+	else
+		confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+
 	for (i = 0; i < len; i++)
 		buf[i] = ci_read_8(confbase + offset + i);
 
diff --git a/lib/libvirtio/virtio.h b/lib/libvirtio/virtio.h
index 8c9daab..b0de538 100644
--- a/lib/libvirtio/virtio.h
+++ b/lib/libvirtio/virtio.h
@@ -107,7 +107,7 @@ struct vqs {
 #define VQ_ALIGN(addr)	(((addr) + 0xfff) & ~0xfff)
 
 extern unsigned long virtio_vring_size(unsigned int qsize);
-extern int virtio_get_qsize(struct virtio_device *dev, int queue);
+extern unsigned int virtio_get_qsize(struct virtio_device *dev, int queue);
 extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue);
 extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue);
 extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue);
-- 
2.5.0



More information about the SLOF mailing list