Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16ffc3ee authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-virtio:
  virtio: enhance id_matching for virtio drivers
  virtio: fix id_matching for virtio drivers
  virtio: handle short buffers in virtio_rng.
  virtio_blk: add missing __dev{init,exit} markings
  virtio: indirect ring entries (VIRTIO_RING_F_INDIRECT_DESC)
  virtio: teach virtio_has_feature() about transport features
  virtio: expose features in sysfs
  virtio_pci: optional MSI-X support
  virtio_pci: split up vp_interrupt
  virtio: find_vqs/del_vqs virtio operations
  virtio: add names to virtqueue struct, mapping from devices to queues.
  virtio: meet virtio spec by finalizing features before using device
  virtio: fix obsolete documentation on probe function
parents c34752bc e3353853
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ static int index_to_minor(int index)
	return index << PART_BITS;
}

static int virtblk_probe(struct virtio_device *vdev)
static int __devinit virtblk_probe(struct virtio_device *vdev)
{
	struct virtio_blk *vblk;
	int err;
@@ -288,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev)
	sg_init_table(vblk->sg, vblk->sg_elems);

	/* We expect one virtqueue, for output. */
	vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
	vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
	if (IS_ERR(vblk->vq)) {
		err = PTR_ERR(vblk->vq);
		goto out_free_vblk;
@@ -388,14 +388,14 @@ out_put_disk:
out_mempool:
	mempool_destroy(vblk->pool);
out_free_vq:
	vdev->config->del_vq(vblk->vq);
	vdev->config->del_vqs(vdev);
out_free_vblk:
	kfree(vblk);
out:
	return err;
}

static void virtblk_remove(struct virtio_device *vdev)
static void __devexit virtblk_remove(struct virtio_device *vdev)
{
	struct virtio_blk *vblk = vdev->priv;

@@ -409,7 +409,7 @@ static void virtblk_remove(struct virtio_device *vdev)
	blk_cleanup_queue(vblk->disk->queue);
	put_disk(vblk->disk);
	mempool_destroy(vblk->pool);
	vdev->config->del_vq(vblk->vq);
	vdev->config->del_vqs(vdev);
	kfree(vblk);
}

+19 −11
Original line number Diff line number Diff line
@@ -35,13 +35,13 @@ static DECLARE_COMPLETION(have_data);

static void random_recv_done(struct virtqueue *vq)
{
	int len;
	unsigned int len;

	/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
	if (!vq->vq_ops->get_buf(vq, &len))
		return;

	data_left = len / sizeof(random_data[0]);
	data_left += len;
	complete(&have_data);
}

@@ -49,7 +49,7 @@ static void register_buffer(void)
{
	struct scatterlist sg;

	sg_init_one(&sg, random_data, RANDOM_DATA_SIZE);
	sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left);
	/* There should always be room for one buffer. */
	if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0)
		BUG();
@@ -59,24 +59,32 @@ static void register_buffer(void)
/* At least we don't udelay() in a loop like some other drivers. */
static int virtio_data_present(struct hwrng *rng, int wait)
{
	if (data_left)
	if (data_left >= sizeof(u32))
		return 1;

again:
	if (!wait)
		return 0;

	wait_for_completion(&have_data);

	/* Not enough?  Re-register. */
	if (unlikely(data_left < sizeof(u32))) {
		register_buffer();
		goto again;
	}

	return 1;
}

/* virtio_data_present() must have succeeded before this is called. */
static int virtio_data_read(struct hwrng *rng, u32 *data)
{
	BUG_ON(!data_left);

	*data = random_data[--data_left];
	BUG_ON(data_left < sizeof(u32));
	data_left -= sizeof(u32);
	*data = random_data[data_left / 4];

	if (!data_left) {
	if (data_left < sizeof(u32)) {
		init_completion(&have_data);
		register_buffer();
	}
@@ -94,13 +102,13 @@ static int virtrng_probe(struct virtio_device *vdev)
	int err;

	/* We expect a single virtqueue. */
	vq = vdev->config->find_vq(vdev, 0, random_recv_done);
	vq = virtio_find_single_vq(vdev, random_recv_done, "input");
	if (IS_ERR(vq))
		return PTR_ERR(vq);

	err = hwrng_register(&virtio_hwrng);
	if (err) {
		vdev->config->del_vq(vq);
		vdev->config->del_vqs(vdev);
		return err;
	}

@@ -112,7 +120,7 @@ static void virtrng_remove(struct virtio_device *vdev)
{
	vdev->config->reset(vdev);
	hwrng_unregister(&virtio_hwrng);
	vdev->config->del_vq(vq);
	vdev->config->del_vqs(vdev);
}

static struct virtio_device_id id_table[] = {
+11 −15
Original line number Diff line number Diff line
@@ -188,6 +188,9 @@ static void hvc_handle_input(struct virtqueue *vq)
 * Finally we put our input buffer in the input queue, ready to receive. */
static int __devinit virtcons_probe(struct virtio_device *dev)
{
	vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
	const char *names[] = { "input", "output" };
	struct virtqueue *vqs[2];
	int err;

	vdev = dev;
@@ -199,20 +202,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
		goto fail;
	}

	/* Find the input queue. */
	/* Find the queues. */
	/* FIXME: This is why we want to wean off hvc: we do nothing
	 * when input comes in. */
	in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input);
	if (IS_ERR(in_vq)) {
		err = PTR_ERR(in_vq);
	err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
	if (err)
		goto free;
	}

	out_vq = vdev->config->find_vq(vdev, 1, NULL);
	if (IS_ERR(out_vq)) {
		err = PTR_ERR(out_vq);
		goto free_in_vq;
	}
	in_vq = vqs[0];
	out_vq = vqs[1];

	/* Start using the new console output. */
	virtio_cons.get_chars = get_chars;
@@ -233,17 +231,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
	hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
	if (IS_ERR(hvc)) {
		err = PTR_ERR(hvc);
		goto free_out_vq;
		goto free_vqs;
	}

	/* Register the input buffer the first time. */
	add_inbuf();
	return 0;

free_out_vq:
	vdev->config->del_vq(out_vq);
free_in_vq:
	vdev->config->del_vq(in_vq);
free_vqs:
	vdev->config->del_vqs(vdev);
free:
	kfree(inbuf);
fail:
+37 −4
Original line number Diff line number Diff line
@@ -228,7 +228,8 @@ extern void lguest_setup_irq(unsigned int irq);
 * function. */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
				    unsigned index,
				    void (*callback)(struct virtqueue *vq))
				    void (*callback)(struct virtqueue *vq),
				    const char *name)
{
	struct lguest_device *ldev = to_lgdev(vdev);
	struct lguest_vq_info *lvq;
@@ -263,7 +264,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
	/* OK, tell virtio_ring.c to set up a virtqueue now we know its size
	 * and we've got a pointer to its pages. */
	vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
				 vdev, lvq->pages, lg_notify, callback);
				 vdev, lvq->pages, lg_notify, callback, name);
	if (!vq) {
		err = -ENOMEM;
		goto unmap;
@@ -312,6 +313,38 @@ static void lg_del_vq(struct virtqueue *vq)
	kfree(lvq);
}

static void lg_del_vqs(struct virtio_device *vdev)
{
	struct virtqueue *vq, *n;

	list_for_each_entry_safe(vq, n, &vdev->vqs, list)
		lg_del_vq(vq);
}

static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
		       struct virtqueue *vqs[],
		       vq_callback_t *callbacks[],
		       const char *names[])
{
	struct lguest_device *ldev = to_lgdev(vdev);
	int i;

	/* We must have this many virtqueues. */
	if (nvqs > ldev->desc->num_vq)
		return -ENOENT;

	for (i = 0; i < nvqs; ++i) {
		vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
		if (IS_ERR(vqs[i]))
			goto error;
	}
	return 0;

error:
	lg_del_vqs(vdev);
	return PTR_ERR(vqs[i]);
}

/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
	.get_features = lg_get_features,
@@ -321,8 +354,8 @@ static struct virtio_config_ops lguest_config_ops = {
	.get_status = lg_get_status,
	.set_status = lg_set_status,
	.reset = lg_reset,
	.find_vq = lg_find_vq,
	.del_vq = lg_del_vq,
	.find_vqs = lg_find_vqs,
	.del_vqs = lg_del_vqs,
};

/* The root device for the lguest virtio devices.  This makes them appear as
+18 −27
Original line number Diff line number Diff line
@@ -845,6 +845,10 @@ static int virtnet_probe(struct virtio_device *vdev)
	int err;
	struct net_device *dev;
	struct virtnet_info *vi;
	struct virtqueue *vqs[3];
	vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
	const char *names[] = { "input", "output", "control" };
	int nvqs;

	/* Allocate ourselves a network device with room for our info */
	dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -905,25 +909,19 @@ static int virtnet_probe(struct virtio_device *vdev)
	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
		vi->mergeable_rx_bufs = true;

	/* We expect two virtqueues, receive then send. */
	vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
	if (IS_ERR(vi->rvq)) {
		err = PTR_ERR(vi->rvq);
	/* We expect two virtqueues, receive then send,
	 * and optionally control. */
	nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;

	err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
	if (err)
		goto free;
	}

	vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
	if (IS_ERR(vi->svq)) {
		err = PTR_ERR(vi->svq);
		goto free_recv;
	}
	vi->rvq = vqs[0];
	vi->svq = vqs[1];

	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
		vi->cvq = vdev->config->find_vq(vdev, 2, NULL);
		if (IS_ERR(vi->cvq)) {
			err = PTR_ERR(vi->svq);
			goto free_send;
		}
		vi->cvq = vqs[2];

		if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
			dev->features |= NETIF_F_HW_VLAN_FILTER;
@@ -941,7 +939,7 @@ static int virtnet_probe(struct virtio_device *vdev)
	err = register_netdev(dev);
	if (err) {
		pr_debug("virtio_net: registering device failed\n");
		goto free_ctrl;
		goto free_vqs;
	}

	/* Last of all, set up some receive buffers. */
@@ -962,13 +960,8 @@ static int virtnet_probe(struct virtio_device *vdev)

unregister:
	unregister_netdev(dev);
free_ctrl:
	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
		vdev->config->del_vq(vi->cvq);
free_send:
	vdev->config->del_vq(vi->svq);
free_recv:
	vdev->config->del_vq(vi->rvq);
free_vqs:
	vdev->config->del_vqs(vdev);
free:
	free_netdev(dev);
	return err;
@@ -994,12 +987,10 @@ static void virtnet_remove(struct virtio_device *vdev)

	BUG_ON(vi->num != 0);

	vdev->config->del_vq(vi->svq);
	vdev->config->del_vq(vi->rvq);
	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
		vdev->config->del_vq(vi->cvq);
	unregister_netdev(vi->dev);

	vdev->config->del_vqs(vi->vdev);

	while (vi->pages)
		__free_pages(get_a_page(vi, GFP_KERNEL), 0);

Loading