Merge tag 'rpmsg-3.19-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 01:07:58 +0000 (17:07 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 01:07:58 +0000 (17:07 -0800)
Pull rpmsg update from Ohad Ben-Cohen:
 "A single patch from Suman Anna which makes rpmsg use less buffers when
  small vrings are being used"

* tag 'rpmsg-3.19-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg:
  rpmsg: use less buffers when vrings are small

drivers/rpmsg/virtio_rpmsg_bus.c

index b6135d4..92f6af6 100644 (file)
@@ -41,6 +41,7 @@
  * @svq:       tx virtqueue
  * @rbufs:     kernel address of rx buffers
  * @sbufs:     kernel address of tx buffers
+ * @num_bufs:  total number of buffers for rx and tx
  * @last_sbuf: index of last tx buffer used
  * @bufs_dma:  dma base addr of the buffers
  * @tx_lock:   protects svq, sbufs and sleepers, to allow concurrent senders.
@@ -60,6 +61,7 @@ struct virtproc_info {
        struct virtio_device *vdev;
        struct virtqueue *rvq, *svq;
        void *rbufs, *sbufs;
+       unsigned int num_bufs;
        int last_sbuf;
        dma_addr_t bufs_dma;
        struct mutex tx_lock;
@@ -86,13 +88,14 @@ struct rpmsg_channel_info {
 #define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
 
 /*
- * We're allocating 512 buffers of 512 bytes for communications, and then
- * using the first 256 buffers for RX, and the last 256 buffers for TX.
+ * We're allocating buffers of 512 bytes each for communications. The
+ * number of buffers will be computed from the number of buffers supported
+ * by the vring, upto a maximum of 512 buffers (256 in each direction).
  *
  * Each buffer will have 16 bytes for the msg header and 496 bytes for
  * the payload.
  *
- * This will require a total space of 256KB for the buffers.
+ * This will utilize a maximum total space of 256KB for the buffers.
  *
  * We might also want to add support for user-provided buffers in time.
  * This will allow bigger buffer size flexibility, and can also be used
@@ -102,9 +105,8 @@ struct rpmsg_channel_info {
  * can change this without changing anything in the firmware of the remote
  * processor.
  */
-#define RPMSG_NUM_BUFS         (512)
+#define MAX_RPMSG_NUM_BUFS     (512)
 #define RPMSG_BUF_SIZE         (512)
-#define RPMSG_TOTAL_BUF_SPACE  (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
 
 /*
  * Local addresses are dynamically allocated on-demand.
@@ -579,7 +581,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
         * either pick the next unused tx buffer
         * (half of our buffers are used for sending messages)
         */
-       if (vrp->last_sbuf < RPMSG_NUM_BUFS / 2)
+       if (vrp->last_sbuf < vrp->num_bufs / 2)
                ret = vrp->sbufs + RPMSG_BUF_SIZE * vrp->last_sbuf++;
        /* or recycle a used one */
        else
@@ -948,6 +950,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
        struct virtproc_info *vrp;
        void *bufs_va;
        int err = 0, i;
+       size_t total_buf_space;
 
        vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
        if (!vrp)
@@ -968,10 +971,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
        vrp->rvq = vqs[0];
        vrp->svq = vqs[1];
 
+       /* we expect symmetric tx/rx vrings */
+       WARN_ON(virtqueue_get_vring_size(vrp->rvq) !=
+               virtqueue_get_vring_size(vrp->svq));
+
+       /* we need less buffers if vrings are small */
+       if (virtqueue_get_vring_size(vrp->rvq) < MAX_RPMSG_NUM_BUFS / 2)
+               vrp->num_bufs = virtqueue_get_vring_size(vrp->rvq) * 2;
+       else
+               vrp->num_bufs = MAX_RPMSG_NUM_BUFS;
+
+       total_buf_space = vrp->num_bufs * RPMSG_BUF_SIZE;
+
        /* allocate coherent memory for the buffers */
        bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
-                               RPMSG_TOTAL_BUF_SPACE,
-                               &vrp->bufs_dma, GFP_KERNEL);
+                                    total_buf_space, &vrp->bufs_dma,
+                                    GFP_KERNEL);
        if (!bufs_va) {
                err = -ENOMEM;
                goto vqs_del;
@@ -984,10 +999,10 @@ static int rpmsg_probe(struct virtio_device *vdev)
        vrp->rbufs = bufs_va;
 
        /* and half is dedicated for TX */
-       vrp->sbufs = bufs_va + RPMSG_TOTAL_BUF_SPACE / 2;
+       vrp->sbufs = bufs_va + total_buf_space / 2;
 
        /* set up the receive buffers */
-       for (i = 0; i < RPMSG_NUM_BUFS / 2; i++) {
+       for (i = 0; i < vrp->num_bufs / 2; i++) {
                struct scatterlist sg;
                void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
 
@@ -1023,8 +1038,8 @@ static int rpmsg_probe(struct virtio_device *vdev)
        return 0;
 
 free_coherent:
-       dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE,
-                                       bufs_va, vrp->bufs_dma);
+       dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
+                         bufs_va, vrp->bufs_dma);
 vqs_del:
        vdev->config->del_vqs(vrp->vdev);
 free_vrp:
@@ -1042,6 +1057,7 @@ static int rpmsg_remove_device(struct device *dev, void *data)
 static void rpmsg_remove(struct virtio_device *vdev)
 {
        struct virtproc_info *vrp = vdev->priv;
+       size_t total_buf_space = vrp->num_bufs * RPMSG_BUF_SIZE;
        int ret;
 
        vdev->config->reset(vdev);
@@ -1057,8 +1073,8 @@ static void rpmsg_remove(struct virtio_device *vdev)
 
        vdev->config->del_vqs(vrp->vdev);
 
-       dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE,
-                                       vrp->rbufs, vrp->bufs_dma);
+       dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
+                         vrp->rbufs, vrp->bufs_dma);
 
        kfree(vrp);
 }