virtio: add request_vqs/free_vqs operations
Subsystems (11)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Michael S. Tsirkin
maintainerPATCH 1/8 virtio: add request_vqs/free_vqs operations
This adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
--- include/linux/virtio_config.h | 35 +++++++++++++++++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 deletions(-)
include/linux/virtio_config.h +35 -0
@@ -49,6 +49,15 @@* @set_status: write the status byte * vdev: the virtio_device * status: the new status byte +* @request_vqs: request the specified number of virtqueues +* vdev: the virtio_device +* max_vqs: the max number of virtqueues we want +* If supplied, must call before any virtqueues are instantiated. +* To modify the max number of virtqueues after request_vqs has been +* called, call free_vqs and then request_vqs with a new value. +* @free_vqs: cleanup resources allocated by request_vqs +* vdev: the virtio_device +* If supplied, must call after all virtqueues have been deleted. * @reset: reset the device * vdev: the virtio device * After this, status and feature negotiation must be done again
@@ -75,6 +84,8 @@ struct virtio_config_opsu8 (*get_status)(struct virtio_device *vdev);void (*set_status)(struct virtio_device *vdev,u8 status);void (*reset)(struct virtio_device *vdev); +int (*request_vqs)(struct virtio_device *vdev,unsigned max_vqs); +void (*free_vqs)(struct virtio_device *vdev);struct virtqueue *(*find_vq)(struct virtio_device *vdev,unsigned index,void (*callback)(struct virtqueue *));
@@ -126,5 +137,29 @@ static inline int virtio_config_buf(struct virtio_device *vdev, vdev->config->get (vdev, offset, buf, len);return 0 ; } + +/** +* virtio_request_vqs: request the specified number of virtqueues +* @vdev: the virtio_device +* @max_vqs: the max number of virtqueues we want +* +* For details, see documentation for request_vqs above. */ +static inline int virtio_request_vqs (struct virtio_device *vdev, +unsigned max_vqs) +{ +return vdev->config->request_vqs ? + vdev->config->request_vqs (vdev, max_vqs) :0 ; +} + +/** +* free_vqs: cleanup resources allocated by virtio_request_vqs +* @vdev: the virtio_device +* +* For details, see documentation for free_vqs above. */ +static inline void virtio_free_vqs (struct virtio_device *vdev) +{ +if (vdev->config->free_vqs) + vdev->config->free_vqs (vdev); +}#endif /* __KERNEL__ */ #endif /* _LINUX_VIRTIO_CONFIG_H */
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 1/8 virtio: add request_vqs/free_vqs operations
In reply to a message not in the archiveThis adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
--- include/linux/virtio_config.h | 35 +++++++++++++++++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 deletions(-)
include/linux/virtio_config.h +35 -0
@@ -49,6 +49,15 @@* @set_status: write the status byte * vdev: the virtio_device * status: the new status byte +* @request_vqs: request the specified number of virtqueues +* vdev: the virtio_device +* max_vqs: the max number of virtqueues we want +* If supplied, must call before any virtqueues are instantiated. +* To modify the max number of virtqueues after request_vqs has been +* called, call free_vqs and then request_vqs with a new value. +* @free_vqs: cleanup resources allocated by request_vqs +* vdev: the virtio_device +* If supplied, must call after all virtqueues have been deleted. * @reset: reset the device * vdev: the virtio device * After this, status and feature negotiation must be done again
@@ -75,6 +84,8 @@ struct virtio_config_opsu8 (*get_status)(struct virtio_device *vdev);void (*set_status)(struct virtio_device *vdev,u8 status);void (*reset)(struct virtio_device *vdev); +int (*request_vqs)(struct virtio_device *vdev,unsigned max_vqs); +void (*free_vqs)(struct virtio_device *vdev);struct virtqueue *(*find_vq)(struct virtio_device *vdev,unsigned index,void (*callback)(struct virtqueue *));
@@ -126,5 +137,29 @@ static inline int virtio_config_buf(struct virtio_device *vdev, vdev->config->get (vdev, offset, buf, len);return 0 ; } + +/** +* virtio_request_vqs: request the specified number of virtqueues +* @vdev: the virtio_device +* @max_vqs: the max number of virtqueues we want +* +* For details, see documentation for request_vqs above. */ +static inline int virtio_request_vqs (struct virtio_device *vdev, +unsigned max_vqs) +{ +return vdev->config->request_vqs ? + vdev->config->request_vqs (vdev, max_vqs) :0 ; +} + +/** +* free_vqs: cleanup resources allocated by virtio_request_vqs +* @vdev: the virtio_device +* +* For details, see documentation for free_vqs above. */ +static inline void virtio_free_vqs (struct virtio_device *vdev) +{ +if (vdev->config->free_vqs) + vdev->config->free_vqs (vdev); +}#endif /* __KERNEL__ */ #endif /* _LINUX_VIRTIO_CONFIG_H */
Signature · 1 line
1.6.0.6
Quoted 5 lines · Michael S. Tsirkin
This adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
Signed-off-by Michael S. Tsirkin <[email protected]>
Hi Michael,
Thanks for this work! But this interface is horrible. Either probe for the
number of vqs in virtio_pci, or change find_vq to
int (*find_vqs)(struct virtio_device *, unsigned max, struct virtqueue *vqs[]);
Thanks,
Rusty.
Quoted 5 lines · Michael S. Tsirkin
This adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
Signed-off-by Michael S. Tsirkin <[email protected]>
Hi Michael,
Thanks for this work! But this interface is horrible. Either probe for the
number of vqs in virtio_pci, or change find_vq to
int (*find_vqs)(struct virtio_device *, unsigned max, struct virtqueue *vqs[]);
Thanks,
Rusty.
Michael S. Tsirkin
maintainerQuoted 8 lines · Rusty Russell
Quoted 5 lines · Michael S. Tsirkin
This adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
Signed-off-by Michael S. Tsirkin <[email protected]>Hi Michael,
Hi Rusty,
Quoted 5 lines
Thanks for this work! But this interface is horrible. Either probe for the
number of vqs invirtio_pci, or changefind_vqtoint (*find_vqs)(struct virtio_device *, unsigned max, struct virtqueue *vqs[]);
I'm happier with the later option: it's easy for a host to expose support for a very large number of vqs, and I don't want them to waste resources if guest does not use them.
Thanks for the feedback!
Quoted 2 lines
Thanks,
Rusty.
Signature · 1 line
MST
Michael S. Tsirkin
maintainerQuoted 8 lines · Rusty Russell
Quoted 5 lines · Michael S. Tsirkin
This adds 2 new optional virtio operations: request_vqs/free_vqs. They will be used for MSI support, because MSI needs to know the total number of vectors upfront.
Signed-off-by Michael S. Tsirkin <[email protected]>Hi Michael,
Hi Rusty,
Quoted 5 lines
Thanks for this work! But this interface is horrible. Either probe for the
number of vqs invirtio_pci, or changefind_vqtoint (*find_vqs)(struct virtio_device *, unsigned max, struct virtqueue *vqs[]);
I'm happier with the later option: it's easy for a host to expose support for a very large number of vqs, and I don't want them to waste resources if guest does not use them.
Thanks for the feedback!
Quoted 2 lines
Thanks,
Rusty.
Signature · 1 line
MST
Michael S. Tsirkin
maintainerPATCH 2/8 virtio_blk: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_blk.
These will be required for MSI support.
--- drivers/block/virtio_blk.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/block/virtio_blk.c +8 -1
@@ -224,10 +224,14 @@ static int virtblk_probe(struct virtio_device *vdev)sg_init_table (vblk->sg, vblk->sg_elems);/* We expect one virtqueue, for output. */ + err =virtio_request_vqs (vdev,1 ); +if (err) + goto out_free_vblk; + vblk->vq = vdev->config->find_vq (vdev,0 , blk_done);if (IS_ERR (vblk->vq)) { err =PTR_ERR (vblk->vq); - goto out_free_vblk; + goto out_free_vqs; } vblk->pool =mempool_create_kmalloc_pool (1 ,sizeof (struct virtblk_req ));
@@ -324,6 +328,8 @@ out_mempool:mempool_destroy (vblk->pool); out_free_vq: vdev->config->del_vq (vblk->vq); +out_free_vqs: +virtio_free_vqs (vdev); out_free_vblk:kfree (vblk); out:
@@ -345,6 +351,7 @@ static void virtblk_remove(struct virtio_device *vdev)put_disk (vblk->disk);mempool_destroy (vblk->pool); vdev->config->del_vq (vblk->vq); +virtio_free_vqs (vdev);kfree (vblk); }
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 2/8 virtio_blk: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_blk.
These will be required for MSI support.
--- drivers/block/virtio_blk.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/block/virtio_blk.c +8 -1
@@ -224,10 +224,14 @@ static int virtblk_probe(struct virtio_device *vdev)sg_init_table (vblk->sg, vblk->sg_elems);/* We expect one virtqueue, for output. */ + err =virtio_request_vqs (vdev,1 ); +if (err) + goto out_free_vblk; + vblk->vq = vdev->config->find_vq (vdev,0 , blk_done);if (IS_ERR (vblk->vq)) { err =PTR_ERR (vblk->vq); - goto out_free_vblk; + goto out_free_vqs; } vblk->pool =mempool_create_kmalloc_pool (1 ,sizeof (struct virtblk_req ));
@@ -324,6 +328,8 @@ out_mempool:mempool_destroy (vblk->pool); out_free_vq: vdev->config->del_vq (vblk->vq); +out_free_vqs: +virtio_free_vqs (vdev); out_free_vblk:kfree (vblk); out:
@@ -345,6 +351,7 @@ static void virtblk_remove(struct virtio_device *vdev)put_disk (vblk->disk);mempool_destroy (vblk->pool); vdev->config->del_vq (vblk->vq); +virtio_free_vqs (vdev);kfree (vblk); }
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 3/8 virtio-rng: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio-rng.
These will be required for MSI support.
--- drivers/char/hw_random/virtio-rng.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
drivers/char/hw_random/virtio-rng.c +9 -1
@@ -94,13 +94,20 @@ static int virtrng_probe(struct virtio_device *vdev)int err;/* We expect a single virtqueue. */ + err =virtio_request_vqs (vdev,1 ); +if (err) +return err; + vq = vdev->config->find_vq (vdev,0 , random_recv_done); -if (IS_ERR (vq)) +if (IS_ERR (vq)) { +virtio_free_vqs (vdev);return PTR_ERR (vq); + } err =hwrng_register (&virtio_hwrng);if (err) { vdev->config->del_vq (vq); +virtio_free_vqs (vdev);return err; }
@@ -113,6 +120,7 @@ static void virtrng_remove(struct virtio_device *vdev) vdev->config->reset (vdev);hwrng_unregister (&virtio_hwrng); vdev->config->del_vq (vq); +virtio_free_vqs (vdev); }static struct virtio_device_id id_table[] = {
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 3/8 virtio-rng: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio-rng.
These will be required for MSI support.
--- drivers/char/hw_random/virtio-rng.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)
drivers/char/hw_random/virtio-rng.c +9 -1
@@ -94,13 +94,20 @@ static int virtrng_probe(struct virtio_device *vdev)int err;/* We expect a single virtqueue. */ + err =virtio_request_vqs (vdev,1 ); +if (err) +return err; + vq = vdev->config->find_vq (vdev,0 , random_recv_done); -if (IS_ERR (vq)) +if (IS_ERR (vq)) { +virtio_free_vqs (vdev);return PTR_ERR (vq); + } err =hwrng_register (&virtio_hwrng);if (err) { vdev->config->del_vq (vq); +virtio_free_vqs (vdev);return err; }
@@ -113,6 +120,7 @@ static void virtrng_remove(struct virtio_device *vdev) vdev->config->reset (vdev);hwrng_unregister (&virtio_hwrng); vdev->config->del_vq (vq); +virtio_free_vqs (vdev); }static struct virtio_device_id id_table[] = {
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 4/8 virtio_console: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_console.
These will be required for MSI support.
--- drivers/char/virtio_console.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
drivers/char/virtio_console.c +7 -1
@@ -199,13 +199,17 @@ static int __devinit virtcons_probe(struct virtio_device *dev) goto fail; } + err =virtio_request_vqs (vdev,2 ); +if (err) + goto free; +/* 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,0 , hvc_handle_input);if (IS_ERR (in_vq)) { err =PTR_ERR (in_vq); - goto free; + goto free_vqs; } out_vq = vdev->config->find_vq (vdev,1 ,NULL );
@@ -244,6 +248,8 @@ free_out_vq: vdev->config->del_vq (out_vq); free_in_vq: vdev->config->del_vq (in_vq); +free_vqs: +virtio_free_vqs (vdev); free:kfree (inbuf); fail:
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 4/8 virtio_console: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_console.
These will be required for MSI support.
--- drivers/char/virtio_console.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
drivers/char/virtio_console.c +7 -1
@@ -199,13 +199,17 @@ static int __devinit virtcons_probe(struct virtio_device *dev) goto fail; } + err =virtio_request_vqs (vdev,2 ); +if (err) + goto free; +/* 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,0 , hvc_handle_input);if (IS_ERR (in_vq)) { err =PTR_ERR (in_vq); - goto free; + goto free_vqs; } out_vq = vdev->config->find_vq (vdev,1 ,NULL );
@@ -244,6 +248,8 @@ free_out_vq: vdev->config->del_vq (out_vq); free_in_vq: vdev->config->del_vq (in_vq); +free_vqs: +virtio_free_vqs (vdev); free:kfree (inbuf); fail:
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 5/8 virtio_net: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_net.
These will be required for MSI support.
--- drivers/net/virtio_net.c | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-)
drivers/net/virtio_net.c +13 -3
@@ -841,6 +841,7 @@ static int virtnet_probe(struct virtio_device *vdev)int err;struct net_device *dev;struct virtnet_info *vi; +bool control_vq;/* Allocate ourselves a network device with room for our info */ dev =alloc_etherdev (sizeof (struct virtnet_info ));
@@ -901,11 +902,17 @@ 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. */ +/* We expect either two or three virtqueues: receive, send and +* optionally control. */ + control_vq =virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ ); + err =virtio_request_vqs (vdev, control_vq ?3 :2 ); +if (err) + goto free; + vi->rvq = vdev->config->find_vq (vdev,0 , skb_recv_done);if (IS_ERR (vi->rvq)) { err =PTR_ERR (vi->rvq); - goto free; + goto free_vqs; } vi->svq = vdev->config->find_vq (vdev,1 , skb_xmit_done);
@@ -914,7 +921,7 @@ static int virtnet_probe(struct virtio_device *vdev) goto free_recv; } -if (virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ )) { +if (control_vq) { vi->cvq = vdev->config->find_vq (vdev,2 ,NULL );if (IS_ERR (vi->cvq)) { err =PTR_ERR (vi->svq);
@@ -965,6 +972,8 @@ free_send: vdev->config->del_vq (vi->svq); free_recv: vdev->config->del_vq (vi->rvq); +free_vqs: +virtio_free_vqs (vi->vdev); free:free_netdev (dev);return err;
@@ -994,6 +1003,7 @@ static void virtnet_remove(struct virtio_device *vdev) vdev->config->del_vq (vi->rvq);if (virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ )) vdev->config->del_vq (vi->cvq); +virtio_free_vqs (vi->vdev);unregister_netdev (vi->dev);while (vi->pages)
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 5/8 virtio_net: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_net.
These will be required for MSI support.
--- drivers/net/virtio_net.c | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-)
drivers/net/virtio_net.c +13 -3
@@ -841,6 +841,7 @@ static int virtnet_probe(struct virtio_device *vdev)int err;struct net_device *dev;struct virtnet_info *vi; +bool control_vq;/* Allocate ourselves a network device with room for our info */ dev =alloc_etherdev (sizeof (struct virtnet_info ));
@@ -901,11 +902,17 @@ 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. */ +/* We expect either two or three virtqueues: receive, send and +* optionally control. */ + control_vq =virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ ); + err =virtio_request_vqs (vdev, control_vq ?3 :2 ); +if (err) + goto free; + vi->rvq = vdev->config->find_vq (vdev,0 , skb_recv_done);if (IS_ERR (vi->rvq)) { err =PTR_ERR (vi->rvq); - goto free; + goto free_vqs; } vi->svq = vdev->config->find_vq (vdev,1 , skb_xmit_done);
@@ -914,7 +921,7 @@ static int virtnet_probe(struct virtio_device *vdev) goto free_recv; } -if (virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ )) { +if (control_vq) { vi->cvq = vdev->config->find_vq (vdev,2 ,NULL );if (IS_ERR (vi->cvq)) { err =PTR_ERR (vi->svq);
@@ -965,6 +972,8 @@ free_send: vdev->config->del_vq (vi->svq); free_recv: vdev->config->del_vq (vi->rvq); +free_vqs: +virtio_free_vqs (vi->vdev); free:free_netdev (dev);return err;
@@ -994,6 +1003,7 @@ static void virtnet_remove(struct virtio_device *vdev) vdev->config->del_vq (vi->rvq);if (virtio_has_feature (vi->vdev,VIRTIO_NET_F_CTRL_VQ )) vdev->config->del_vq (vi->cvq); +virtio_free_vqs (vi->vdev);unregister_netdev (vi->dev);while (vi->pages)
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 6/8 virtio_balloon: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_balloon.
These will be required for MSI support.
--- drivers/virtio/virtio_balloon.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/virtio/virtio_balloon.c +8 -1
@@ -217,10 +217,14 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->vdev = vdev;/* We expect two virtqueues. */ + err =virtio_request_vqs (vdev,2 ); +if (err) + goto out_free_vb; + vb->inflate_vq = vdev->config->find_vq (vdev,0 , balloon_ack);if (IS_ERR (vb->inflate_vq)) { err =PTR_ERR (vb->inflate_vq); - goto out_free_vb; + goto out_free_vqs; } vb->deflate_vq = vdev->config->find_vq (vdev,1 , balloon_ack);
@@ -244,6 +248,8 @@ out_del_deflate_vq: vdev->config->del_vq (vb->deflate_vq); out_del_inflate_vq: vdev->config->del_vq (vb->inflate_vq); +out_free_vqs: +virtio_free_vqs (vdev); out_free_vb:kfree (vb); out:
@@ -265,6 +271,7 @@ static void virtballoon_remove(struct virtio_device *vdev) vdev->config->del_vq (vb->deflate_vq); vdev->config->del_vq (vb->inflate_vq); +virtio_free_vqs (vdev);kfree (vb); }
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 6/8 virtio_balloon: add request_vqs/free_vqs calls
In reply to a message not in the archiveAdd request_vqs/free_vqs calls to virtio_balloon.
These will be required for MSI support.
--- drivers/virtio/virtio_balloon.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/virtio/virtio_balloon.c +8 -1
@@ -217,10 +217,14 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->vdev = vdev;/* We expect two virtqueues. */ + err =virtio_request_vqs (vdev,2 ); +if (err) + goto out_free_vb; + vb->inflate_vq = vdev->config->find_vq (vdev,0 , balloon_ack);if (IS_ERR (vb->inflate_vq)) { err =PTR_ERR (vb->inflate_vq); - goto out_free_vb; + goto out_free_vqs; } vb->deflate_vq = vdev->config->find_vq (vdev,1 , balloon_ack);
@@ -244,6 +248,8 @@ out_del_deflate_vq: vdev->config->del_vq (vb->deflate_vq); out_del_inflate_vq: vdev->config->del_vq (vb->inflate_vq); +out_free_vqs: +virtio_free_vqs (vdev); out_free_vb:kfree (vb); out:
@@ -265,6 +271,7 @@ static void virtballoon_remove(struct virtio_device *vdev) vdev->config->del_vq (vb->deflate_vq); vdev->config->del_vq (vb->inflate_vq); +virtio_free_vqs (vdev);kfree (vb); }
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 7/8 virtio_pci: split up vp_interrupt
In reply to a message not in the archiveThis reorganizes virtio-pci code in vp_interrupt slightly, so that it's easier to add per-vq MSI support on top.
--- drivers/virtio/virtio_pci.c | 45 +++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 10 deletions(-)
drivers/virtio/virtio_pci.c +35 -10
@@ -164,6 +164,37 @@ static void vp_notify(struct virtqueue *vq)iowrite16 (info->queue_index, vp_dev->ioaddr +VIRTIO_PCI_QUEUE_NOTIFY ); } +/* Handle a configuration change: Tell driver if it wants to know. */ +static irqreturn_t vp_config_changed (int irq,void *opaque) +{ +struct virtio_pci_device *vp_dev = opaque; +struct virtio_driver *drv; + drv =container_of (vp_dev->vdev.dev.driver, + struct virtio_driver, driver); + +if (drv && drv->config_changed) + drv->config_changed (&vp_dev->vdev); +return IRQ_HANDLED ; +} + +/* Notify all virtqueues on an interrupt. */ +static irqreturn_t vp_vring_interrupt (int irq,void *opaque) +{ +struct virtio_pci_device *vp_dev = opaque; +struct virtio_pci_vq_info *info; +irqreturn_t ret =IRQ_NONE ; +unsigned long flags; + +spin_lock_irqsave (&vp_dev->lock, flags); +list_for_each_entry (info, &vp_dev->virtqueues, node) { +if (vring_interrupt (irq, info->vq) ==IRQ_HANDLED ) + ret =IRQ_HANDLED ; + } +spin_unlock_irqrestore (&vp_dev->lock, flags); + +return ret; +} +/* A small wrapper to also acknowledge the interrupt when it's handled. * I really need an EIO hook for the vring so I can ack the interrupt once we * know that we'll be handling the IRQ but before we invoke the callback since
@@ -173,9 +204,6 @@ static void vp_notify(struct virtqueue *vq)static irqreturn_t vp_interrupt (int irq,void *opaque) {struct virtio_pci_device *vp_dev = opaque; -struct virtio_pci_vq_info *info; -irqreturn_t ret =IRQ_NONE ; -unsigned long flags;u8 isr;/* reading the ISR has the effect of also clearing it so it's very
@@ -187,14 +215,11 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)return IRQ_NONE ;/* Configuration change? Tell driver if it wants to know. */ -if (isr &VIRTIO_PCI_ISR_CONFIG ) { -struct virtio_driver *drv; - drv =container_of (vp_dev->vdev.dev.driver, - struct virtio_driver, driver); +if (isr &VIRTIO_PCI_ISR_CONFIG ) +vp_config_changed (irq, opaque); -if (drv && drv->config_changed) - drv->config_changed (&vp_dev->vdev); - } +return vp_vring_interrupt (irq, opaque); +}spin_lock_irqsave (&vp_dev->lock, flags);list_for_each_entry (info, &vp_dev->virtqueues, node) {
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 7/8 virtio_pci: split up vp_interrupt
In reply to a message not in the archiveThis reorganizes virtio-pci code in vp_interrupt slightly, so that it's easier to add per-vq MSI support on top.
--- drivers/virtio/virtio_pci.c | 45 +++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 10 deletions(-)
drivers/virtio/virtio_pci.c +35 -10
@@ -164,6 +164,37 @@ static void vp_notify(struct virtqueue *vq)iowrite16 (info->queue_index, vp_dev->ioaddr +VIRTIO_PCI_QUEUE_NOTIFY ); } +/* Handle a configuration change: Tell driver if it wants to know. */ +static irqreturn_t vp_config_changed (int irq,void *opaque) +{ +struct virtio_pci_device *vp_dev = opaque; +struct virtio_driver *drv; + drv =container_of (vp_dev->vdev.dev.driver, + struct virtio_driver, driver); + +if (drv && drv->config_changed) + drv->config_changed (&vp_dev->vdev); +return IRQ_HANDLED ; +} + +/* Notify all virtqueues on an interrupt. */ +static irqreturn_t vp_vring_interrupt (int irq,void *opaque) +{ +struct virtio_pci_device *vp_dev = opaque; +struct virtio_pci_vq_info *info; +irqreturn_t ret =IRQ_NONE ; +unsigned long flags; + +spin_lock_irqsave (&vp_dev->lock, flags); +list_for_each_entry (info, &vp_dev->virtqueues, node) { +if (vring_interrupt (irq, info->vq) ==IRQ_HANDLED ) + ret =IRQ_HANDLED ; + } +spin_unlock_irqrestore (&vp_dev->lock, flags); + +return ret; +} +/* A small wrapper to also acknowledge the interrupt when it's handled. * I really need an EIO hook for the vring so I can ack the interrupt once we * know that we'll be handling the IRQ but before we invoke the callback since
@@ -173,9 +204,6 @@ static void vp_notify(struct virtqueue *vq)static irqreturn_t vp_interrupt (int irq,void *opaque) {struct virtio_pci_device *vp_dev = opaque; -struct virtio_pci_vq_info *info; -irqreturn_t ret =IRQ_NONE ; -unsigned long flags;u8 isr;/* reading the ISR has the effect of also clearing it so it's very
@@ -187,14 +215,11 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)return IRQ_NONE ;/* Configuration change? Tell driver if it wants to know. */ -if (isr &VIRTIO_PCI_ISR_CONFIG ) { -struct virtio_driver *drv; - drv =container_of (vp_dev->vdev.dev.driver, - struct virtio_driver, driver); +if (isr &VIRTIO_PCI_ISR_CONFIG ) +vp_config_changed (irq, opaque); -if (drv && drv->config_changed) - drv->config_changed (&vp_dev->vdev); - } +return vp_vring_interrupt (irq, opaque); +}spin_lock_irqsave (&vp_dev->lock, flags);list_for_each_entry (info, &vp_dev->virtqueues, node) {
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 8/8 virtio_pci: optional MSI-X support
In reply to a message not in the archiveThis implements optional MSI-X support in virtio_pci. MSI-X is used whenever the host supports at least 2 MSI-X
vectors: 1 for configuration changes and 1 for virtqueues. Per-virtqueue vectors are allocated if enough vectors available.
--- drivers/virtio/virtio_pci.c | 147 ++++++++++++++++++++++++++++++++++++++----- 1 files changed, 132 insertions(+), 15 deletions(-)
drivers/virtio/virtio_pci.c +132 -15
@@ -42,8 +42,33 @@ struct virtio_pci_device/* a list of queues so we can dispatch IRQs */ spinlock_t lock;struct list_head virtqueues; + +/* MSI-X support */ +struct msix_entry *msix_entries; +/* Name strings for interrupts. This size should be enough, +* and I'm too lazy to allocate each name separately. */ +char (*msix_names)[256 ]; +/* Number of vectors configured at startup (excludes per-virtqueue +* vectors if any) */ +unsigned msix_preset_vectors; +/* Number of per-virtqueue vectors if any. */ +unsigned msix_per_vq_vectors; +}; + +/* Constants for MSI-X */ +/* Use first vector for configuration changes, second and the rest for +* virtqueues Thus, we need at least 2 vectors for MSI. */ +enum { +VP_MSIX_CONFIG_VECTOR =0 , +VP_MSIX_VQ_VECTOR =1 , +VP_MSIX_MIN_VECTORS =2 }; +static inline int vq_vector (int index) +{ +return index +VP_MSIX_VQ_VECTOR ; +} +struct virtio_pci_vq_info {/* the actual virtqueue */
@@ -221,14 +246,92 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)return vp_vring_interrupt (irq, opaque); } -spin_lock_irqsave (&vp_dev->lock, flags); -list_for_each_entry (info, &vp_dev->virtqueues, node) { -if (vring_interrupt (irq, info->vq) ==IRQ_HANDLED ) - ret =IRQ_HANDLED ; +/* the config->free_vqs() implementation */ +static void vp_free_vqs (struct virtio_device *vdev) { +struct virtio_pci_device *vp_dev =to_vp_device (vdev); +int i; + +for (i =0 ; i < vp_dev->msix_preset_vectors; ++i) +free_irq (vp_dev->msix_entries[i].vector, vp_dev); + +if (!vp_dev->msix_preset_vectors) +free_irq (vp_dev->pci_dev->irq, vp_dev); +} + +/* the config->request_vqs() implementation */ +static int vp_request_vqs (struct virtio_device *vdev,unsigned max_vqs) { +struct virtio_pci_device *vp_dev =to_vp_device (vdev); +const char *name =dev_name (&vp_dev->vdev.dev); +unsigned i, vectors; +int err = -ENOMEM ; + +/* We need at most one vector per queue and one for config changes */ + vectors =vq_vector (max_vqs); + vp_dev->msix_entries =kmalloc (vectors *sizeof *vp_dev->msix_entries, +GFP_KERNEL ); +if (!vp_dev->msix_entries) + goto error_entries; + vp_dev->msix_names =kmalloc (vectors *sizeof *vp_dev->msix_names, +GFP_KERNEL ); +if (!vp_dev->msix_names) + goto error_names; + +snprintf (vp_dev->msix_names[VP_MSIX_CONFIG_VECTOR ], +sizeof *vp_dev->msix_names,"%s-config" , name); +for (i =0 ; i < max_vqs; ++i) +snprintf (vp_dev->msix_names[vq_vector (i)], +sizeof *vp_dev->msix_names,"%s-vq-%d" , name, i); + + vp_dev->msix_preset_vectors =1 ; + vp_dev->msix_per_vq_vectors = max_vqs; +for (;;) { + err =pci_enable_msix (vp_dev->pci_dev, vp_dev->msix_entries, + vectors); +/* Error out if not enough vectors */ +if (err >0 && err <VP_MSIX_MIN_VECTORS ) + err = -EBUSY ; +if (err <=0 ) +break ; +/* Not enough vectors for all queues. Retry, disabling +* per-queue interrupts */ + vectors =VP_MSIX_MIN_VECTORS ; + vp_dev->msix_preset_vectors =VP_MSIX_MIN_VECTORS ; + vp_dev->msix_per_vq_vectors =0 ; +snprintf (vp_dev->msix_names[VP_MSIX_VQ_VECTOR ], +sizeof *vp_dev->msix_names,"%s-vq" , name); } -spin_unlock_irqrestore (&vp_dev->lock, flags); -return ret; +if (err) { +/* Can't allocate enough MSI-X vectors, use regular interrupt */ + vp_dev->msix_preset_vectors =0 ; + vp_dev->msix_per_vq_vectors =0 ; +/* Register a handler for the queue with the PCI device's +* interrupt */ + err =request_irq (vp_dev->pci_dev->irq, vp_interrupt, +IRQF_SHARED , name, vp_dev); +if (err) + goto error_irq; + } +for (i =0 ; i < vp_dev->msix_preset_vectors; ++i) { + err =request_irq (vp_dev->msix_entries[i].vector, + i ==VP_MSIX_CONFIG_VECTOR ? + vp_config_changed : vp_vring_interrupt, +0 , vp_dev->msix_names[i], vp_dev); +if (err) { +/* Set msix_preset_vectors so that only vectors we +* already allocated will be freed by vp_free_vqs. */ + vp_dev->msix_preset_vectors = i; + goto error_irq; + } + } +return 0 ; +error_irq: +vp_free_vqs (vdev); +kfree (vp_dev->msix_names); +error_names: +kfree (vp_dev->msix_entries); +error_entries: +return err; }/* the config->find_vq() implementation */
@@ -242,6 +345,10 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,u16 num;int err; +/* If using IRQ vector per vq, make sure we have enough vectors */ +if (vp_dev->msix_per_vq_vectors && vp_dev->msix_per_vq_vectors <= index) +return ERR_PTR (-ENOENT ); +/* Select the queue we're interested in */ iowrite16 (index, vp_dev->ioaddr +VIRTIO_PCI_QUEUE_SEL );
@@ -285,8 +392,19 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,list_add (&info->node, &vp_dev->virtqueues);spin_unlock_irqrestore (&vp_dev->lock, flags); +/* allocate per-vq irq if neccessary */ +if (vp_dev->msix_per_vq_vectors) { + err =request_irq (vp_dev->msix_entries[vq_vector (index)].vector, + vring_interrupt,0 , + vp_dev->msix_names[vq_vector (index)], vq); +if (err) + goto out_request_irq; + } +return vq; +out_request_irq: +vring_del_virtqueue (vq); out_activate_queue:iowrite32 (0 , vp_dev->ioaddr +VIRTIO_PCI_QUEUE_PFN );free_pages_exact (info->queue, size);
@@ -302,6 +420,11 @@ static void vp_del_vq(struct virtqueue *vq)struct virtio_pci_vq_info *info = vq->priv;unsigned long flags, size; +if (vp_dev->msix_per_vq_vectors) { +int vector =vq_vector (info->queue_index); +free_irq (vp_dev->msix_entries[vector].vector, vq); + } +spin_lock_irqsave (&vp_dev->lock, flags);list_del (&info->node);spin_unlock_irqrestore (&vp_dev->lock, flags);
@@ -323,6 +446,8 @@ static struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, + .request_vqs = vp_request_vqs, + .free_vqs = vp_free_vqs, .find_vq = vp_find_vq, .del_vq = vp_del_vq, .get_features = vp_get_features,
@@ -394,21 +519,13 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; vp_dev->vdev.id.device = pci_dev->subsystem_device; -/* register a handler for the queue with the PCI device's interrupt */ - err =request_irq (vp_dev->pci_dev->irq, vp_interrupt,IRQF_SHARED , -dev_name (&vp_dev->vdev.dev), vp_dev); -if (err) - goto out_set_drvdata; -/* finally register the virtio device */ err =register_virtio_device (&vp_dev->vdev);if (err) - goto out_req_irq; + goto out_set_drvdata;return 0 ; -out_req_irq: -free_irq (pci_dev->irq, vp_dev); out_set_drvdata:pci_set_drvdata (pci_dev,NULL );pci_iounmap (pci_dev, vp_dev->ioaddr);
Signature · 1 line
1.6.0.6
Michael S. Tsirkin
maintainerPATCH 8/8 virtio_pci: optional MSI-X support
In reply to a message not in the archiveThis implements optional MSI-X support in virtio_pci. MSI-X is used whenever the host supports at least 2 MSI-X
vectors: 1 for configuration changes and 1 for virtqueues. Per-virtqueue vectors are allocated if enough vectors available.
--- drivers/virtio/virtio_pci.c | 147 ++++++++++++++++++++++++++++++++++++++----- 1 files changed, 132 insertions(+), 15 deletions(-)
drivers/virtio/virtio_pci.c +132 -15
@@ -42,8 +42,33 @@ struct virtio_pci_device/* a list of queues so we can dispatch IRQs */ spinlock_t lock;struct list_head virtqueues; + +/* MSI-X support */ +struct msix_entry *msix_entries; +/* Name strings for interrupts. This size should be enough, +* and I'm too lazy to allocate each name separately. */ +char (*msix_names)[256 ]; +/* Number of vectors configured at startup (excludes per-virtqueue +* vectors if any) */ +unsigned msix_preset_vectors; +/* Number of per-virtqueue vectors if any. */ +unsigned msix_per_vq_vectors; +}; + +/* Constants for MSI-X */ +/* Use first vector for configuration changes, second and the rest for +* virtqueues Thus, we need at least 2 vectors for MSI. */ +enum { +VP_MSIX_CONFIG_VECTOR =0 , +VP_MSIX_VQ_VECTOR =1 , +VP_MSIX_MIN_VECTORS =2 }; +static inline int vq_vector (int index) +{ +return index +VP_MSIX_VQ_VECTOR ; +} +struct virtio_pci_vq_info {/* the actual virtqueue */
@@ -221,14 +246,92 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)return vp_vring_interrupt (irq, opaque); } -spin_lock_irqsave (&vp_dev->lock, flags); -list_for_each_entry (info, &vp_dev->virtqueues, node) { -if (vring_interrupt (irq, info->vq) ==IRQ_HANDLED ) - ret =IRQ_HANDLED ; +/* the config->free_vqs() implementation */ +static void vp_free_vqs (struct virtio_device *vdev) { +struct virtio_pci_device *vp_dev =to_vp_device (vdev); +int i; + +for (i =0 ; i < vp_dev->msix_preset_vectors; ++i) +free_irq (vp_dev->msix_entries[i].vector, vp_dev); + +if (!vp_dev->msix_preset_vectors) +free_irq (vp_dev->pci_dev->irq, vp_dev); +} + +/* the config->request_vqs() implementation */ +static int vp_request_vqs (struct virtio_device *vdev,unsigned max_vqs) { +struct virtio_pci_device *vp_dev =to_vp_device (vdev); +const char *name =dev_name (&vp_dev->vdev.dev); +unsigned i, vectors; +int err = -ENOMEM ; + +/* We need at most one vector per queue and one for config changes */ + vectors =vq_vector (max_vqs); + vp_dev->msix_entries =kmalloc (vectors *sizeof *vp_dev->msix_entries, +GFP_KERNEL ); +if (!vp_dev->msix_entries) + goto error_entries; + vp_dev->msix_names =kmalloc (vectors *sizeof *vp_dev->msix_names, +GFP_KERNEL ); +if (!vp_dev->msix_names) + goto error_names; + +snprintf (vp_dev->msix_names[VP_MSIX_CONFIG_VECTOR ], +sizeof *vp_dev->msix_names,"%s-config" , name); +for (i =0 ; i < max_vqs; ++i) +snprintf (vp_dev->msix_names[vq_vector (i)], +sizeof *vp_dev->msix_names,"%s-vq-%d" , name, i); + + vp_dev->msix_preset_vectors =1 ; + vp_dev->msix_per_vq_vectors = max_vqs; +for (;;) { + err =pci_enable_msix (vp_dev->pci_dev, vp_dev->msix_entries, + vectors); +/* Error out if not enough vectors */ +if (err >0 && err <VP_MSIX_MIN_VECTORS ) + err = -EBUSY ; +if (err <=0 ) +break ; +/* Not enough vectors for all queues. Retry, disabling +* per-queue interrupts */ + vectors =VP_MSIX_MIN_VECTORS ; + vp_dev->msix_preset_vectors =VP_MSIX_MIN_VECTORS ; + vp_dev->msix_per_vq_vectors =0 ; +snprintf (vp_dev->msix_names[VP_MSIX_VQ_VECTOR ], +sizeof *vp_dev->msix_names,"%s-vq" , name); } -spin_unlock_irqrestore (&vp_dev->lock, flags); -return ret; +if (err) { +/* Can't allocate enough MSI-X vectors, use regular interrupt */ + vp_dev->msix_preset_vectors =0 ; + vp_dev->msix_per_vq_vectors =0 ; +/* Register a handler for the queue with the PCI device's +* interrupt */ + err =request_irq (vp_dev->pci_dev->irq, vp_interrupt, +IRQF_SHARED , name, vp_dev); +if (err) + goto error_irq; + } +for (i =0 ; i < vp_dev->msix_preset_vectors; ++i) { + err =request_irq (vp_dev->msix_entries[i].vector, + i ==VP_MSIX_CONFIG_VECTOR ? + vp_config_changed : vp_vring_interrupt, +0 , vp_dev->msix_names[i], vp_dev); +if (err) { +/* Set msix_preset_vectors so that only vectors we +* already allocated will be freed by vp_free_vqs. */ + vp_dev->msix_preset_vectors = i; + goto error_irq; + } + } +return 0 ; +error_irq: +vp_free_vqs (vdev); +kfree (vp_dev->msix_names); +error_names: +kfree (vp_dev->msix_entries); +error_entries: +return err; }/* the config->find_vq() implementation */
@@ -242,6 +345,10 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,u16 num;int err; +/* If using IRQ vector per vq, make sure we have enough vectors */ +if (vp_dev->msix_per_vq_vectors && vp_dev->msix_per_vq_vectors <= index) +return ERR_PTR (-ENOENT ); +/* Select the queue we're interested in */ iowrite16 (index, vp_dev->ioaddr +VIRTIO_PCI_QUEUE_SEL );
@@ -285,8 +392,19 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,list_add (&info->node, &vp_dev->virtqueues);spin_unlock_irqrestore (&vp_dev->lock, flags); +/* allocate per-vq irq if neccessary */ +if (vp_dev->msix_per_vq_vectors) { + err =request_irq (vp_dev->msix_entries[vq_vector (index)].vector, + vring_interrupt,0 , + vp_dev->msix_names[vq_vector (index)], vq); +if (err) + goto out_request_irq; + } +return vq; +out_request_irq: +vring_del_virtqueue (vq); out_activate_queue:iowrite32 (0 , vp_dev->ioaddr +VIRTIO_PCI_QUEUE_PFN );free_pages_exact (info->queue, size);
@@ -302,6 +420,11 @@ static void vp_del_vq(struct virtqueue *vq)struct virtio_pci_vq_info *info = vq->priv;unsigned long flags, size; +if (vp_dev->msix_per_vq_vectors) { +int vector =vq_vector (info->queue_index); +free_irq (vp_dev->msix_entries[vector].vector, vq); + } +spin_lock_irqsave (&vp_dev->lock, flags);list_del (&info->node);spin_unlock_irqrestore (&vp_dev->lock, flags);
@@ -323,6 +446,8 @@ static struct virtio_config_ops virtio_pci_config_ops = { .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, + .request_vqs = vp_request_vqs, + .free_vqs = vp_free_vqs, .find_vq = vp_find_vq, .del_vq = vp_del_vq, .get_features = vp_get_features,
@@ -394,21 +519,13 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; vp_dev->vdev.id.device = pci_dev->subsystem_device; -/* register a handler for the queue with the PCI device's interrupt */ - err =request_irq (vp_dev->pci_dev->irq, vp_interrupt,IRQF_SHARED , -dev_name (&vp_dev->vdev.dev), vp_dev); -if (err) - goto out_set_drvdata; -/* finally register the virtio device */ err =register_virtio_device (&vp_dev->vdev);if (err) - goto out_req_irq; + goto out_set_drvdata;return 0 ; -out_req_irq: -free_irq (pci_dev->irq, vp_dev); out_set_drvdata:pci_set_drvdata (pci_dev,NULL );pci_iounmap (pci_dev, vp_dev->ioaddr);
Signature · 1 line
1.6.0.6