[SLOF] [PATCH v6 23/23] virtio-net: enable virtio 1.0
Nikunj A Dadhania
nikunj at linux.vnet.ibm.com
Mon Feb 1 16:48:13 AEDT 2016
Also add a device file for non-transitional pci device id: 0x1041
Signed-off-by: Nikunj A Dadhania <nikunj at linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <thuth at redhat.com>
---
board-qemu/slof/Makefile | 1 +
board-qemu/slof/pci-device_1af4_1041.fs | 15 ++++++
lib/libvirtio/virtio-net.c | 94 +++++++++++++++++++++------------
lib/libvirtio/virtio-net.h | 3 ++
4 files changed, 80 insertions(+), 33 deletions(-)
create mode 100644 board-qemu/slof/pci-device_1af4_1041.fs
diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile
index b7d923c..44706b1 100644
--- a/board-qemu/slof/Makefile
+++ b/board-qemu/slof/Makefile
@@ -66,6 +66,7 @@ USB_FFS_FILES = \
VIO_FFS_FILES = \
$(SLOFBRDDIR)/pci-device_1af4_1000.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1041.fs \
$(SLOFBRDDIR)/pci-device_1af4_1001.fs \
$(SLOFBRDDIR)/pci-device_1af4_1042.fs \
$(SLOFBRDDIR)/pci-device_1af4_1004.fs \
diff --git a/board-qemu/slof/pci-device_1af4_1041.fs b/board-qemu/slof/pci-device_1af4_1041.fs
new file mode 100644
index 0000000..552b0ef
--- /dev/null
+++ b/board-qemu/slof/pci-device_1af4_1041.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 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
+\ ****************************************************************************/
+
+\ Device ID 1041 is for virtio-net non-transitional device.
+\ Include the driver for virtio-net
+s" pci-device_1af4_1000.fs" included
diff --git a/lib/libvirtio/virtio-net.c b/lib/libvirtio/virtio-net.c
index cce0bd7..fc620a2 100644
--- a/lib/libvirtio/virtio-net.c
+++ b/lib/libvirtio/virtio-net.c
@@ -26,6 +26,7 @@
#include <byteorder.h>
#include "virtio.h"
#include "virtio-net.h"
+#include "virtio-internal.h"
#undef DEBUG
//#define DEBUG
@@ -37,6 +38,8 @@
#define sync() asm volatile (" sync \n" ::: "memory")
+#define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1)
+
struct virtio_device virtiodev;
static struct vqs vq_rx; /* Information about receive virtqueues */
static struct vqs vq_tx; /* Information about transmit virtqueues */
@@ -54,6 +57,16 @@ struct virtio_net_hdr {
static unsigned int net_hdr_size;
+struct virtio_net_hdr_v1 {
+ uint8_t flags;
+ uint8_t gso_type;
+ le16 hdr_len;
+ le16 gso_size;
+ le16 csum_start;
+ le16 csum_offset;
+ le16 num_buffers;
+};
+
static uint16_t last_rx_idx; /* Last index in RX "used" ring */
/**
@@ -68,8 +81,8 @@ static int virtionet_init_pci(struct virtio_device *dev)
if (!dev)
return -1;
- /* Keep it disabled until the driver is 1.0 capable */
- virtiodev.is_modern = false;
+ /* make a copy of the device structure */
+ memcpy(&virtiodev, dev, sizeof(struct virtio_device));
/* Reset device */
virtio_reset_device(&virtiodev);
@@ -113,10 +126,17 @@ static int virtionet_init(net_driver_t *driver)
/* Tell HV that we know how to drive the device. */
virtio_set_status(&virtiodev, status);
- /* Device specific setup - we do not support special features right now */
- virtio_set_guest_features(&virtiodev, 0);
+ /* Device specific setup */
+ if (virtiodev.is_modern) {
+ if (virtio_negotiate_guest_features(&virtiodev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+ net_hdr_size = sizeof(struct virtio_net_hdr_v1);
+ virtio_get_status(&virtiodev, &status);
+ } else {
+ net_hdr_size = sizeof(struct virtio_net_hdr);
+ virtio_set_guest_features(&virtiodev, 0);
+ }
- net_hdr_size = sizeof(struct virtio_net_hdr);
/* Allocate memory for one transmit an multiple receive buffers */
vq_rx.buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size)
* RX_QUEUE_SIZE);
@@ -131,22 +151,23 @@ static int virtionet_init(net_driver_t *driver)
+ i * (BUFFER_ENTRY_SIZE+net_hdr_size);
uint32_t id = i*2;
/* Descriptor for net_hdr: */
- virtio_fill_desc(&vq_rx.desc[id], false, addr, net_hdr_size,
+ virtio_fill_desc(&vq_rx.desc[id], virtiodev.is_modern, addr, net_hdr_size,
VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1);
/* Descriptor for data: */
- virtio_fill_desc(&vq_rx.desc[id+1], false, addr + net_hdr_size,
+ virtio_fill_desc(&vq_rx.desc[id+1], virtiodev.is_modern, addr + net_hdr_size,
BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0);
- vq_rx.avail->ring[i] = id;
+ vq_rx.avail->ring[i] = virtio_cpu_to_modern16(&virtiodev, id);
}
sync();
- vq_rx.avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq_rx.avail->idx = RX_QUEUE_SIZE;
- last_rx_idx = vq_rx.used->idx;
+ vq_rx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, RX_QUEUE_SIZE);
+
+ last_rx_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
- vq_tx.avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_tx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
vq_tx.avail->idx = 0;
/* Tell HV that setup succeeded */
@@ -198,8 +219,10 @@ static int virtionet_term(net_driver_t *driver)
*/
static int virtionet_xmit(char *buf, int len)
{
- int id;
- static struct virtio_net_hdr nethdr;
+ int id, idx;
+ static struct virtio_net_hdr_v1 nethdr_v1;
+ static struct virtio_net_hdr nethdr_legacy;
+ void *nethdr = &nethdr_legacy;
if (len > BUFFER_ENTRY_SIZE) {
printf("virtionet: Packet too big!\n");
@@ -208,21 +231,25 @@ static int virtionet_xmit(char *buf, int len)
dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
- memset(&nethdr, 0, net_hdr_size);
+ if (virtiodev.is_modern)
+ nethdr = &nethdr_v1;
+
+ memset(nethdr, 0, net_hdr_size);
/* Determine descriptor index */
- id = (vq_tx.avail->idx * 2) % vq_tx.size;
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_tx.avail->idx);
+ id = (idx * 2) % vq_tx.size;
/* Set up virtqueue descriptor for header */
- virtio_fill_desc(&vq_tx.desc[id], false, (uint64_t)&nethdr,
- net_hdr_size, VRING_DESC_F_NEXT, id + 1);
+ virtio_fill_desc(&vq_tx.desc[id], virtiodev.is_modern, (uint64_t)nethdr,
+ net_hdr_size, VRING_DESC_F_NEXT, id + 1);
/* Set up virtqueue descriptor for data */
- virtio_fill_desc(&vq_tx.desc[id+1], false, (uint64_t)buf, len, 0, 0);
+ virtio_fill_desc(&vq_tx.desc[id+1], virtiodev.is_modern, (uint64_t)buf, len, 0, 0);
- vq_tx.avail->ring[vq_tx.avail->idx % vq_tx.size] = id;
+ vq_tx.avail->ring[idx % vq_tx.size] = virtio_cpu_to_modern16(&virtiodev, id);
sync();
- vq_tx.avail->idx += 1;
+ vq_tx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
sync();
/* Tell HV that TX queue is ready */
@@ -237,23 +264,24 @@ static int virtionet_xmit(char *buf, int len)
*/
static int virtionet_receive(char *buf, int maxlen)
{
- int len = 0;
- int id;
+ uint32_t len = 0;
+ uint32_t id, idx;
- if (last_rx_idx == vq_rx.used->idx) {
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
+
+ if (last_rx_idx == idx) {
/* Nothing received yet */
return 0;
}
- id = (vq_rx.used->ring[last_rx_idx % vq_rx.size].id + 1)
- % vq_rx.size;
- len = vq_rx.used->ring[last_rx_idx % vq_rx.size].len
- - net_hdr_size;
-
+ id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1)
+ % vq_rx.size;
+ len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len)
+ - net_hdr_size;
dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i,"
" id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len);
- if (len > maxlen) {
+ if (len > (uint32_t)maxlen) {
printf("virtio-net: Receive buffer not big enough!\n");
len = maxlen;
}
@@ -271,14 +299,14 @@ static int virtionet_receive(char *buf, int maxlen)
#endif
/* Copy data to destination buffer */
- memcpy(buf, (void*)vq_rx.desc[id].addr, len);
+ memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len);
/* Move indices to next entries */
last_rx_idx = last_rx_idx + 1;
- vq_rx.avail->ring[vq_rx.avail->idx % vq_rx.size] = id - 1;
+ vq_rx.avail->ring[idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1);
sync();
- vq_rx.avail->idx += 1;
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
/* Tell HV that RX queue entry is ready */
virtio_queue_notify(&virtiodev, VQ_RX);
diff --git a/lib/libvirtio/virtio-net.h b/lib/libvirtio/virtio-net.h
index 195afd4..c2d8ee3 100644
--- a/lib/libvirtio/virtio-net.h
+++ b/lib/libvirtio/virtio-net.h
@@ -23,6 +23,9 @@ enum {
VQ_TX = 1, /* Transmit Queue */
};
+/* VIRTIO_NET Feature bits */
+#define VIRTIO_NET_F_MAC (1 << 5)
+
extern net_driver_t *virtionet_open(struct virtio_device *dev);
extern void virtionet_close(net_driver_t *driver);
extern int virtionet_read(char *buf, int len);
--
2.5.0
More information about the SLOF
mailing list