Commit a586d4f6 authored by Rusty Russell's avatar Rusty Russell
Browse files

virtio: simplify config mechanism.



Previously we used a type/len pair within the config space, but this
seems overkill.  We now simply define a structure which represents the
layout in the config space: the config space can now only be extended
at the end.

The main driver-visible changes:
1) We indicate what fields are present with an explicit feature bit.
2) Virtqueues are explicitly numbered, and not in the config space.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent f35d9d8a
Loading
Loading
Loading
Loading
+105 −71
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include <zlib.h>
#include <assert.h>
#include <sched.h>
#include <limits.h>
#include <stddef.h>
#include "linux/lguest_launcher.h"
#include "linux/virtio_config.h"
#include "linux/virtio_net.h"
@@ -99,13 +101,11 @@ struct device_list
	/* The descriptor page for the devices. */
	u8 *descpage;

	/* The tail of the last descriptor. */
	unsigned int desc_used;

	/* A single linked list of devices. */
	struct device *dev;
	/* ... And an end pointer so we can easily append new devices */
	struct device **lastdev;
	/* And a pointer to the last device for easy append and also for
	 * configuration appending. */
	struct device *lastdev;
};

/* The list of Guest devices, based on command line arguments. */
@@ -191,7 +191,7 @@ static void *_convert(struct iovec *iov, size_t size, size_t align,
#define cpu_to_le64(v64) (v64)
#define le16_to_cpu(v16) (v16)
#define le32_to_cpu(v32) (v32)
#define le64_to_cpu(v32) (v64)
#define le64_to_cpu(v64) (v64)

/*L:100 The Launcher code itself takes us out into userspace, that scary place
 * where pointers run wild and free!  Unfortunately, like most userspace
@@ -986,54 +986,44 @@ static void handle_input(int fd)
 *
 * All devices need a descriptor so the Guest knows it exists, and a "struct
 * device" so the Launcher can keep track of it.  We have common helper
 * routines to allocate them.
 *
 * This routine allocates a new "struct lguest_device_desc" from descriptor
 * table just above the Guest's normal memory.  It returns a pointer to that
 * descriptor. */
static struct lguest_device_desc *new_dev_desc(u16 type)
{
	struct lguest_device_desc *d;
 * routines to allocate and manage them. */

	/* We only have one page for all the descriptors. */
	if (devices.desc_used + sizeof(*d) > getpagesize())
		errx(1, "Too many devices");

	/* We don't need to set config_len or status: page is 0 already. */
	d = (void *)devices.descpage + devices.desc_used;
	d->type = type;
	devices.desc_used += sizeof(*d);

	return d;
/* The layout of the device page is a "struct lguest_device_desc" followed by a
 * number of virtqueue descriptors, then two sets of feature bits, then an
 * array of configuration bytes.  This routine returns the configuration
 * pointer. */
static u8 *device_config(const struct device *dev)
{
	return (void *)(dev->desc + 1)
		+ dev->desc->num_vq * sizeof(struct lguest_vqconfig)
		+ dev->desc->feature_len * 2;
}

/* Each device descriptor is followed by some configuration information.
 * Each configuration field looks like: u8 type, u8 len, [... len bytes...].
 *
 * This routine adds a new field to an existing device's descriptor.  It only
 * works for the last device, but that's OK because that's how we use it. */
static void add_desc_field(struct device *dev, u8 type, u8 len, const void *c)
/* This routine allocates a new "struct lguest_device_desc" from descriptor
 * table page just above the Guest's normal memory.  It returns a pointer to
 * that descriptor. */
static struct lguest_device_desc *new_dev_desc(u16 type)
{
	/* This is the last descriptor, right? */
	assert(devices.descpage + devices.desc_used
	       == (u8 *)(dev->desc + 1) + dev->desc->config_len);
	struct lguest_device_desc d = { .type = type };
	void *p;

	/* We only have one page of device descriptions. */
	if (devices.desc_used + 2 + len > getpagesize())
		errx(1, "Too many devices");
	/* Figure out where the next device config is, based on the last one. */
	if (devices.lastdev)
		p = device_config(devices.lastdev)
			+ devices.lastdev->desc->config_len;
	else
		p = devices.descpage;

	/* Copy in the new config header: type then length. */
	devices.descpage[devices.desc_used++] = type;
	devices.descpage[devices.desc_used++] = len;
	memcpy(devices.descpage + devices.desc_used, c, len);
	devices.desc_used += len;
	/* We only have one page for all the descriptors. */
	if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
		errx(1, "Too many devices");

	/* Update the device descriptor length: two byte head then data. */
	dev->desc->config_len += 2 + len;
	/* p might not be aligned, so we memcpy in. */
	return memcpy(p, &d, sizeof(d));
}

/* This routine adds a virtqueue to a device.  We specify how many descriptors
 * the virtqueue is to have. */
/* Each device descriptor is followed by the description of its virtqueues.  We
 * specify how many descriptors the virtqueue is to have. */
static void add_virtqueue(struct device *dev, unsigned int num_descs,
			  void (*handle_output)(int fd, struct virtqueue *me))
{
@@ -1059,9 +1049,15 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
	/* Initialize the vring. */
	vring_init(&vq->vring, num_descs, p, getpagesize());

	/* Add the configuration information to this device's descriptor. */
	add_desc_field(dev, VIRTIO_CONFIG_F_VIRTQUEUE,
		       sizeof(vq->config), &vq->config);
	/* Append virtqueue to this device's descriptor.  We use
	 * device_config() to get the end of the device's current virtqueues;
	 * we check that we haven't added any config or feature information
	 * yet, otherwise we'd be overwriting them. */
	assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
	memcpy(device_config(dev), &vq->config, sizeof(vq->config));
	dev->desc->num_vq++;

	verbose("Virtqueue page %#lx\n", to_guest_phys(p));

	/* Add to tail of list, so dev->vq is first vq, dev->vq->next is
	 * second.  */
@@ -1077,6 +1073,37 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
		vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
}

/* The virtqueue descriptors are followed by feature bytes. */
static void add_feature(struct device *dev, unsigned bit)
{
	u8 *features;

	/* We can't extend the feature bits once we've added config bytes */
	if (dev->desc->feature_len <= bit / CHAR_BIT) {
		assert(dev->desc->config_len == 0);
		dev->desc->feature_len = (bit / CHAR_BIT) + 1;
	}

	features = (u8 *)(dev->desc + 1)
		+ dev->desc->num_vq * sizeof(struct lguest_vqconfig);

	features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
}

/* This routine sets the configuration fields for an existing device's
 * descriptor.  It only works for the last device, but that's OK because that's
 * how we use it. */
static void set_config(struct device *dev, unsigned len, const void *conf)
{
	/* Check we haven't overflowed our single page. */
	if (device_config(dev) + len > devices.descpage + getpagesize())
		errx(1, "Too many devices");

	/* Copy in the config information, and store the length. */
	memcpy(device_config(dev), conf, len);
	dev->desc->config_len = len;
}

/* This routine does all the creation and setup of a new device, including
 * calling new_dev_desc() to allocate the descriptor and device memory. */
static struct device *new_device(const char *name, u16 type, int fd,
@@ -1084,14 +1111,6 @@ static struct device *new_device(const char *name, u16 type, int fd,
{
	struct device *dev = malloc(sizeof(*dev));

	/* Append to device list.  Prepending to a single-linked list is
	 * easier, but the user expects the devices to be arranged on the bus
	 * in command-line order.  The first network device on the command line
	 * is eth0, the first block device /dev/vda, etc. */
	*devices.lastdev = dev;
	dev->next = NULL;
	devices.lastdev = &dev->next;

	/* Now we populate the fields one at a time. */
	dev->fd = fd;
	/* If we have an input handler for this file descriptor, then we add it
@@ -1102,6 +1121,17 @@ static struct device *new_device(const char *name, u16 type, int fd,
	dev->handle_input = handle_input;
	dev->name = name;
	dev->vq = NULL;

	/* Append to device list.  Prepending to a single-linked list is
	 * easier, but the user expects the devices to be arranged on the bus
	 * in command-line order.  The first network device on the command line
	 * is eth0, the first block device /dev/vda, etc. */
	if (devices.lastdev)
		devices.lastdev->next = dev;
	else
		devices.dev = dev;
	devices.lastdev = dev;

	return dev;
}

@@ -1226,7 +1256,7 @@ static void setup_tun_net(const char *arg)
	int netfd, ipfd;
	u32 ip;
	const char *br_name = NULL;
	u8 hwaddr[6];
	struct virtio_net_config conf;

	/* We open the /dev/net/tun device and tell it we want a tap device.  A
	 * tap device is like a tun device, only somehow different.  To tell
@@ -1265,12 +1295,13 @@ static void setup_tun_net(const char *arg)
		ip = str2ip(arg);

	/* Set up the tun device, and get the mac address for the interface. */
	configure_device(ipfd, ifr.ifr_name, ip, hwaddr);
	configure_device(ipfd, ifr.ifr_name, ip, conf.mac);

	/* Tell Guest what MAC address to use. */
	add_desc_field(dev, VIRTIO_CONFIG_NET_MAC_F, sizeof(hwaddr), hwaddr);
	add_feature(dev, VIRTIO_NET_F_MAC);
	set_config(dev, sizeof(conf), &conf);

	/* We don't seed the socket any more; setup is done. */
	/* We don't need the socket any more; setup is done. */
	close(ipfd);

	verbose("device %u: tun net %u.%u.%u.%u\n",
@@ -1458,8 +1489,7 @@ static void setup_block_file(const char *filename)
	struct device *dev;
	struct vblk_info *vblk;
	void *stack;
	u64 cap;
	unsigned int val;
	struct virtio_blk_config conf;

	/* This is the pipe the I/O thread will use to tell us I/O is done. */
	pipe(p);
@@ -1477,14 +1507,18 @@ static void setup_block_file(const char *filename)
	vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
	vblk->len = lseek64(vblk->fd, 0, SEEK_END);

	/* We support barriers. */
	add_feature(dev, VIRTIO_BLK_F_BARRIER);

	/* Tell Guest how many sectors this device has. */
	cap = cpu_to_le64(vblk->len / 512);
	add_desc_field(dev, VIRTIO_CONFIG_BLK_F_CAPACITY, sizeof(cap), &cap);
	conf.capacity = cpu_to_le64(vblk->len / 512);

	/* Tell Guest not to put in too many descriptors at once: two are used
	 * for the in and out elements. */
	val = cpu_to_le32(VIRTQUEUE_NUM - 2);
	add_desc_field(dev, VIRTIO_CONFIG_BLK_F_SEG_MAX, sizeof(val), &val);
	add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
	conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);

	set_config(dev, sizeof(conf), &conf);

	/* The I/O thread writes to this end of the pipe when done. */
	vblk->done_fd = p[1];
@@ -1505,7 +1539,7 @@ static void setup_block_file(const char *filename)
	close(vblk->workpipe[0]);

	verbose("device %u: virtblock %llu sectors\n",
		devices.device_num, cap);
		devices.device_num, le64_to_cpu(conf.capacity));
}
/* That's the end of device setup. :*/

@@ -1610,12 +1644,12 @@ int main(int argc, char *argv[])
	/* First we initialize the device list.  Since console and network
	 * device receive input from a file descriptor, we keep an fdset
	 * (infds) and the maximum fd number (max_infd) with the head of the
	 * list.  We also keep a pointer to the last device, for easy appending
	 * to the list.  Finally, we keep the next interrupt number to hand out
	 * (1: remember that 0 is used by the timer). */
	 * list.  We also keep a pointer to the last device.  Finally, we keep
	 * the next interrupt number to hand out (1: remember that 0 is used by
	 * the timer). */
	FD_ZERO(&devices.infds);
	devices.max_infd = -1;
	devices.lastdev = &devices.dev;
	devices.lastdev = NULL;
	devices.next_irq = 1;

	cpu_id = 0;
+13 −22
Original line number Diff line number Diff line
@@ -162,8 +162,6 @@ static int virtblk_probe(struct virtio_device *vdev)
{
	struct virtio_blk *vblk;
	int err, major;
	void *token;
	unsigned int len;
	u64 cap;
	u32 v;

@@ -178,7 +176,7 @@ static int virtblk_probe(struct virtio_device *vdev)
	vblk->vdev = vdev;

	/* We expect one virtqueue, for output. */
	vblk->vq = vdev->config->find_vq(vdev, blk_done);
	vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
	if (IS_ERR(vblk->vq)) {
		err = PTR_ERR(vblk->vq);
		goto out_free_vblk;
@@ -216,15 +214,12 @@ static int virtblk_probe(struct virtio_device *vdev)
	vblk->disk->fops = &virtblk_fops;

	/* If barriers are supported, tell block layer that queue is ordered */
	token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len);
	if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
	if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
		blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);

	err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
	if (err) {
		dev_err(&vdev->dev, "Bad/missing capacity in config\n");
		goto out_cleanup_queue;
	}
	/* Host must always specify the capacity. */
	__virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
			    &cap);

	/* If capacity is too big, truncate with warning. */
	if ((sector_t)cap != cap) {
@@ -234,27 +229,23 @@ static int virtblk_probe(struct virtio_device *vdev)
	}
	set_capacity(vblk->disk, cap);

	err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v);
	/* Host can optionally specify maximum segment size and number of
	 * segments. */
	err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
				offsetof(struct virtio_blk_config, size_max),
				&v);
	if (!err)
		blk_queue_max_segment_size(vblk->disk->queue, v);
	else if (err != -ENOENT) {
		dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
		goto out_cleanup_queue;
	}

	err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
	err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
				offsetof(struct virtio_blk_config, seg_max),
				&v);
	if (!err)
		blk_queue_max_hw_segments(vblk->disk->queue, v);
	else if (err != -ENOENT) {
		dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
		goto out_cleanup_queue;
	}

	add_disk(vblk->disk);
	return 0;

out_cleanup_queue:
	blk_cleanup_queue(vblk->disk->queue);
out_put_disk:
	put_disk(vblk->disk);
out_unregister_blkdev:
+2 −2
Original line number Diff line number Diff line
@@ -158,13 +158,13 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
	/* Find the input queue. */
	/* FIXME: This is why we want to wean off hvc: we do nothing
	 * when input comes in. */
	in_vq = vdev->config->find_vq(vdev, NULL);
	in_vq = vdev->config->find_vq(vdev, 0, NULL);
	if (IS_ERR(in_vq)) {
		err = PTR_ERR(in_vq);
		goto free;
	}

	out_vq = vdev->config->find_vq(vdev, NULL);
	out_vq = vdev->config->find_vq(vdev, 1, NULL);
	if (IS_ERR(out_vq)) {
		err = PTR_ERR(out_vq);
		goto free_in_vq;
+74 −58
Original line number Diff line number Diff line
@@ -52,57 +52,82 @@ struct lguest_device {
/*D:130
 * Device configurations
 *
 * The configuration information for a device consists of a series of fields.
 * We don't really care what they are: the Launcher set them up, and the driver
 * will look at them during setup.
 * The configuration information for a device consists of one or more
 * virtqueues, a feature bitmaks, and some configuration bytes.  The
 * configuration bytes don't really matter to us: the Launcher set them up, and
 * the driver will look at them during setup.
 *
 * For us these fields come immediately after that device's descriptor in the
 * lguest_devices page.
 *
 * Each field starts with a "type" byte, a "length" byte, then that number of
 * bytes of configuration information.  The device descriptor tells us the
 * total configuration length so we know when we've reached the last field. */
 * A convenient routine to return the device's virtqueue config array:
 * immediately after the descriptor. */
static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
{
	return (void *)(desc + 1);
}

/* type + length bytes */
#define FHDR_LEN 2
/* The features come immediately after the virtqueues. */
static u8 *lg_features(const struct lguest_device_desc *desc)
{
	return (void *)(lg_vq(desc) + desc->num_vq);
}

/* This finds the first field of a given type for a device's configuration. */
static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len)
/* The config space comes after the two feature bitmasks. */
static u8 *lg_config(const struct lguest_device_desc *desc)
{
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
	int i;

	for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
		if (desc->config[i] == type) {
			/* Mark it used, so Host can know we looked at it, and
			 * also so we won't find the same one twice. */
			desc->config[i] |= 0x80;
			/* Remember, the second byte is the length. */
			*len = desc->config[i+1];
			/* We return a pointer to the field header. */
			return desc->config + i;
	return lg_features(desc) + desc->feature_len * 2;
}

/* The total size of the config page used by this device (incl. desc) */
static unsigned desc_size(const struct lguest_device_desc *desc)
{
	return sizeof(*desc)
		+ desc->num_vq * sizeof(struct lguest_vqconfig)
		+ desc->feature_len * 2
		+ desc->config_len;
}

	/* Not found: return NULL for failure. */
	return NULL;
/* This tests (and acknowleges) a feature bit. */
static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
{
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
	u8 *features;

	/* Obviously if they ask for a feature off the end of our feature
	 * bitmap, it's not set. */
	if (fbit / 8 > desc->feature_len)
		return false;

	/* The feature bitmap comes after the virtqueues. */
	features = lg_features(desc);
	if (!(features[fbit / 8] & (1 << (fbit % 8))))
		return false;

	/* We set the matching bit in the other half of the bitmap to tell the
	 * Host we want to use this feature.  We don't use this yet, but we
	 * could in future. */
	features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
	return true;
}

/* Once they've found a field, getting a copy of it is easy. */
static void lg_get(struct virtio_device *vdev, void *token,
static void lg_get(struct virtio_device *vdev, unsigned int offset,
		   void *buf, unsigned len)
{
	/* Check they didn't ask for more than the length of the field! */
	BUG_ON(len > ((u8 *)token)[1]);
	memcpy(buf, token + FHDR_LEN, len);
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;

	/* Check they didn't ask for more than the length of the config! */
	BUG_ON(offset + len > desc->config_len);
	memcpy(buf, lg_config(desc) + offset, len);
}

/* Setting the contents is also trivial. */
static void lg_set(struct virtio_device *vdev, void *token,
static void lg_set(struct virtio_device *vdev, unsigned int offset,
		   const void *buf, unsigned len)
{
	BUG_ON(len > ((u8 *)token)[1]);
	memcpy(token + FHDR_LEN, buf, len);
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;

	/* Check they didn't ask for more than the length of the config! */
	BUG_ON(offset + len > desc->config_len);
	memcpy(lg_config(desc) + offset, buf, len);
}

/* The operations to get and set the status word just access the status field
@@ -165,39 +190,29 @@ static void lg_notify(struct virtqueue *vq)
 *
 * So we provide devices with a "find virtqueue and set it up" function. */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
				    unsigned index,
				    bool (*callback)(struct virtqueue *vq))
{
	struct lguest_device *ldev = to_lgdev(vdev);
	struct lguest_vq_info *lvq;
	struct virtqueue *vq;
	unsigned int len;
	void *token;
	int err;

	/* Look for a field of the correct type to mark a virtqueue.  Note that
	 * if this succeeds, then the type will be changed so it won't be found
	 * again, and future lg_find_vq() calls will find the next
	 * virtqueue (if any). */
	token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
	if (!token)
	/* We must have this many virtqueues. */
	if (index >= ldev->desc->num_vq)
		return ERR_PTR(-ENOENT);

	lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
	if (!lvq)
		return ERR_PTR(-ENOMEM);

	/* Note: we could use a configuration space inside here, just like we
	 * do for the device.  This would allow expansion in future, because
	 * our configuration system is designed to be expansible.  But this is
	 * way easier. */
	if (len != sizeof(lvq->config)) {
		dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
		err = -EIO;
		goto free_lvq;
	}
	/* Make a copy of the "struct lguest_vqconfig" field.  We need a copy
	 * because the config space might not be aligned correctly. */
	vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
	/* Make a copy of the "struct lguest_vqconfig" entry, which sits after
	 * the descriptor.  We need a copy because the config space might not
	 * be aligned correctly. */
	memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));

	printk("Mapping virtqueue %i addr %lx\n", index,
	       (unsigned long)lvq->config.pfn << PAGE_SHIFT);
	/* Figure out how many pages the ring will take, and map that memory */
	lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
				DIV_ROUND_UP(vring_size(lvq->config.num,
@@ -259,7 +274,7 @@ static void lg_del_vq(struct virtqueue *vq)

/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
	.find = lg_find,
	.feature = lg_feature,
	.get = lg_get,
	.set = lg_set,
	.get_status = lg_get_status,
@@ -329,13 +344,14 @@ static void scan_devices(void)
	struct lguest_device_desc *d;

	/* We start at the page beginning, and skip over each entry. */
	for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) {
	for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
		d = lguest_devices + i;

		/* Once we hit a zero, stop. */
		if (d->type == 0)
			break;

		printk("Device at %i has size %u\n", i, desc_size(d));
		add_lguest_device(d);
	}
}
+11 −14
Original line number Diff line number Diff line
@@ -311,10 +311,8 @@ static int virtnet_close(struct net_device *dev)
static int virtnet_probe(struct virtio_device *vdev)
{
	int err;
	unsigned int len;
	struct net_device *dev;
	struct virtnet_info *vi;
	void *token;

	/* Allocate ourselves a network device with room for our info */
	dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -330,25 +328,24 @@ static int virtnet_probe(struct virtio_device *vdev)
	SET_NETDEV_DEV(dev, &vdev->dev);

	/* Do we support "hardware" checksums? */
	token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len);
	if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) {
	if (vdev->config->feature(vdev, VIRTIO_NET_F_NO_CSUM)) {
		/* This opens up the world of extra features. */
		dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
		if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4))
		if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO4))
			dev->features |= NETIF_F_TSO;
		if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO))
		if (vdev->config->feature(vdev, VIRTIO_NET_F_UFO))
			dev->features |= NETIF_F_UFO;
		if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN))
		if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO4_ECN))
			dev->features |= NETIF_F_TSO_ECN;
		if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6))
		if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO6))
			dev->features |= NETIF_F_TSO6;
	}

	/* Configuration may specify what MAC to use.  Otherwise random. */
	token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len);
	if (token) {
		dev->addr_len = len;
		vdev->config->get(vdev, token, dev->dev_addr, len);
	if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
		vdev->config->get(vdev,
				  offsetof(struct virtio_net_config, mac),
				  dev->dev_addr, dev->addr_len);
	} else
		random_ether_addr(dev->dev_addr);

@@ -359,13 +356,13 @@ static int virtnet_probe(struct virtio_device *vdev)
	vi->vdev = vdev;

	/* We expect two virtqueues, receive then send. */
	vi->rvq = vdev->config->find_vq(vdev, skb_recv_done);
	vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
	if (IS_ERR(vi->rvq)) {
		err = PTR_ERR(vi->rvq);
		goto free;
	}

	vi->svq = vdev->config->find_vq(vdev, skb_xmit_done);
	vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
	if (IS_ERR(vi->svq)) {
		err = PTR_ERR(vi->svq);
		goto free_recv;
Loading