Commit 9499f5e7 authored by Rusty Russell's avatar Rusty Russell

virtio: add names to virtqueue struct, mapping from devices to queues.

Add a linked list of all virtqueues for a virtio device: this helps for
debugging and is also needed for upcoming interface change.

Also, add a "name" field for clearer debug messages.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent ef688e15
...@@ -288,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -288,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev)
sg_init_table(vblk->sg, vblk->sg_elems); sg_init_table(vblk->sg, vblk->sg_elems);
/* We expect one virtqueue, for output. */ /* We expect one virtqueue, for output. */
vblk->vq = vdev->config->find_vq(vdev, 0, blk_done); vblk->vq = vdev->config->find_vq(vdev, 0, blk_done, "requests");
if (IS_ERR(vblk->vq)) { if (IS_ERR(vblk->vq)) {
err = PTR_ERR(vblk->vq); err = PTR_ERR(vblk->vq);
goto out_free_vblk; goto out_free_vblk;
......
...@@ -94,7 +94,7 @@ static int virtrng_probe(struct virtio_device *vdev) ...@@ -94,7 +94,7 @@ static int virtrng_probe(struct virtio_device *vdev)
int err; int err;
/* We expect a single virtqueue. */ /* We expect a single virtqueue. */
vq = vdev->config->find_vq(vdev, 0, random_recv_done); vq = vdev->config->find_vq(vdev, 0, random_recv_done, "input");
if (IS_ERR(vq)) if (IS_ERR(vq))
return PTR_ERR(vq); return PTR_ERR(vq);
......
...@@ -202,13 +202,13 @@ static int __devinit virtcons_probe(struct virtio_device *dev) ...@@ -202,13 +202,13 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Find the input queue. */ /* Find the input queue. */
/* FIXME: This is why we want to wean off hvc: we do nothing /* FIXME: This is why we want to wean off hvc: we do nothing
* when input comes in. */ * when input comes in. */
in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input); in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input, "input");
if (IS_ERR(in_vq)) { if (IS_ERR(in_vq)) {
err = PTR_ERR(in_vq); err = PTR_ERR(in_vq);
goto free; goto free;
} }
out_vq = vdev->config->find_vq(vdev, 1, NULL); out_vq = vdev->config->find_vq(vdev, 1, NULL, "output");
if (IS_ERR(out_vq)) { if (IS_ERR(out_vq)) {
err = PTR_ERR(out_vq); err = PTR_ERR(out_vq);
goto free_in_vq; goto free_in_vq;
......
...@@ -228,7 +228,8 @@ extern void lguest_setup_irq(unsigned int irq); ...@@ -228,7 +228,8 @@ extern void lguest_setup_irq(unsigned int irq);
* function. */ * function. */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev, static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *vq)) void (*callback)(struct virtqueue *vq),
const char *name)
{ {
struct lguest_device *ldev = to_lgdev(vdev); struct lguest_device *ldev = to_lgdev(vdev);
struct lguest_vq_info *lvq; struct lguest_vq_info *lvq;
...@@ -263,7 +264,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, ...@@ -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 /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
* and we've got a pointer to its pages. */ * and we've got a pointer to its pages. */
vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, 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) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
goto unmap; goto unmap;
......
...@@ -906,20 +906,20 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -906,20 +906,20 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->mergeable_rx_bufs = true; vi->mergeable_rx_bufs = true;
/* We expect two virtqueues, receive then send. */ /* We expect two virtqueues, receive then send. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done, "input");
if (IS_ERR(vi->rvq)) { if (IS_ERR(vi->rvq)) {
err = PTR_ERR(vi->rvq); err = PTR_ERR(vi->rvq);
goto free; goto free;
} }
vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done); vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done, "output");
if (IS_ERR(vi->svq)) { if (IS_ERR(vi->svq)) {
err = PTR_ERR(vi->svq); err = PTR_ERR(vi->svq);
goto free_recv; goto free_recv;
} }
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
vi->cvq = vdev->config->find_vq(vdev, 2, NULL); vi->cvq = vdev->config->find_vq(vdev, 2, NULL, "control");
if (IS_ERR(vi->cvq)) { if (IS_ERR(vi->cvq)) {
err = PTR_ERR(vi->svq); err = PTR_ERR(vi->svq);
goto free_send; goto free_send;
......
...@@ -174,7 +174,8 @@ static void kvm_notify(struct virtqueue *vq) ...@@ -174,7 +174,8 @@ static void kvm_notify(struct virtqueue *vq)
*/ */
static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *vq)) void (*callback)(struct virtqueue *vq),
const char *name)
{ {
struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_device *kdev = to_kvmdev(vdev);
struct kvm_vqconfig *config; struct kvm_vqconfig *config;
...@@ -194,7 +195,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, ...@@ -194,7 +195,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
vdev, (void *) config->address, vdev, (void *) config->address,
kvm_notify, callback); kvm_notify, callback, name);
if (!vq) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
goto unmap; goto unmap;
......
...@@ -186,6 +186,8 @@ int register_virtio_device(struct virtio_device *dev) ...@@ -186,6 +186,8 @@ int register_virtio_device(struct virtio_device *dev)
/* Acknowledge that we've seen the device. */ /* Acknowledge that we've seen the device. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
INIT_LIST_HEAD(&dev->vqs);
/* device_register() causes the bus infrastructure to look for a /* device_register() causes the bus infrastructure to look for a
* matching driver. */ * matching driver. */
err = device_register(&dev->dev); err = device_register(&dev->dev);
......
...@@ -218,13 +218,13 @@ static int virtballoon_probe(struct virtio_device *vdev) ...@@ -218,13 +218,13 @@ static int virtballoon_probe(struct virtio_device *vdev)
vb->vdev = vdev; vb->vdev = vdev;
/* We expect two virtqueues. */ /* We expect two virtqueues. */
vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack); vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack, "inflate");
if (IS_ERR(vb->inflate_vq)) { if (IS_ERR(vb->inflate_vq)) {
err = PTR_ERR(vb->inflate_vq); err = PTR_ERR(vb->inflate_vq);
goto out_free_vb; goto out_free_vb;
} }
vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack); vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack, "deflate");
if (IS_ERR(vb->deflate_vq)) { if (IS_ERR(vb->deflate_vq)) {
err = PTR_ERR(vb->deflate_vq); err = PTR_ERR(vb->deflate_vq);
goto out_del_inflate_vq; goto out_del_inflate_vq;
......
...@@ -208,7 +208,8 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) ...@@ -208,7 +208,8 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)
/* the config->find_vq() implementation */ /* the config->find_vq() implementation */
static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
void (*callback)(struct virtqueue *vq)) void (*callback)(struct virtqueue *vq),
const char *name)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtio_pci_vq_info *info; struct virtio_pci_vq_info *info;
...@@ -247,7 +248,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, ...@@ -247,7 +248,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
/* create the vring */ /* create the vring */
vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
vdev, info->queue, vp_notify, callback); vdev, info->queue, vp_notify, callback, name);
if (!vq) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
goto out_activate_queue; goto out_activate_queue;
......
...@@ -23,21 +23,30 @@ ...@@ -23,21 +23,30 @@
#ifdef DEBUG #ifdef DEBUG
/* For development, we want to crash whenever the ring is screwed. */ /* For development, we want to crash whenever the ring is screwed. */
#define BAD_RING(_vq, fmt...) \ #define BAD_RING(_vq, fmt, args...) \
do { dev_err(&(_vq)->vq.vdev->dev, fmt); BUG(); } while(0) do { \
dev_err(&(_vq)->vq.vdev->dev, \
"%s:"fmt, (_vq)->vq.name, ##args); \
BUG(); \
} while (0)
/* Caller is supposed to guarantee no reentry. */ /* Caller is supposed to guarantee no reentry. */
#define START_USE(_vq) \ #define START_USE(_vq) \
do { \ do { \
if ((_vq)->in_use) \ if ((_vq)->in_use) \
panic("in_use = %i\n", (_vq)->in_use); \ panic("%s:in_use = %i\n", \
(_vq)->vq.name, (_vq)->in_use); \
(_vq)->in_use = __LINE__; \ (_vq)->in_use = __LINE__; \
mb(); \ mb(); \
} while(0) } while (0)
#define END_USE(_vq) \ #define END_USE(_vq) \
do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0) do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
#else #else
#define BAD_RING(_vq, fmt...) \ #define BAD_RING(_vq, fmt, args...) \
do { dev_err(&_vq->vq.vdev->dev, fmt); (_vq)->broken = true; } while(0) do { \
dev_err(&_vq->vq.vdev->dev, \
"%s:"fmt, (_vq)->vq.name, ##args); \
(_vq)->broken = true; \
} while (0)
#define START_USE(vq) #define START_USE(vq)
#define END_USE(vq) #define END_USE(vq)
#endif #endif
...@@ -284,7 +293,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, ...@@ -284,7 +293,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
struct virtio_device *vdev, struct virtio_device *vdev,
void *pages, void *pages,
void (*notify)(struct virtqueue *), void (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *)) void (*callback)(struct virtqueue *),
const char *name)
{ {
struct vring_virtqueue *vq; struct vring_virtqueue *vq;
unsigned int i; unsigned int i;
...@@ -303,10 +313,12 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, ...@@ -303,10 +313,12 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
vq->vq.callback = callback; vq->vq.callback = callback;
vq->vq.vdev = vdev; vq->vq.vdev = vdev;
vq->vq.vq_ops = &vring_vq_ops; vq->vq.vq_ops = &vring_vq_ops;
vq->vq.name = name;
vq->notify = notify; vq->notify = notify;
vq->broken = false; vq->broken = false;
vq->last_used_idx = 0; vq->last_used_idx = 0;
vq->num_added = 0; vq->num_added = 0;
list_add_tail(&vq->vq.list, &vdev->vqs);
#ifdef DEBUG #ifdef DEBUG
vq->in_use = false; vq->in_use = false;
#endif #endif
...@@ -327,6 +339,7 @@ EXPORT_SYMBOL_GPL(vring_new_virtqueue); ...@@ -327,6 +339,7 @@ EXPORT_SYMBOL_GPL(vring_new_virtqueue);
void vring_del_virtqueue(struct virtqueue *vq) void vring_del_virtqueue(struct virtqueue *vq)
{ {
list_del(&vq->list);
kfree(to_vvq(vq)); kfree(to_vvq(vq));
} }
EXPORT_SYMBOL_GPL(vring_del_virtqueue); EXPORT_SYMBOL_GPL(vring_del_virtqueue);
......
...@@ -10,14 +10,17 @@ ...@@ -10,14 +10,17 @@
/** /**
* virtqueue - a queue to register buffers for sending or receiving. * virtqueue - a queue to register buffers for sending or receiving.
* @list: the chain of virtqueues for this device
* @callback: the function to call when buffers are consumed (can be NULL). * @callback: the function to call when buffers are consumed (can be NULL).
* @name: the name of this virtqueue (mainly for debugging)
* @vdev: the virtio device this queue was created for. * @vdev: the virtio device this queue was created for.
* @vq_ops: the operations for this virtqueue (see below). * @vq_ops: the operations for this virtqueue (see below).
* @priv: a pointer for the virtqueue implementation to use. * @priv: a pointer for the virtqueue implementation to use.
*/ */
struct virtqueue struct virtqueue {
{ struct list_head list;
void (*callback)(struct virtqueue *vq); void (*callback)(struct virtqueue *vq);
const char *name;
struct virtio_device *vdev; struct virtio_device *vdev;
struct virtqueue_ops *vq_ops; struct virtqueue_ops *vq_ops;
void *priv; void *priv;
...@@ -76,15 +79,16 @@ struct virtqueue_ops { ...@@ -76,15 +79,16 @@ struct virtqueue_ops {
* @dev: underlying device. * @dev: underlying device.
* @id: the device type identification (used to match it with a driver). * @id: the device type identification (used to match it with a driver).
* @config: the configuration ops for this device. * @config: the configuration ops for this device.
* @vqs: the list of virtqueues for this device.
* @features: the features supported by both driver and device. * @features: the features supported by both driver and device.
* @priv: private pointer for the driver's use. * @priv: private pointer for the driver's use.
*/ */
struct virtio_device struct virtio_device {
{
int index; int index;
struct device dev; struct device dev;
struct virtio_device_id id; struct virtio_device_id id;
struct virtio_config_ops *config; struct virtio_config_ops *config;
struct list_head vqs;
/* Note that this is a Linux set_bit-style bitmap. */ /* Note that this is a Linux set_bit-style bitmap. */
unsigned long features[1]; unsigned long features[1];
void *priv; void *priv;
......
...@@ -55,7 +55,8 @@ ...@@ -55,7 +55,8 @@
* @find_vq: find a virtqueue and instantiate it. * @find_vq: find a virtqueue and instantiate it.
* vdev: the virtio_device * vdev: the virtio_device
* index: the 0-based virtqueue number in case there's more than one. * index: the 0-based virtqueue number in case there's more than one.
* callback: the virqtueue callback * callback: the virtqueue callback
* name: the virtqueue name (mainly for debugging)
* Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
* @del_vq: free a virtqueue found by find_vq(). * @del_vq: free a virtqueue found by find_vq().
* @get_features: get the array of feature bits for this device. * @get_features: get the array of feature bits for this device.
...@@ -77,7 +78,8 @@ struct virtio_config_ops ...@@ -77,7 +78,8 @@ struct virtio_config_ops
void (*reset)(struct virtio_device *vdev); void (*reset)(struct virtio_device *vdev);
struct virtqueue *(*find_vq)(struct virtio_device *vdev, struct virtqueue *(*find_vq)(struct virtio_device *vdev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *)); void (*callback)(struct virtqueue *),
const char *name);
void (*del_vq)(struct virtqueue *vq); void (*del_vq)(struct virtqueue *vq);
u32 (*get_features)(struct virtio_device *vdev); u32 (*get_features)(struct virtio_device *vdev);
void (*finalize_features)(struct virtio_device *vdev); void (*finalize_features)(struct virtio_device *vdev);
......
...@@ -119,7 +119,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, ...@@ -119,7 +119,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
struct virtio_device *vdev, struct virtio_device *vdev,
void *pages, void *pages,
void (*notify)(struct virtqueue *vq), void (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq)); void (*callback)(struct virtqueue *vq),
const char *name);
void vring_del_virtqueue(struct virtqueue *vq); void vring_del_virtqueue(struct virtqueue *vq);
/* Filter out transport-specific feature bits. */ /* Filter out transport-specific feature bits. */
void vring_transport_features(struct virtio_device *vdev); void vring_transport_features(struct virtio_device *vdev);
......
...@@ -246,7 +246,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) ...@@ -246,7 +246,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
chan->vdev = vdev; chan->vdev = vdev;
/* We expect one virtqueue, for requests. */ /* We expect one virtqueue, for requests. */
chan->vq = vdev->config->find_vq(vdev, 0, req_done); chan->vq = vdev->config->find_vq(vdev, 0, req_done, "requests");
if (IS_ERR(chan->vq)) { if (IS_ERR(chan->vq)) {
err = PTR_ERR(chan->vq); err = PTR_ERR(chan->vq);
goto out_free_vq; goto out_free_vq;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment