|
@@ -41,6 +41,7 @@
|
|
* @svq: tx virtqueue
|
|
* @svq: tx virtqueue
|
|
* @rbufs: kernel address of rx buffers
|
|
* @rbufs: kernel address of rx buffers
|
|
* @sbufs: kernel address of tx 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
|
|
* @last_sbuf: index of last tx buffer used
|
|
* @bufs_dma: dma base addr of the buffers
|
|
* @bufs_dma: dma base addr of the buffers
|
|
* @tx_lock: protects svq, sbufs and sleepers, to allow concurrent senders.
|
|
* @tx_lock: protects svq, sbufs and sleepers, to allow concurrent senders.
|
|
@@ -60,6 +61,7 @@ struct virtproc_info {
|
|
struct virtio_device *vdev;
|
|
struct virtio_device *vdev;
|
|
struct virtqueue *rvq, *svq;
|
|
struct virtqueue *rvq, *svq;
|
|
void *rbufs, *sbufs;
|
|
void *rbufs, *sbufs;
|
|
|
|
+ unsigned int num_bufs;
|
|
int last_sbuf;
|
|
int last_sbuf;
|
|
dma_addr_t bufs_dma;
|
|
dma_addr_t bufs_dma;
|
|
struct mutex tx_lock;
|
|
struct mutex tx_lock;
|
|
@@ -86,13 +88,14 @@ struct rpmsg_channel_info {
|
|
#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
|
|
#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
|
|
* Each buffer will have 16 bytes for the msg header and 496 bytes for
|
|
* the payload.
|
|
* 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.
|
|
* 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
|
|
* 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
|
|
* can change this without changing anything in the firmware of the remote
|
|
* processor.
|
|
* processor.
|
|
*/
|
|
*/
|
|
-#define RPMSG_NUM_BUFS (512)
|
|
|
|
|
|
+#define MAX_RPMSG_NUM_BUFS (512)
|
|
#define RPMSG_BUF_SIZE (512)
|
|
#define RPMSG_BUF_SIZE (512)
|
|
-#define RPMSG_TOTAL_BUF_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Local addresses are dynamically allocated on-demand.
|
|
* 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
|
|
* either pick the next unused tx buffer
|
|
* (half of our buffers are used for sending messages)
|
|
* (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++;
|
|
ret = vrp->sbufs + RPMSG_BUF_SIZE * vrp->last_sbuf++;
|
|
/* or recycle a used one */
|
|
/* or recycle a used one */
|
|
else
|
|
else
|
|
@@ -948,6 +950,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
|
struct virtproc_info *vrp;
|
|
struct virtproc_info *vrp;
|
|
void *bufs_va;
|
|
void *bufs_va;
|
|
int err = 0, i;
|
|
int err = 0, i;
|
|
|
|
+ size_t total_buf_space;
|
|
|
|
|
|
vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
|
|
vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
|
|
if (!vrp)
|
|
if (!vrp)
|
|
@@ -968,10 +971,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
|
vrp->rvq = vqs[0];
|
|
vrp->rvq = vqs[0];
|
|
vrp->svq = vqs[1];
|
|
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 */
|
|
/* allocate coherent memory for the buffers */
|
|
bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
|
|
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) {
|
|
if (!bufs_va) {
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
goto vqs_del;
|
|
goto vqs_del;
|
|
@@ -984,10 +999,10 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
|
vrp->rbufs = bufs_va;
|
|
vrp->rbufs = bufs_va;
|
|
|
|
|
|
/* and half is dedicated for TX */
|
|
/* 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 */
|
|
/* 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;
|
|
struct scatterlist sg;
|
|
void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
|
|
void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
|
|
|
|
|
|
@@ -1023,8 +1038,8 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
free_coherent:
|
|
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:
|
|
vqs_del:
|
|
vdev->config->del_vqs(vrp->vdev);
|
|
vdev->config->del_vqs(vrp->vdev);
|
|
free_vrp:
|
|
free_vrp:
|
|
@@ -1042,6 +1057,7 @@ static int rpmsg_remove_device(struct device *dev, void *data)
|
|
static void rpmsg_remove(struct virtio_device *vdev)
|
|
static void rpmsg_remove(struct virtio_device *vdev)
|
|
{
|
|
{
|
|
struct virtproc_info *vrp = vdev->priv;
|
|
struct virtproc_info *vrp = vdev->priv;
|
|
|
|
+ size_t total_buf_space = vrp->num_bufs * RPMSG_BUF_SIZE;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
vdev->config->reset(vdev);
|
|
vdev->config->reset(vdev);
|
|
@@ -1057,8 +1073,8 @@ static void rpmsg_remove(struct virtio_device *vdev)
|
|
|
|
|
|
vdev->config->del_vqs(vrp->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);
|
|
kfree(vrp);
|
|
}
|
|
}
|