Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-v…
Browse files Browse the repository at this point in the history
…irtio

* 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
  • Loading branch information
torvalds committed Jun 12, 2009
2 parents c34752b + e335385 commit 16ffc3e
Show file tree
Hide file tree
Showing 16 changed files with 592 additions and 158 deletions.
10 changes: 5 additions & 5 deletions drivers/block/virtio_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -388,14 +388,14 @@ static int virtblk_probe(struct virtio_device *vdev)
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;

Expand All @@ -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);
}

Expand Down
30 changes: 19 additions & 11 deletions drivers/char/hw_random/virtio-rng.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ 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);
}

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();
Expand All @@ -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();
}
Expand All @@ -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;
}

Expand All @@ -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[] = {
Expand Down
26 changes: 11 additions & 15 deletions drivers/char/virtio_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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:
Expand Down
41 changes: 37 additions & 4 deletions drivers/lguest/lguest_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
45 changes: 18 additions & 27 deletions drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand All @@ -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. */
Expand All @@ -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;
Expand All @@ -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);

Expand Down
Loading

0 comments on commit 16ffc3e

Please sign in to comment.