Commit c44b5943 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull virtio updates from Michael Tsirkin:
 "Fixes, cleanups, performance

  A bunch of changes to virtio, most affecting virtio net. Also ptr_ring
  batched zeroing - first of batching enhancements that seems ready."

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  s390/virtio: change maintainership
  tools/virtio: fix spelling mistake: "wakeus" -> "wakeups"
  virtio_net: tidy a couple debug statements
  ptr_ring: support testing different batching sizes
  ringtest: support test specific parameters
  ptr_ring: batch ring zeroing
  virtio: virtio_driver doc
  virtio_net: don't reset twice on XDP on/off
  virtio_net: fix support for small rings
  virtio_net: reduce alignment for buffers
  virtio_net: rework mergeable buffer handling
  virtio_net: allow specifying context for rx
  virtio: allow extra context per descriptor
  tools/virtio: fix build breakage
  virtio: add context flag to find vqs
  virtio: wrap find_vqs
  ringtest: fix an assert statement
parents 5ccd4140 c8b0d729
...@@ -13556,8 +13556,8 @@ F: include/uapi/linux/virtio_*.h ...@@ -13556,8 +13556,8 @@ F: include/uapi/linux/virtio_*.h
F: drivers/crypto/virtio/ F: drivers/crypto/virtio/
VIRTIO DRIVERS FOR S390 VIRTIO DRIVERS FOR S390
M: Christian Borntraeger <borntraeger@de.ibm.com>
M: Cornelia Huck <cornelia.huck@de.ibm.com> M: Cornelia Huck <cornelia.huck@de.ibm.com>
M: Halil Pasic <pasic@linux.vnet.ibm.com>
L: linux-s390@vger.kernel.org L: linux-s390@vger.kernel.org
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
......
...@@ -452,8 +452,7 @@ static int init_vq(struct virtio_blk *vblk) ...@@ -452,8 +452,7 @@ static int init_vq(struct virtio_blk *vblk)
} }
/* Discover virtqueues and write information to configuration. */ /* Discover virtqueues and write information to configuration. */
err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names, err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
&desc);
if (err) if (err)
goto out; goto out;
......
...@@ -1945,7 +1945,7 @@ static int init_vqs(struct ports_device *portdev) ...@@ -1945,7 +1945,7 @@ static int init_vqs(struct ports_device *portdev)
} }
} }
/* Find the queues. */ /* Find the queues. */
err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, err = virtio_find_vqs(portdev->vdev, nr_queues, vqs,
io_callbacks, io_callbacks,
(const char **)io_names, NULL); (const char **)io_names, NULL);
if (err) if (err)
......
...@@ -119,8 +119,7 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) ...@@ -119,8 +119,7 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi)
names[i] = vi->data_vq[i].name; names[i] = vi->data_vq[i].name;
} }
ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks, ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, callbacks, names, NULL);
names, NULL);
if (ret) if (ret)
goto err_find; goto err_find;
......
...@@ -175,8 +175,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -175,8 +175,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
DRM_INFO("virgl 3d acceleration not supported by guest\n"); DRM_INFO("virgl 3d acceleration not supported by guest\n");
#endif #endif
ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs, ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);
callbacks, names, NULL);
if (ret) { if (ret) {
DRM_ERROR("failed to find virt queues\n"); DRM_ERROR("failed to find virt queues\n");
goto err_vqs; goto err_vqs;
......
...@@ -278,7 +278,7 @@ static void vop_del_vqs(struct virtio_device *dev) ...@@ -278,7 +278,7 @@ static void vop_del_vqs(struct virtio_device *dev)
static struct virtqueue *vop_find_vq(struct virtio_device *dev, static struct virtqueue *vop_find_vq(struct virtio_device *dev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name) const char *name, bool ctx)
{ {
struct _vop_vdev *vdev = to_vopvdev(dev); struct _vop_vdev *vdev = to_vopvdev(dev);
struct vop_device *vpdev = vdev->vpdev; struct vop_device *vpdev = vdev->vpdev;
...@@ -314,6 +314,7 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev, ...@@ -314,6 +314,7 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN, le16_to_cpu(config.num), MIC_VIRTIO_RING_ALIGN,
dev, dev,
false, false,
ctx,
(void __force *)va, vop_notify, callback, name); (void __force *)va, vop_notify, callback, name);
if (!vq) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
...@@ -374,7 +375,8 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev, ...@@ -374,7 +375,8 @@ static struct virtqueue *vop_find_vq(struct virtio_device *dev,
static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs, static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs,
struct virtqueue *vqs[], struct virtqueue *vqs[],
vq_callback_t *callbacks[], vq_callback_t *callbacks[],
const char * const names[], struct irq_affinity *desc) const char * const names[], const bool *ctx,
struct irq_affinity *desc)
{ {
struct _vop_vdev *vdev = to_vopvdev(dev); struct _vop_vdev *vdev = to_vopvdev(dev);
struct vop_device *vpdev = vdev->vpdev; struct vop_device *vpdev = vdev->vpdev;
...@@ -388,7 +390,8 @@ static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs, ...@@ -388,7 +390,8 @@ static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs,
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
dev_dbg(_vop_dev(vdev), "%s: %d: %s\n", dev_dbg(_vop_dev(vdev), "%s: %d: %s\n",
__func__, i, names[i]); __func__, i, names[i]);
vqs[i] = vop_find_vq(dev, i, callbacks[i], names[i]); vqs[i] = vop_find_vq(dev, i, callbacks[i], names[i],
ctx ? ctx[i] : false);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]); err = PTR_ERR(vqs[i]);
goto error; goto error;
......
...@@ -679,8 +679,7 @@ static int cfv_probe(struct virtio_device *vdev) ...@@ -679,8 +679,7 @@ static int cfv_probe(struct virtio_device *vdev)
goto err; goto err;
/* Get the TX virtio ring. This is a "guest side vring". */ /* Get the TX virtio ring. This is a "guest side vring". */
err = vdev->config->find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names, err = virtio_find_vqs(vdev, 1, &cfv->vq_tx, &vq_cbs, &names, NULL);
NULL);
if (err) if (err)
goto err; goto err;
......
This diff is collapsed.
...@@ -71,7 +71,7 @@ EXPORT_SYMBOL(rproc_vq_interrupt); ...@@ -71,7 +71,7 @@ EXPORT_SYMBOL(rproc_vq_interrupt);
static struct virtqueue *rp_find_vq(struct virtio_device *vdev, static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
unsigned int id, unsigned int id,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name) const char *name, bool ctx)
{ {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct rproc *rproc = vdev_to_rproc(vdev); struct rproc *rproc = vdev_to_rproc(vdev);
...@@ -103,8 +103,8 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, ...@@ -103,8 +103,8 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
* Create the new vq, and tell virtio we're not interested in * Create the new vq, and tell virtio we're not interested in
* the 'weak' smp barriers, since we're talking with a real device. * the 'weak' smp barriers, since we're talking with a real device.
*/ */
vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr, vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, ctx,
rproc_virtio_notify, callback, name); addr, rproc_virtio_notify, callback, name);
if (!vq) { if (!vq) {
dev_err(dev, "vring_new_virtqueue %s failed\n", name); dev_err(dev, "vring_new_virtqueue %s failed\n", name);
rproc_free_vring(rvring); rproc_free_vring(rvring);
...@@ -138,12 +138,14 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, ...@@ -138,12 +138,14 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
struct virtqueue *vqs[], struct virtqueue *vqs[],
vq_callback_t *callbacks[], vq_callback_t *callbacks[],
const char * const names[], const char * const names[],
const bool * ctx,
struct irq_affinity *desc) struct irq_affinity *desc)
{ {
int i, ret; int i, ret;
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i],
ctx ? ctx[i] : false);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
ret = PTR_ERR(vqs[i]); ret = PTR_ERR(vqs[i]);
goto error; goto error;
......
...@@ -869,7 +869,7 @@ static int rpmsg_probe(struct virtio_device *vdev) ...@@ -869,7 +869,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
init_waitqueue_head(&vrp->sendq); init_waitqueue_head(&vrp->sendq);
/* We expect two virtqueues, rx and tx (and in this order) */ /* We expect two virtqueues, rx and tx (and in this order) */
err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names, NULL); err = virtio_find_vqs(vdev, 2, vqs, vq_cbs, names, NULL);
if (err) if (err)
goto free_vrp; goto free_vrp;
......
...@@ -189,7 +189,7 @@ static bool kvm_notify(struct virtqueue *vq) ...@@ -189,7 +189,7 @@ static bool 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) const char *name, bool ctx)
{ {
struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_device *kdev = to_kvmdev(vdev);
struct kvm_vqconfig *config; struct kvm_vqconfig *config;
...@@ -211,7 +211,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, ...@@ -211,7 +211,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
goto out; goto out;
vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN, vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN,
vdev, true, (void *) config->address, vdev, true, ctx, (void *) config->address,
kvm_notify, callback, name); kvm_notify, callback, name);
if (!vq) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
...@@ -256,6 +256,7 @@ static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -256,6 +256,7 @@ static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], struct virtqueue *vqs[],
vq_callback_t *callbacks[], vq_callback_t *callbacks[],
const char * const names[], const char * const names[],
const bool *ctx,
struct irq_affinity *desc) struct irq_affinity *desc)
{ {
struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_device *kdev = to_kvmdev(vdev);
...@@ -266,7 +267,8 @@ static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -266,7 +267,8 @@ static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
return -ENOENT; return -ENOENT;
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i],
ctx ? ctx[i] : false);
if (IS_ERR(vqs[i])) if (IS_ERR(vqs[i]))
goto error; goto error;
} }
......
...@@ -484,7 +484,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev) ...@@ -484,7 +484,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
int i, vq_callback_t *callback, int i, vq_callback_t *callback,
const char *name, const char *name, bool ctx,
struct ccw1 *ccw) struct ccw1 *ccw)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
...@@ -522,7 +522,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, ...@@ -522,7 +522,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
} }
vq = vring_new_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev, vq = vring_new_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev,
true, info->queue, virtio_ccw_kvm_notify, true, ctx, info->queue, virtio_ccw_kvm_notify,
callback, name); callback, name);
if (!vq) { if (!vq) {
/* For now, we fail if we can't get the requested size. */ /* For now, we fail if we can't get the requested size. */
...@@ -629,6 +629,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -629,6 +629,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], struct virtqueue *vqs[],
vq_callback_t *callbacks[], vq_callback_t *callbacks[],
const char * const names[], const char * const names[],
const bool *ctx,
struct irq_affinity *desc) struct irq_affinity *desc)
{ {
struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct virtio_ccw_device *vcdev = to_vc_device(vdev);
...@@ -642,7 +643,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -642,7 +643,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i], vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i],
ccw); ctx ? ctx[i] : false, ccw);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
ret = PTR_ERR(vqs[i]); ret = PTR_ERR(vqs[i]);
vqs[i] = NULL; vqs[i] = NULL;
......
...@@ -894,8 +894,7 @@ static int virtscsi_init(struct virtio_device *vdev, ...@@ -894,8 +894,7 @@ static int virtscsi_init(struct virtio_device *vdev,
} }
/* Discover virtqueues and write information to configuration. */ /* Discover virtqueues and write information to configuration. */
err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names, err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
&desc);
if (err) if (err)
goto out; goto out;
......
...@@ -418,8 +418,7 @@ static int init_vqs(struct virtio_balloon *vb) ...@@ -418,8 +418,7 @@ static int init_vqs(struct virtio_balloon *vb)
* optionally stat. * optionally stat.
*/ */
nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2; nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names, err = virtio_find_vqs(vb->vdev, nvqs, vqs, callbacks, names, NULL);
NULL);
if (err) if (err)
return err; return err;
......
...@@ -173,8 +173,7 @@ static int virtinput_init_vqs(struct virtio_input *vi) ...@@ -173,8 +173,7 @@ static int virtinput_init_vqs(struct virtio_input *vi)
static const char * const names[] = { "events", "status" }; static const char * const names[] = { "events", "status" };
int err; int err;
err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names, err = virtio_find_vqs(vi->vdev, 2, vqs, cbs, names, NULL);
NULL);
if (err) if (err)
return err; return err;
vi->evt = vqs[0]; vi->evt = vqs[0];
......
...@@ -351,7 +351,7 @@ static void vm_del_vqs(struct virtio_device *vdev) ...@@ -351,7 +351,7 @@ static void vm_del_vqs(struct virtio_device *vdev)
static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name) const char *name, bool ctx)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
struct virtio_mmio_vq_info *info; struct virtio_mmio_vq_info *info;
...@@ -388,7 +388,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, ...@@ -388,7 +388,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
/* Create the vring */ /* Create the vring */
vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev, vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev,
true, true, vm_notify, callback, name); true, true, ctx, vm_notify, callback, name);
if (!vq) { if (!vq) {
err = -ENOMEM; err = -ENOMEM;
goto error_new_virtqueue; goto error_new_virtqueue;
...@@ -447,6 +447,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -447,6 +447,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], struct virtqueue *vqs[],
vq_callback_t *callbacks[], vq_callback_t *callbacks[],
const char * const names[], const char * const names[],
const bool *ctx,
struct irq_affinity *desc) struct irq_affinity *desc)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
...@@ -459,7 +460,8 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -459,7 +460,8 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
return err; return err;
for (i = 0; i < nvqs; ++i) { for (i = 0; i < nvqs; ++i) {
vqs[i] = vm_setup_vq(vdev, i, callbacks[i], names[i]); vqs[i] = vm_setup_vq(vdev, i, callbacks[i], names[i],
ctx ? ctx[i] : false);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
vm_del_vqs(vdev); vm_del_vqs(vdev);
return PTR_ERR(vqs[i]); return PTR_ERR(vqs[i]);
......
...@@ -172,6 +172,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, ...@@ -172,6 +172,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name, const char *name,
bool ctx,
u16 msix_vec) u16 msix_vec)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
...@@ -183,7 +184,7 @@ static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, ...@@ -183,7 +184,7 @@ static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index,
if (!info) if (!info)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx,
msix_vec); msix_vec);
if (IS_ERR(vq)) if (IS_ERR(vq))
goto out_info; goto out_info;
...@@ -274,6 +275,7 @@ void vp_del_vqs(struct virtio_device *vdev) ...@@ -274,6 +275,7 @@ void vp_del_vqs(struct virtio_device *vdev)
static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[], bool per_vq_vectors, const char * const names[], bool per_vq_vectors,
const bool *ctx,
struct irq_affinity *desc) struct irq_affinity *desc)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
...@@ -315,6 +317,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, ...@@ -315,6 +317,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,
else else
msix_vec = VP_MSIX_VQ_VECTOR; msix_vec = VP_MSIX_VQ_VECTOR;
vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
ctx ? ctx[i] : false,
msix_vec); msix_vec);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]); err = PTR_ERR(vqs[i]);
...@@ -345,7 +348,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, ...@@ -345,7 +348,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,
static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[]) const char * const names[], const bool *ctx)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
int i, err; int i, err;
...@@ -367,6 +370,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, ...@@ -367,6 +370,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,
continue; continue;
} }
vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i],
ctx ? ctx[i] : false,
VIRTIO_MSI_NO_VECTOR); VIRTIO_MSI_NO_VECTOR);
if (IS_ERR(vqs[i])) { if (IS_ERR(vqs[i])) {
err = PTR_ERR(vqs[i]); err = PTR_ERR(vqs[i]);
...@@ -383,20 +387,21 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, ...@@ -383,20 +387,21 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,
/* the config->find_vqs() implementation */ /* the config->find_vqs() implementation */
int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[], struct irq_affinity *desc) const char * const names[], const bool *ctx,
struct irq_affinity *desc)
{ {
int err; int err;
/* Try MSI-X with one vector per queue. */ /* Try MSI-X with one vector per queue. */
err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, desc); err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc);
if (!err) if (!err)
return 0; return 0;
/* Fallback: MSI-X with one vector for config, one shared for queues. */ /* Fallback: MSI-X with one vector for config, one shared for queues. */
err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, desc); err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc);
if (!err) if (!err)
return 0; return 0;
/* Finally fall back to regular interrupts. */ /* Finally fall back to regular interrupts. */
return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names); return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx);
} }
const char *vp_bus_name(struct virtio_device *vdev) const char *vp_bus_name(struct virtio_device *vdev)
......
...@@ -102,6 +102,7 @@ struct virtio_pci_device { ...@@ -102,6 +102,7 @@ struct virtio_pci_device {
unsigned idx, unsigned idx,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name, const char *name,
bool ctx,
u16 msix_vec); u16 msix_vec);
void (*del_vq)(struct virtio_pci_vq_info *info); void (*del_vq)(struct virtio_pci_vq_info *info);
...@@ -131,7 +132,8 @@ void vp_del_vqs(struct virtio_device *vdev); ...@@ -131,7 +132,8 @@ void vp_del_vqs(struct virtio_device *vdev);
/* the config->find_vqs() implementation */ /* the config->find_vqs() implementation */
int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[], struct irq_affinity *desc); const char * const names[], const bool *ctx,
struct irq_affinity *desc);
const char *vp_bus_name(struct virtio_device *vdev); const char *vp_bus_name(struct virtio_device *vdev);
/* Setup the affinity for a virtqueue: /* Setup the affinity for a virtqueue:
......
...@@ -116,6 +116,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, ...@@ -116,6 +116,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name, const char *name,
bool ctx,
u16 msix_vec) u16 msix_vec)
{ {
struct virtqueue *vq; struct virtqueue *vq;
...@@ -135,7 +136,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, ...@@ -135,7 +136,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
/* create the vring */ /* create the vring */
vq = vring_create_virtqueue(index, num, vq = vring_create_virtqueue(index, num,
VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev, VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev,
true, false, vp_notify, callback, name); true, false, ctx,
vp_notify, callback, name);
if (!vq) if (!vq)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -297,6 +297,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, ...@@ -297,6 +297,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
unsigned index, unsigned index,
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name, const char *name,
bool ctx,
u16 msix_vec) u16 msix_vec)
{ {
struct virtio_pci_common_cfg __iomem *cfg = vp_dev->common; struct virtio_pci_common_cfg __iomem *cfg = vp_dev->common;
...@@ -328,7 +329,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, ...@@ -328,7 +329,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
/* create the vring */ /* create the vring */
vq = vring_create_virtqueue(index, num, vq = vring_create_virtqueue(index, num,
SMP_CACHE_BYTES, &vp_dev->vdev, SMP_CACHE_BYTES, &vp_dev->vdev,
true, true, vp_notify, callback, name); true, true, ctx,
vp_notify, callback, name);
if (!vq) if (!vq)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -387,12 +389,14 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, ...@@ -387,12 +389,14 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
} }
static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs, static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[],
const char * const names[], struct irq_affinity *desc) vq_callback_t *callbacks[],
const char * const names[], const bool *ctx,
struct irq_affinity *desc)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtqueue *vq; struct virtqueue *vq;
int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, desc); int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names, ctx, desc);
if (rc) if (rc)
return rc; return rc;
......
...@@ -263,6 +263,7 @@ static inline int virtqueue_add(struct virtqueue *_vq, ...@@ -263,6 +263,7 @@ static inline int virtqueue_add(struct virtqueue *_vq,
unsigned int out_sgs, unsigned int out_sgs,
unsigned int in_sgs, unsigned int in_sgs,
void *data, void *data,
void *ctx,
gfp_t gfp) gfp_t gfp)
{ {
struct vring_virtqueue *vq = to_vvq(_vq); struct vring_virtqueue *vq = to_vvq(_vq);
...@@ -275,6 +276,7 @@ static inline int virtqueue_add(struct virtqueue *_vq, ...@@ -275,6 +276,7 @@ static inline int virtqueue_add(struct virtqueue *_vq,
START_USE(vq); START_USE(vq);
BUG_ON(data == NULL); BUG_ON(data == NULL);
BUG_ON(ctx && vq->indirect);
if (unlikely(vq->broken)) { if (unlikely(vq->broken)) {
END_USE(vq); END_USE(vq);
...@@ -389,6 +391,8 @@ static inline int virtqueue_add(struct virtqueue *_vq, ...@@ -389,6 +391,8 @@ static inline int virtqueue_add(struct virtqueue *_vq,
vq->desc_state[head].data = data; vq->desc_state[head].data = data;
if (indirect) if (indirect)
vq->desc_state[head].indir_desc = desc; vq->desc_state[head].indir_desc = desc;
if (ctx)
vq->desc_state[head].indir_desc = ctx;
/* Put entry in available array (but don't update avail->idx until they /* Put entry in available array (but don't update avail->idx until they
* do sync). */ * do sync). */
...@@ -461,7 +465,8 @@ int virtqueue_add_sgs(struct virtqueue *_vq, ...@@ -461,7 +465,8 @@ int virtqueue_add_sgs(struct virtqueue *_vq,
for (sg = sgs[i]; sg; sg = sg_next(sg)) for (sg = sgs[i]; sg; sg = sg_next(sg))
total_sg++; total_sg++;
} }
return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs, data, gfp); return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs,
data, NULL, gfp);
} }
EXPORT_SYMBOL_GPL(virtqueue_add_sgs); EXPORT_SYMBOL_GPL(virtqueue_add_sgs);
...@@ -483,7 +488,7 @@ int virtqueue_add_outbuf(struct virtqueue *vq, ...@@ -483,7 +488,7 @@ int virtqueue_add_outbuf(struct virtqueue *vq,
void *data, void *data,
gfp_t gfp) gfp_t gfp)
{ {
return virtqueue_add(vq, &sg, num, 1, 0, data, gfp); return virtqueue_add(vq, &sg, num, 1, 0, data, NULL, gfp);
} }
EXPORT_SYMBOL_GPL(virtqueue_add_outbuf); EXPORT_SYMBOL_GPL(virtqueue_add_outbuf);
...@@ -505,10 +510,34 @@ int virtqueue_add_inbuf(struct virtqueue *vq, ...@@ -505,10 +510,34 @@ int virtqueue_add_inbuf(struct virtqueue *vq,
void *data, void *data,
gfp_t gfp) gfp_t gfp)
{ {
return virtqueue_add(vq, &sg, num, 0, 1, data, gfp); return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, gfp);
} }
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf); EXPORT_SYMBOL_GPL(virtqueue_add_inbuf);
/**
* virtqueue_add_inbuf_ctx - expose input buffers to other end
* @vq: the struct virtqueue we're talking about.
* @sg: scatterlist (must be well-formed and terminated!)
* @num: the number of entries in @sg writable by other side
* @data: the token identifying the buffer.
* @ctx: extra context for the token
* @gfp: how to do memory allocations (if necessary).
*
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
*
* Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
*/
int virtqueue_add_inbuf_ctx(struct virtqueue *vq,
struct scatterlist *sg, unsigned int num,
void *data,
void *ctx,
gfp_t gfp)
{
return virtqueue_add(vq, &sg, num, 0, 1, data, ctx, gfp);
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_ctx);
/** /**
* virtqueue_kick_prepare - first half of split virtqueue_kick call. * virtqueue_kick_prepare - first half of split virtqueue_kick call.
* @vq: the struct virtqueue * @vq: the struct virtqueue
...@@ -598,7 +627,8 @@ bool virtqueue_kick(struct virtqueue *vq) ...@@ -598,7 +627,8 @@ bool virtqueue_kick(struct virtqueue *vq)
} }
EXPORT_SYMBOL_GPL(virtqueue_kick); EXPORT_SYMBOL_GPL(virtqueue_kick);
static void detach_buf(struct vring_virtqueue *vq, unsigned int head) static void detach_buf(struct vring_virtqueue *vq, unsigned int head,
void **ctx)
{ {
unsigned int i, j; unsigned int i, j;
__virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); __virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT);
...@@ -622,10 +652,15 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head) ...@@ -622,10 +652,15 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
/* Plus final descriptor */ /* Plus final descriptor */
vq->vq.num_free++; vq->vq.num_free++;
/* Free the indirect table, if any, now that it's unmapped. */ if (vq->indirect) {
if (vq->desc_state[head].indir_desc) {
struct vring_desc *indir_desc = vq->desc_state[head].indir_desc; struct vring_desc *indir_desc = vq->desc_state[head].indir_desc;
u32 len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len); u32 len;
/* Free the indirect table, if any, now that it's unmapped. */
if (!indir_desc)
return;
len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len);
BUG_ON(!(vq->vring.desc[head].flags & BUG_ON(!(vq->vring.desc[head].flags &
cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))); cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT)));
...@@ -634,8 +669,10 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head) ...@@ -634,8 +669,10 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
for (j = 0; j < len / sizeof(struct vring_desc); j++) for (j = 0; j < len / sizeof(struct vring_desc); j++)
vring_unmap_one(vq, &indir_desc[j]); vring_unmap_one(vq, &indir_desc[j]);
kfree(vq->desc_state[head].indir_desc); kfree(indir_desc);
vq->desc_state[head].indir_desc = NULL; vq->desc_state[head].indir_desc = NULL;
} else if (ctx) {
*ctx = vq->desc_state[head].indir_desc;
} }
} }
...@@ -660,7 +697,8 @@ static inline bool more_used(const struct vring_virtqueue *vq) ...@@ -660,7 +697,8 @@ static inline bool more_used(const struct vring_virtqueue *vq)
* Returns NULL if there are no used buffers, or the "data" token * Returns NULL if there are no used buffers, or the "data" token
* handed to virtqueue_add_*(). * handed to virtqueue_add_*().
*/ */
void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) void *virtqueue_get_buf_ctx(struct virtqueue *_vq, unsigned int *len,
void **ctx)
{ {
struct vring_virtqueue *vq = to_vvq(_vq); struct vring_virtqueue *vq = to_vvq(_vq);
void *ret; void *ret;
...@@ -698,7 +736,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) ...@@ -698,7 +736,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
/* detach_buf clears data, so grab it now. */ /* detach_buf clears data, so grab it now. */
ret = vq->desc_state[i].data; ret = vq->desc_state[i].data;
detach_buf(vq, i); detach_buf(vq, i, ctx);
vq->last_used_idx++; vq->last_used_idx++;
/* If we expect an interrupt for the next entry, tell host /* If we expect an interrupt for the next entry, tell host
* by writing event index and flush out the write before * by writing event index and flush out the write before
...@@ -715,8 +753,13 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) ...@@ -715,8 +753,13 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
END_USE(vq); END_USE(vq);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(virtqueue_get_buf); EXPORT_SYMBOL_GPL(virtqueue_get_buf_ctx);
void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
{
return virtqueue_get_buf_ctx(_vq, len, NULL);
}
EXPORT_SYMBOL_GPL(virtqueue_get_buf);
/** /**
* virtqueue_disable_cb - disable callbacks * virtqueue_disable_cb - disable callbacks
* @vq: the struct virtqueue we're talking about. * @vq: the struct virtqueue we're talking about.
...@@ -878,7 +921,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq) ...@@ -878,7 +921,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
continue; continue;
/* detach_buf clears data, so grab it now. */ /* detach_buf clears data, so grab it now. */
buf = vq->desc_state[i].data; buf = vq->desc_state[i].data;
detach_buf(vq, i); detach_buf(vq, i, NULL);
vq->avail_idx_shadow--; vq->avail_idx_shadow--;
vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow);
END_USE(vq); END_USE(vq);
...@@ -916,6 +959,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, ...@@ -916,6 +959,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
struct vring vring, struct vring vring,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool context,
bool (*notify)(struct virtqueue *), bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *), void (*callback)(struct virtqueue *),
const char *name) const char *name)
...@@ -950,7 +994,8 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, ...@@ -950,7 +994,8 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
vq->last_add_time_valid = false; vq->last_add_time_valid = false;
#endif #endif
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC); vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
!context;
vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
/* No callback? Tell other side not to bother us. */ /* No callback? Tell other side not to bother us. */
...@@ -1019,6 +1064,7 @@ struct virtqueue *vring_create_virtqueue( ...@@ -1019,6 +1064,7 @@ struct virtqueue *vring_create_virtqueue(
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool may_reduce_num, bool may_reduce_num,
bool context,
bool (*notify)(struct virtqueue *), bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *), void (*callback)(struct virtqueue *),
const char *name) const char *name)
...@@ -1058,7 +1104,7 @@ struct virtqueue *vring_create_virtqueue( ...@@ -1058,7 +1104,7 @@ struct virtqueue *vring_create_virtqueue(
queue_size_in_bytes = vring_size(num, vring_align); queue_size_in_bytes = vring_size(num, vring_align);
vring_init(&vring, num, queue, vring_align); vring_init(&vring, num, queue, vring_align);
vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, context,
notify, callback, name); notify, callback, name);
if (!vq) { if (!vq) {
vring_free_queue(vdev, queue_size_in_bytes, queue, vring_free_queue(vdev, queue_size_in_bytes, queue,
...@@ -1079,6 +1125,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -1079,6 +1125,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
unsigned int vring_align, unsigned int vring_align,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool context,
void *pages, void *pages,
bool (*notify)(struct virtqueue *vq), bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
...@@ -1086,7 +1133,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -1086,7 +1133,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
{ {
struct vring vring; struct vring vring;
vring_init(&vring, num, pages, vring_align); vring_init(&vring, num, pages, vring_align);
return __vring_new_virtqueue(index, vring, vdev, weak_barriers, return __vring_new_virtqueue(index, vring, vdev, weak_barriers, context,
notify, callback, name); notify, callback, name);
} }
EXPORT_SYMBOL_GPL(vring_new_virtqueue); EXPORT_SYMBOL_GPL(vring_new_virtqueue);
......
...@@ -34,11 +34,13 @@ ...@@ -34,11 +34,13 @@
struct ptr_ring { struct ptr_ring {
int producer ____cacheline_aligned_in_smp; int producer ____cacheline_aligned_in_smp;
spinlock_t producer_lock; spinlock_t producer_lock;
int consumer ____cacheline_aligned_in_smp; int consumer_head ____cacheline_aligned_in_smp; /* next valid entry */
int consumer_tail; /* next entry to invalidate */
spinlock_t consumer_lock; spinlock_t consumer_lock;
/* Shared consumer/producer data */ /* Shared consumer/producer data */
/* Read-only by both the producer and the consumer */ /* Read-only by both the producer and the consumer */
int size ____cacheline_aligned_in_smp; /* max entries in queue */ int size ____cacheline_aligned_in_smp; /* max entries in queue */
int batch; /* number of entries to consume in a batch */
void **queue; void **queue;
}; };
...@@ -170,7 +172,7 @@ static inline int ptr_ring_produce_bh(struct ptr_ring *r, void *ptr) ...@@ -170,7 +172,7 @@ static inline int ptr_ring_produce_bh(struct ptr_ring *r, void *ptr)
static inline void *__ptr_ring_peek(struct ptr_ring *r) static inline void *__ptr_ring_peek(struct ptr_ring *r)
{ {
if (likely(r->size)) if (likely(r->size))
return r->queue[r->consumer]; return r->queue[r->consumer_head];
return NULL; return NULL;
} }
...@@ -231,9 +233,38 @@ static inline bool ptr_ring_empty_bh(struct ptr_ring *r) ...@@ -231,9 +233,38 @@ static inline bool ptr_ring_empty_bh(struct ptr_ring *r)
/* Must only be called after __ptr_ring_peek returned !NULL */ /* Must only be called after __ptr_ring_peek returned !NULL */
static inline void __ptr_ring_discard_one(struct ptr_ring *r) static inline void __ptr_ring_discard_one(struct ptr_ring *r)
{ {
r->queue[r->consumer++] = NULL; /* Fundamentally, what we want to do is update consumer
if (unlikely(r->consumer >= r->size)) * index and zero out the entry so producer can reuse it.
r->consumer = 0; * Doing it naively at each consume would be as simple as:
* r->queue[r->consumer++] = NULL;
* if (unlikely(r->consumer >= r->size))
* r->consumer = 0;
* but that is suboptimal when the ring is full as producer is writing
* out new entries in the same cache line. Defer these updates until a
* batch of entries has been consumed.
*/
int head = r->consumer_head++;
/* Once we have processed enough entries invalidate them in
* the ring all at once so producer can reuse their space in the ring.
* We also do this when we reach end of the ring - not mandatory
* but helps keep the implementation simple.
*/
if (unlikely(r->consumer_head - r->consumer_tail >= r->batch ||
r->consumer_head >= r->size)) {
/* Zero out entries in the reverse order: this way we touch the
* cache line that producer might currently be reading the last;
* producer won't make progress and touch other cache lines
* besides the first one until we write out all entries.
*/
while (likely(head >= r->consumer_tail))
r->queue[head--] = NULL;
r->consumer_tail = r->consumer_head;
}
if (unlikely(r->consumer_head >= r->size)) {
r->consumer_head = 0;
r->consumer_tail = 0;
}
} }
static inline void *__ptr_ring_consume(struct ptr_ring *r) static inline void *__ptr_ring_consume(struct ptr_ring *r)
...@@ -345,14 +376,27 @@ static inline void **__ptr_ring_init_queue_alloc(int size, gfp_t gfp) ...@@ -345,14 +376,27 @@ static inline void **__ptr_ring_init_queue_alloc(int size, gfp_t gfp)
return kzalloc(ALIGN(size * sizeof(void *), SMP_CACHE_BYTES), gfp); return kzalloc(ALIGN(size * sizeof(void *), SMP_CACHE_BYTES), gfp);
} }
static inline void __ptr_ring_set_size(struct ptr_ring *r, int size)
{
r->size = size;
r->batch = SMP_CACHE_BYTES * 2 / sizeof(*(r->queue));
/* We need to set batch at least to 1 to make logic
* in __ptr_ring_discard_one work correctly.
* Batching too much (because ring is small) would cause a lot of
* burstiness. Needs tuning, for now disable batching.
*/
if (r->batch > r->size / 2 || !r->batch)
r->batch = 1;
}
static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp) static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
{ {
r->queue = __ptr_ring_init_queue_alloc(size, gfp); r->queue = __ptr_ring_init_queue_alloc(size, gfp);
if (!r->queue) if (!r->queue)
return -ENOMEM; return -ENOMEM;
r->size = size; __ptr_ring_set_size(r, size);
r->producer = r->consumer = 0; r->producer = r->consumer_head = r->consumer_tail = 0;
spin_lock_init(&r->producer_lock); spin_lock_init(&r->producer_lock);
spin_lock_init(&r->consumer_lock); spin_lock_init(&r->consumer_lock);
...@@ -373,9 +417,10 @@ static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue, ...@@ -373,9 +417,10 @@ static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
else if (destroy) else if (destroy)
destroy(ptr); destroy(ptr);
r->size = size; __ptr_ring_set_size(r, size);
r->producer = producer; r->producer = producer;
r->consumer = 0; r->consumer_head = 0;
r->consumer_tail = 0;
old = r->queue; old = r->queue;
r->queue = queue; r->queue = queue;
......
...@@ -44,6 +44,12 @@ int virtqueue_add_inbuf(struct virtqueue *vq, ...@@ -44,6 +44,12 @@ int virtqueue_add_inbuf(struct virtqueue *vq,
void *data, void *data,
gfp_t gfp); gfp_t gfp);
int virtqueue_add_inbuf_ctx(struct virtqueue *vq,
struct scatterlist sg[], unsigned int num,
void *data,
void *ctx,
gfp_t gfp);
int virtqueue_add_sgs(struct virtqueue *vq, int virtqueue_add_sgs(struct virtqueue *vq,
struct scatterlist *sgs[], struct scatterlist *sgs[],
unsigned int out_sgs, unsigned int out_sgs,
...@@ -59,6 +65,9 @@ bool virtqueue_notify(struct virtqueue *vq); ...@@ -59,6 +65,9 @@ bool virtqueue_notify(struct virtqueue *vq);
void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
void *virtqueue_get_buf_ctx(struct virtqueue *vq, unsigned int *len,
void **ctx);
void virtqueue_disable_cb(struct virtqueue *vq); void virtqueue_disable_cb(struct virtqueue *vq);
bool virtqueue_enable_cb(struct virtqueue *vq); bool virtqueue_enable_cb(struct virtqueue *vq);
...@@ -156,9 +165,13 @@ int virtio_device_restore(struct virtio_device *dev); ...@@ -156,9 +165,13 @@ int virtio_device_restore(struct virtio_device *dev);
* @feature_table_legacy: same as feature_table but when working in legacy mode. * @feature_table_legacy: same as feature_table but when working in legacy mode.
* @feature_table_size_legacy: number of entries in feature table legacy array. * @feature_table_size_legacy: number of entries in feature table legacy array.
* @probe: the function to call when a device is found. Returns 0 or -errno. * @probe: the function to call when a device is found. Returns 0 or -errno.
* @scan: optional function to call after successful probe; intended
* for virtio-scsi to invoke a scan.
* @remove: the function to call when a device is removed. * @remove: the function to call when a device is removed.
* @config_changed: optional function to call when the device configuration * @config_changed: optional function to call when the device configuration
* changes; may be called in interrupt context. * changes; may be called in interrupt context.
* @freeze: optional function to call during suspend/hibernation.
* @restore: optional function to call on resume.
*/ */
struct virtio_driver { struct virtio_driver {
struct device_driver driver; struct device_driver driver;
......
...@@ -72,7 +72,8 @@ struct virtio_config_ops { ...@@ -72,7 +72,8 @@ struct virtio_config_ops {
void (*reset)(struct virtio_device *vdev); void (*reset)(struct virtio_device *vdev);
int (*find_vqs)(struct virtio_device *, unsigned nvqs, int (*find_vqs)(struct virtio_device *, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[], struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[], struct irq_affinity *desc); const char * const names[], const bool *ctx,
struct irq_affinity *desc);
void (*del_vqs)(struct virtio_device *); void (*del_vqs)(struct virtio_device *);
u64 (*get_features)(struct virtio_device *vdev); u64 (*get_features)(struct virtio_device *vdev);
int (*finalize_features)(struct virtio_device *vdev); int (*finalize_features)(struct virtio_device *vdev);
...@@ -173,12 +174,32 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, ...@@ -173,12 +174,32 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
vq_callback_t *callbacks[] = { c }; vq_callback_t *callbacks[] = { c };
const char *names[] = { n }; const char *names[] = { n };
struct virtqueue *vq; struct virtqueue *vq;
int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL); int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names, NULL,
NULL);
if (err < 0) if (err < 0)
return ERR_PTR(err); return ERR_PTR(err);
return vq; return vq;
} }
static inline
int virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[],
struct irq_affinity *desc)
{
return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, NULL, desc);
}
static inline
int virtio_find_vqs_ctx(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[], vq_callback_t *callbacks[],
const char * const names[], const bool *ctx,
struct irq_affinity *desc)
{
return vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names, ctx,
desc);
}
/** /**
* virtio_device_ready - enable vq use in probe function * virtio_device_ready - enable vq use in probe function
* @vdev: the device * @vdev: the device
......
...@@ -71,6 +71,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, ...@@ -71,6 +71,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool may_reduce_num, bool may_reduce_num,
bool ctx,
bool (*notify)(struct virtqueue *vq), bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name); const char *name);
...@@ -80,6 +81,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, ...@@ -80,6 +81,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
struct vring vring, struct vring vring,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool ctx,
bool (*notify)(struct virtqueue *), bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *), void (*callback)(struct virtqueue *),
const char *name); const char *name);
...@@ -93,6 +95,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -93,6 +95,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
unsigned int vring_align, unsigned int vring_align,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool ctx,
void *pages, void *pages,
bool (*notify)(struct virtqueue *vq), bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
......
...@@ -576,7 +576,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev) ...@@ -576,7 +576,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
vsock->vdev = vdev; vsock->vdev = vdev;
ret = vsock->vdev->config->find_vqs(vsock->vdev, VSOCK_VQ_MAX, ret = virtio_find_vqs(vsock->vdev, VSOCK_VQ_MAX,
vsock->vqs, callbacks, names, vsock->vqs, callbacks, names,
NULL); NULL);
if (ret < 0) if (ret < 0)
......
...@@ -57,6 +57,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -57,6 +57,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
unsigned int vring_align, unsigned int vring_align,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
bool ctx,
void *pages, void *pages,
bool (*notify)(struct virtqueue *vq), bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
int runcycles = 10000000; int runcycles = 10000000;
int max_outstanding = INT_MAX; int max_outstanding = INT_MAX;
int batch = 1; int batch = 1;
int param = 0;
bool do_sleep = false; bool do_sleep = false;
bool do_relax = false; bool do_relax = false;
...@@ -86,7 +87,7 @@ void set_affinity(const char *arg) ...@@ -86,7 +87,7 @@ void set_affinity(const char *arg)
cpu = strtol(arg, &endptr, 0); cpu = strtol(arg, &endptr, 0);
assert(!*endptr); assert(!*endptr);
assert(cpu >= 0 || cpu < CPU_SETSIZE); assert(cpu >= 0 && cpu < CPU_SETSIZE);
self = pthread_self(); self = pthread_self();
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
...@@ -246,6 +247,11 @@ static const struct option longopts[] = { ...@@ -246,6 +247,11 @@ static const struct option longopts[] = {
.has_arg = required_argument, .has_arg = required_argument,
.val = 'b', .val = 'b',
}, },
{
.name = "param",
.has_arg = required_argument,
.val = 'p',
},
{ {
.name = "sleep", .name = "sleep",
.has_arg = no_argument, .has_arg = no_argument,
...@@ -274,6 +280,7 @@ static void help(void) ...@@ -274,6 +280,7 @@ static void help(void)
" [--run-cycles C (default: %d)]" " [--run-cycles C (default: %d)]"
" [--batch b]" " [--batch b]"
" [--outstanding o]" " [--outstanding o]"
" [--param p]"
" [--sleep]" " [--sleep]"
" [--relax]" " [--relax]"
" [--exit]" " [--exit]"
...@@ -328,6 +335,12 @@ int main(int argc, char **argv) ...@@ -328,6 +335,12 @@ int main(int argc, char **argv)
assert(c > 0 && c < INT_MAX); assert(c > 0 && c < INT_MAX);
max_outstanding = c; max_outstanding = c;
break; break;
case 'p':
c = strtol(optarg, &endptr, 0);
assert(!*endptr);
assert(c > 0 && c < INT_MAX);
param = c;
break;
case 'b': case 'b':
c = strtol(optarg, &endptr, 0); c = strtol(optarg, &endptr, 0);
assert(!*endptr); assert(!*endptr);
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <stdbool.h> #include <stdbool.h>
extern int param;
extern bool do_exit; extern bool do_exit;
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
......
...@@ -97,6 +97,9 @@ void alloc_ring(void) ...@@ -97,6 +97,9 @@ void alloc_ring(void)
{ {
int ret = ptr_ring_init(&array, ring_size, 0); int ret = ptr_ring_init(&array, ring_size, 0);
assert(!ret); assert(!ret);
/* Hacky way to poke at ring internals. Useful for testing though. */
if (param)
array.batch = param;
} }
/* guest side */ /* guest side */
......
...@@ -100,7 +100,7 @@ static void vq_info_add(struct vdev_info *dev, int num) ...@@ -100,7 +100,7 @@ static void vq_info_add(struct vdev_info *dev, int num)
vring_init(&info->vring, num, info->ring, 4096); vring_init(&info->vring, num, info->ring, 4096);
info->vq = vring_new_virtqueue(info->idx, info->vq = vring_new_virtqueue(info->idx,
info->vring.num, 4096, &dev->vdev, info->vring.num, 4096, &dev->vdev,
true, info->ring, true, false, info->ring,
vq_notify, vq_callback, "test"); vq_notify, vq_callback, "test");
assert(info->vq); assert(info->vq);
info->vq->priv = info; info->vq->priv = info;
...@@ -202,7 +202,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, ...@@ -202,7 +202,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
test = 0; test = 0;
r = ioctl(dev->control, VHOST_TEST_RUN, &test); r = ioctl(dev->control, VHOST_TEST_RUN, &test);
assert(r >= 0); assert(r >= 0);
fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious); fprintf(stderr, "spurious wakeups: 0x%llx\n", spurious);
} }
const char optstring[] = "h"; const char optstring[] = "h";
......
...@@ -314,7 +314,8 @@ static int parallel_test(u64 features, ...@@ -314,7 +314,8 @@ static int parallel_test(u64 features,
err(1, "Could not set affinity to cpu %u", first_cpu); err(1, "Could not set affinity to cpu %u", first_cpu);
vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &gvdev.vdev, true, vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &gvdev.vdev, true,
guest_map, fast_vringh ? no_notify_host false, guest_map,
fast_vringh ? no_notify_host
: parallel_notify_host, : parallel_notify_host,
never_callback_guest, "guest vq"); never_callback_guest, "guest vq");
...@@ -479,7 +480,7 @@ int main(int argc, char *argv[]) ...@@ -479,7 +480,7 @@ int main(int argc, char *argv[])
memset(__user_addr_min, 0, vring_size(RINGSIZE, ALIGN)); memset(__user_addr_min, 0, vring_size(RINGSIZE, ALIGN));
/* Set up guest side. */ /* Set up guest side. */
vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, false,
__user_addr_min, __user_addr_min,
never_notify_host, never_callback_guest, never_notify_host, never_callback_guest,
"guest vq"); "guest vq");
...@@ -663,7 +664,7 @@ int main(int argc, char *argv[]) ...@@ -663,7 +664,7 @@ int main(int argc, char *argv[])
/* Force creation of direct, which we modify. */ /* Force creation of direct, which we modify. */
__virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC); __virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true,
__user_addr_min, false, __user_addr_min,
never_notify_host, never_notify_host,
never_callback_guest, never_callback_guest,
"guest vq"); "guest 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