Eliminate the code duplication between virtqueue_add_buf and
virtqueue_add_sg.  That's safe to do now that no devices will
pass scatterlists with a termination marker in the middle.

Signed-off-by: Paolo Bonzini <pbonz...@redhat.com>
---
 drivers/virtio/virtio_ring.c |  159 +++---------------------------------------
 1 files changed, 11 insertions(+), 148 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b803cf7..71488c5 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -123,63 +123,6 @@ struct vring_virtqueue
 
 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
 
-/* Set up an indirect table of descriptors and add it to the queue. */
-static int vring_add_indirect(struct vring_virtqueue *vq,
-                             struct scatterlist sg[],
-                             unsigned int out,
-                             unsigned int in,
-                             gfp_t gfp)
-{
-       struct vring_desc *desc;
-       unsigned head;
-       int i;
-
-       /*
-        * We require lowmem mappings for the descriptors because
-        * otherwise virt_to_phys will give us bogus addresses in the
-        * virtqueue.
-        */
-       gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH);
-
-       desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp);
-       if (!desc)
-               return -ENOMEM;
-
-       /* Transfer entries from the sg list into the indirect page */
-       for (i = 0; i < out; i++) {
-               desc[i].flags = VRING_DESC_F_NEXT;
-               desc[i].addr = sg_phys(sg);
-               desc[i].len = sg->length;
-               desc[i].next = i+1;
-               sg++;
-       }
-       for (; i < (out + in); i++) {
-               desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
-               desc[i].addr = sg_phys(sg);
-               desc[i].len = sg->length;
-               desc[i].next = i+1;
-               sg++;
-       }
-
-       /* Last one doesn't continue. */
-       desc[i-1].flags &= ~VRING_DESC_F_NEXT;
-       desc[i-1].next = 0;
-
-       /* We're about to use a buffer */
-       vq->vq.num_free--;
-
-       /* Use a single buffer which doesn't continue */
-       head = vq->free_head;
-       vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
-       vq->vring.desc[head].addr = virt_to_phys(desc);
-       vq->vring.desc[head].len = i * sizeof(struct vring_desc);
-
-       /* Update free pointer */
-       vq->free_head = vq->vring.desc[head].next;
-
-       return head;
-}
-
 /**
  * virtqueue_add_buf_single - expose a single scatterlist entry to other end
  * @vq: the struct virtqueue we're talking about.
@@ -234,104 +177,25 @@ EXPORT_SYMBOL_GPL(virtqueue_add_buf_single);
  *
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
  */
-int virtqueue_add_buf(struct virtqueue *_vq,
+int virtqueue_add_buf(struct virtqueue *vq,
                      struct scatterlist sg[],
                      unsigned int out,
                      unsigned int in,
                      void *data,
                      gfp_t gfp)
 {
-       struct vring_virtqueue *vq = to_vvq(_vq);
-       unsigned int i, avail, uninitialized_var(prev);
-       int head;
-
-       START_USE(vq);
-
-       BUG_ON(data == NULL);
-
-#ifdef DEBUG
-       {
-               ktime_t now = ktime_get();
-
-               /* No kick or get, with .1 second between?  Warn. */
-               if (vq->last_add_time_valid)
-                       WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time))
-                                           > 100);
-               vq->last_add_time = now;
-               vq->last_add_time_valid = true;
-       }
-#endif
-
-       /* If the host supports indirect descriptor tables, and we have multiple
-        * buffers, then go indirect. FIXME: tune this threshold */
-       if (vq->indirect && (out + in) > 1 && vq->vq.num_free) {
-               head = vring_add_indirect(vq, sg, out, in, gfp);
-               if (likely(head >= 0))
-                       goto add_head;
-       }
-
-       BUG_ON(out + in > vq->vring.num);
-       BUG_ON(out + in == 0);
-
-       if (vq->vq.num_free < out + in) {
-               pr_debug("Can't add buf len %i - avail = %i\n",
-                        out + in, vq->vq.num_free);
-               /* FIXME: for historical reasons, we force a notify here if
-                * there are outgoing parts to the buffer.  Presumably the
-                * host should service the ring ASAP. */
-               if (out)
-                       vq->notify(&vq->vq);
-               END_USE(vq);
-               return -ENOSPC;
-       }
-
-       /* We're about to use some buffers from the free list. */
-       vq->vq.num_free -= out + in;
-
-       head = vq->free_head;
-       for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
-               vq->vring.desc[i].flags = VRING_DESC_F_NEXT;
-               vq->vring.desc[i].addr = sg_phys(sg);
-               vq->vring.desc[i].len = sg->length;
-               prev = i;
-               sg++;
-       }
-       for (; in; i = vq->vring.desc[i].next, in--) {
-               vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
-               vq->vring.desc[i].addr = sg_phys(sg);
-               vq->vring.desc[i].len = sg->length;
-               prev = i;
-               sg++;
-       }
-       /* Last one doesn't continue. */
-       vq->vring.desc[prev].flags &= ~VRING_DESC_F_NEXT;
-
-       /* Update free pointer */
-       vq->free_head = i;
-
-add_head:
-       /* Set token. */
-       vq->data[head] = data;
-
-       /* Put entry in available array (but don't update avail->idx until they
-        * do sync). */
-       avail = (vq->vring.avail->idx & (vq->vring.num-1));
-       vq->vring.avail->ring[avail] = head;
-
-       /* Descriptors and available array need to be set before we expose the
-        * new available array entries. */
-       virtio_wmb(vq);
-       vq->vring.avail->idx++;
-       vq->num_added++;
+       int ret;
 
-       /* This is very unlikely, but theoretically possible.  Kick
-        * just in case. */
-       if (unlikely(vq->num_added == (1 << 16) - 1))
-               virtqueue_kick(_vq);
+       ret = virtqueue_start_buf(vq, data, out + in, !!out + !!in, gfp);
+       if (ret < 0)
+               return ret;
 
-       pr_debug("Added buffer head %i to %p\n", head, vq);
-       END_USE(vq);
+       if (out)
+               virtqueue_add_sg(vq, sg, out, DMA_TO_DEVICE);
+       if (in)
+               virtqueue_add_sg(vq, sg + out, in, DMA_FROM_DEVICE);
 
+       virtqueue_end_buf(vq);
        return 0;
 }
 EXPORT_SYMBOL_GPL(virtqueue_add_buf);
@@ -537,8 +401,7 @@ EXPORT_SYMBOL_GPL(virtqueue_start_buf);
  * @nents: the number of items to process in sgl
  * @dir: whether the sgl is read or written (DMA_TO_DEVICE/DMA_FROM_DEVICE 
only)
  *
- * Note that, unlike virtqueue_add_buf, this function follows chained
- * scatterlists, and stops before the @nents-th item if a scatterlist item
+ * This function will stop before the @nents-th item if a scatterlist item
  * has a marker.
  *
  * Caller must ensure we don't call this with other virtqueue operations
-- 
1.7.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

Reply via email to