2019-01-31 15:42:21

by xiang xiao

[permalink] [raw]
Subject: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

Hi,
This series enhance the buffer allocation by:
1.Support the different buffer number in rx/tx direction
2.Get the individual rx/tx buffer size from config space

Here is the related OpenAMP change:
https://github.com/OpenAMP/open-amp/pull/155

Xiang Xiao (3):
rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv
rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately
rpmsg: virtio_rpmsg_bus: get buffer size from config space

drivers/rpmsg/virtio_rpmsg_bus.c | 127 +++++++++++++++++++++++---------------
include/uapi/linux/virtio_rpmsg.h | 24 +++++++
2 files changed, 100 insertions(+), 51 deletions(-)
create mode 100644 include/uapi/linux/virtio_rpmsg.h

--
2.7.4



2019-01-31 15:42:27

by xiang xiao

[permalink] [raw]
Subject: [PATCH 2/3] rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately

many dma allocator align the returned address with buffer size,
so two small allocation could reduce the alignment requirement
and save the the memory space wasted by the potential alignment.

Signed-off-by: Xiang Xiao <[email protected]>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 58 +++++++++++++++++++++++-----------------
1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index fb0d2eb..59c4554 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -40,7 +40,8 @@
* @num_sbufs: total number of buffers for tx
* @buf_size: size of one rx or tx buffer
* @last_sbuf: index of last tx buffer used
- * @bufs_dma: dma base addr of the buffers
+ * @rbufs_dma: dma base addr of rx buffers
+ * @sbufs_dma: dma base addr of tx buffers
* @tx_lock: protects svq, sbufs and sleepers, to allow concurrent senders.
* sending a message might require waking up a dozing remote
* processor, which involves sleeping, hence the mutex.
@@ -62,7 +63,8 @@ struct virtproc_info {
unsigned int num_sbufs;
unsigned int buf_size;
int last_sbuf;
- dma_addr_t bufs_dma;
+ dma_addr_t rbufs_dma;
+ dma_addr_t sbufs_dma;
struct mutex tx_lock;
struct idr endpoints;
struct mutex endpoints_lock;
@@ -872,9 +874,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
static const char * const names[] = { "input", "output" };
struct virtqueue *vqs[2];
struct virtproc_info *vrp;
- void *bufs_va;
int err = 0, i;
- size_t total_buf_space;
bool notify;

vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
@@ -909,25 +909,28 @@ static int rpmsg_probe(struct virtio_device *vdev)

vrp->buf_size = MAX_RPMSG_BUF_SIZE;

- total_buf_space = (vrp->num_rbufs + vrp->num_sbufs) * vrp->buf_size;
-
/* allocate coherent memory for the buffers */
- bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
- total_buf_space, &vrp->bufs_dma,
- GFP_KERNEL);
- if (!bufs_va) {
+ vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
+ vrp->num_rbufs * vrp->buf_size,
+ &vrp->rbufs_dma, GFP_KERNEL);
+ if (!vrp->rbufs) {
err = -ENOMEM;
goto vqs_del;
}

- dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
- bufs_va, &vrp->bufs_dma);
+ dev_dbg(&vdev->dev, "rx buffers: va %p, dma 0x%pad\n",
+ vrp->rbufs, &vrp->rbufs_dma);

- /* first part of the buffers is dedicated for RX */
- vrp->rbufs = bufs_va;
+ vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
+ vrp->num_sbufs * vrp->buf_size,
+ &vrp->sbufs_dma, GFP_KERNEL);
+ if (!vrp->sbufs) {
+ err = -ENOMEM;
+ goto free_rbufs;
+ }

- /* and second part is dedicated for TX */
- vrp->sbufs = bufs_va + vrp->num_rbufs * vrp->buf_size;
+ dev_dbg(&vdev->dev, "tx buffers: va %p, dma 0x%pad\n",
+ vrp->sbufs, &vrp->sbufs_dma);

/* set up the receive buffers */
for (i = 0; i < vrp->num_rbufs; i++) {
@@ -954,7 +957,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
if (!vrp->ns_ept) {
dev_err(&vdev->dev, "failed to create the ns ept\n");
err = -ENOMEM;
- goto free_coherent;
+ goto free_sbufs;
}
}

@@ -979,9 +982,14 @@ static int rpmsg_probe(struct virtio_device *vdev)

return 0;

-free_coherent:
- dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
- bufs_va, vrp->bufs_dma);
+free_sbufs:
+ dma_free_coherent(vdev->dev.parent->parent,
+ vrp->num_sbufs * vrp->buf_size,
+ vrp->sbufs, vrp->sbufs_dma);
+free_rbufs:
+ dma_free_coherent(vdev->dev.parent->parent,
+ vrp->num_rbufs * vrp->buf_size,
+ vrp->rbufs, vrp->rbufs_dma);
vqs_del:
vdev->config->del_vqs(vrp->vdev);
free_vrp:
@@ -999,8 +1007,6 @@ static int rpmsg_remove_device(struct device *dev, void *data)
static void rpmsg_remove(struct virtio_device *vdev)
{
struct virtproc_info *vrp = vdev->priv;
- unsigned int num_bufs = vrp->num_rbufs + vrp->num_sbufs;
- size_t total_buf_space = num_bufs * vrp->buf_size;
int ret;

vdev->config->reset(vdev);
@@ -1016,8 +1022,12 @@ static void rpmsg_remove(struct virtio_device *vdev)

vdev->config->del_vqs(vrp->vdev);

- dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
- vrp->rbufs, vrp->bufs_dma);
+ dma_free_coherent(vdev->dev.parent->parent,
+ vrp->num_sbufs * vrp->buf_size,
+ vrp->sbufs, vrp->sbufs_dma);
+ dma_free_coherent(vdev->dev.parent->parent,
+ vrp->num_rbufs * vrp->buf_size,
+ vrp->rbufs, vrp->rbufs_dma);

kfree(vrp);
}
--
2.7.4


2019-01-31 15:42:29

by xiang xiao

[permalink] [raw]
Subject: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

512 bytes isn't always suitable for all case, let firmware
maker decide the best value from resource table.
enable by VIRTIO_RPMSG_F_BUFSZ feature bit.

Signed-off-by: Xiang Xiao <[email protected]>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
2 files changed, 56 insertions(+), 18 deletions(-)
create mode 100644 include/uapi/linux/virtio_rpmsg.h

diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 59c4554..049dd97 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -16,6 +16,7 @@
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/virtio_rpmsg.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
@@ -38,7 +39,8 @@
* @sbufs: kernel address of tx buffers
* @num_rbufs: total number of buffers for rx
* @num_sbufs: total number of buffers for tx
- * @buf_size: size of one rx or tx buffer
+ * @rbuf_size: size of one rx buffer
+ * @sbuf_size: size of one tx buffer
* @last_sbuf: index of last tx buffer used
* @rbufs_dma: dma base addr of rx buffers
* @sbufs_dma: dma base addr of tx buffers
@@ -61,7 +63,8 @@ struct virtproc_info {
void *rbufs, *sbufs;
unsigned int num_rbufs;
unsigned int num_sbufs;
- unsigned int buf_size;
+ unsigned int rbuf_size;
+ unsigned int sbuf_size;
int last_sbuf;
dma_addr_t rbufs_dma;
dma_addr_t sbufs_dma;
@@ -73,9 +76,6 @@ struct virtproc_info {
struct rpmsg_endpoint *ns_ept;
};

-/* The feature bitmap for virtio rpmsg */
-#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
-
/**
* struct rpmsg_hdr - common header for all rpmsg messages
* @src: source address
@@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)

/* either pick the next unused tx buffer */
if (vrp->last_sbuf < vrp->num_sbufs)
- ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
+ ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
/* or recycle a used one */
else
ret = virtqueue_get_buf(vrp->svq, &len);
@@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
* messaging), or to improve the buffer allocator, to support
* variable-length buffer sizes.
*/
- if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
+ if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
dev_err(dev, "message is too big (%d)\n", len);
return -EMSGSIZE;
}
@@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
* We currently use fixed-sized buffers, so trivially sanitize
* the reported payload length.
*/
- if (len > vrp->buf_size ||
+ if (len > vrp->rbuf_size ||
msg->len > (len - sizeof(struct rpmsg_hdr))) {
dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
return -EINVAL;
@@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
dev_warn(dev, "msg received with no recipient\n");

/* publish the real size of the buffer */
- rpmsg_sg_init(&sg, msg, vrp->buf_size);
+ rpmsg_sg_init(&sg, msg, vrp->rbuf_size);

/* add the buffer back to the remote processor's virtqueue */
err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
@@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
else
vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;

- vrp->buf_size = MAX_RPMSG_BUF_SIZE;
+ /* try to get buffer size from config space */
+ if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
+ /* note: virtio_rpmsg_config is defined from remote view */
+ virtio_cread(vdev, struct virtio_rpmsg_config,
+ txbuf_size, &vrp->rbuf_size);
+ virtio_cread(vdev, struct virtio_rpmsg_config,
+ rxbuf_size, &vrp->sbuf_size);
+ }
+
+ /* use the default if resource table doesn't provide one */
+ if (!vrp->rbuf_size)
+ vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
+ if (!vrp->sbuf_size)
+ vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;

/* allocate coherent memory for the buffers */
vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
- vrp->num_rbufs * vrp->buf_size,
+ vrp->num_rbufs * vrp->rbuf_size,
&vrp->rbufs_dma, GFP_KERNEL);
if (!vrp->rbufs) {
err = -ENOMEM;
@@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
vrp->rbufs, &vrp->rbufs_dma);

vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
- vrp->num_sbufs * vrp->buf_size,
+ vrp->num_sbufs * vrp->sbuf_size,
&vrp->sbufs_dma, GFP_KERNEL);
if (!vrp->sbufs) {
err = -ENOMEM;
@@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
/* set up the receive buffers */
for (i = 0; i < vrp->num_rbufs; i++) {
struct scatterlist sg;
- void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
+ void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;

- rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
+ rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);

err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
GFP_KERNEL);
@@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)

free_sbufs:
dma_free_coherent(vdev->dev.parent->parent,
- vrp->num_sbufs * vrp->buf_size,
+ vrp->num_sbufs * vrp->sbuf_size,
vrp->sbufs, vrp->sbufs_dma);
free_rbufs:
dma_free_coherent(vdev->dev.parent->parent,
- vrp->num_rbufs * vrp->buf_size,
+ vrp->num_rbufs * vrp->rbuf_size,
vrp->rbufs, vrp->rbufs_dma);
vqs_del:
vdev->config->del_vqs(vrp->vdev);
@@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
vdev->config->del_vqs(vrp->vdev);

dma_free_coherent(vdev->dev.parent->parent,
- vrp->num_sbufs * vrp->buf_size,
+ vrp->num_sbufs * vrp->sbuf_size,
vrp->sbufs, vrp->sbufs_dma);
dma_free_coherent(vdev->dev.parent->parent,
- vrp->num_rbufs * vrp->buf_size,
+ vrp->num_rbufs * vrp->rbuf_size,
vrp->rbufs, vrp->rbufs_dma);

kfree(vrp);
@@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {

static unsigned int features[] = {
VIRTIO_RPMSG_F_NS,
+ VIRTIO_RPMSG_F_BUFSZ,
};

static struct virtio_driver virtio_ipc_driver = {
diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
new file mode 100644
index 0000000..24fa0dd
--- /dev/null
+++ b/include/uapi/linux/virtio_rpmsg.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (C) Pinecone Inc. 2019
+ * Copyright (C) Xiang Xiao <[email protected]>
+ */
+
+#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
+#define _UAPI_LINUX_VIRTIO_RPMSG_H
+
+#include <linux/types.h>
+
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
+#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
+
+struct virtio_rpmsg_config {
+ /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
+ __u32 txbuf_size;
+ __u32 rxbuf_size;
+ __u32 reserved[14]; /* Reserve for the future use */
+ /* Put the customize config here */
+} __attribute__((packed));
+
+#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
--
2.7.4


2019-01-31 15:44:52

by xiang xiao

[permalink] [raw]
Subject: [PATCH 1/3] rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv

it's useful if the communication throughput is different from each side

Signed-off-by: Xiang Xiao <[email protected]>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 47 ++++++++++++++++++++--------------------
1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 664f957..fb0d2eb 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -36,8 +36,9 @@
* @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
- * @buf_size: size of one rx or tx buffer
+ * @num_rbufs: total number of buffers for rx
+ * @num_sbufs: total number of buffers for tx
+ * @buf_size: size of one rx or tx buffer
* @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.
@@ -57,7 +58,8 @@ struct virtproc_info {
struct virtio_device *vdev;
struct virtqueue *rvq, *svq;
void *rbufs, *sbufs;
- unsigned int num_bufs;
+ unsigned int num_rbufs;
+ unsigned int num_sbufs;
unsigned int buf_size;
int last_sbuf;
dma_addr_t bufs_dma;
@@ -136,7 +138,7 @@ struct virtio_rpmsg_channel {
/*
* 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).
+ * by the vring, up to a maximum of 256 in each direction.
*
* Each buffer will have 16 bytes for the msg header and 496 bytes for
* the payload.
@@ -151,7 +153,7 @@ struct virtio_rpmsg_channel {
* can change this without changing anything in the firmware of the remote
* processor.
*/
-#define MAX_RPMSG_NUM_BUFS (512)
+#define MAX_RPMSG_NUM_BUFS (256)
#define MAX_RPMSG_BUF_SIZE (512)

/*
@@ -446,11 +448,8 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
/* support multiple concurrent senders */
mutex_lock(&vrp->tx_lock);

- /*
- * either pick the next unused tx buffer
- * (half of our buffers are used for sending messages)
- */
- if (vrp->last_sbuf < vrp->num_bufs / 2)
+ /* either pick the next unused tx buffer */
+ if (vrp->last_sbuf < vrp->num_sbufs)
ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
/* or recycle a used one */
else
@@ -897,19 +896,20 @@ 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;
+ if (virtqueue_get_vring_size(vrp->rvq) < MAX_RPMSG_NUM_BUFS)
+ vrp->num_rbufs = virtqueue_get_vring_size(vrp->rvq);
+ else
+ vrp->num_rbufs = MAX_RPMSG_NUM_BUFS;
+
+ if (virtqueue_get_vring_size(vrp->svq) < MAX_RPMSG_NUM_BUFS)
+ vrp->num_sbufs = virtqueue_get_vring_size(vrp->svq);
else
- vrp->num_bufs = MAX_RPMSG_NUM_BUFS;
+ vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;

vrp->buf_size = MAX_RPMSG_BUF_SIZE;

- total_buf_space = vrp->num_bufs * vrp->buf_size;
+ total_buf_space = (vrp->num_rbufs + vrp->num_sbufs) * vrp->buf_size;

/* allocate coherent memory for the buffers */
bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
@@ -923,14 +923,14 @@ static int rpmsg_probe(struct virtio_device *vdev)
dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
bufs_va, &vrp->bufs_dma);

- /* half of the buffers is dedicated for RX */
+ /* first part of the buffers is dedicated for RX */
vrp->rbufs = bufs_va;

- /* and half is dedicated for TX */
- vrp->sbufs = bufs_va + total_buf_space / 2;
+ /* and second part is dedicated for TX */
+ vrp->sbufs = bufs_va + vrp->num_rbufs * vrp->buf_size;

/* set up the receive buffers */
- for (i = 0; i < vrp->num_bufs / 2; i++) {
+ for (i = 0; i < vrp->num_rbufs; i++) {
struct scatterlist sg;
void *cpu_addr = vrp->rbufs + i * vrp->buf_size;

@@ -999,7 +999,8 @@ 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 * vrp->buf_size;
+ unsigned int num_bufs = vrp->num_rbufs + vrp->num_sbufs;
+ size_t total_buf_space = num_bufs * vrp->buf_size;
int ret;

vdev->config->reset(vdev);
--
2.7.4


2019-05-09 11:48:39

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 1/3] rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv

Hello Xiang,

I tested your patch on stm32 platform, no issue.
No remark on you code.

Acked-by:Arnaud POULIQUEN <[email protected]>

Thanks,
Arnaud

On 1/31/19 4:41 PM, Xiang Xiao wrote:
> it's useful if the communication throughput is different from each side
>
> Signed-off-by: Xiang Xiao <[email protected]>
> ---
> drivers/rpmsg/virtio_rpmsg_bus.c | 47 ++++++++++++++++++++--------------------
> 1 file changed, 24 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> index 664f957..fb0d2eb 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -36,8 +36,9 @@
> * @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
> - * @buf_size: size of one rx or tx buffer
> + * @num_rbufs: total number of buffers for rx
> + * @num_sbufs: total number of buffers for tx
> + * @buf_size: size of one rx or tx buffer
> * @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.
> @@ -57,7 +58,8 @@ struct virtproc_info {
> struct virtio_device *vdev;
> struct virtqueue *rvq, *svq;
> void *rbufs, *sbufs;
> - unsigned int num_bufs;
> + unsigned int num_rbufs;
> + unsigned int num_sbufs;
> unsigned int buf_size;
> int last_sbuf;
> dma_addr_t bufs_dma;
> @@ -136,7 +138,7 @@ struct virtio_rpmsg_channel {
> /*
> * 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).
> + * by the vring, up to a maximum of 256 in each direction.
> *
> * Each buffer will have 16 bytes for the msg header and 496 bytes for
> * the payload.
> @@ -151,7 +153,7 @@ struct virtio_rpmsg_channel {
> * can change this without changing anything in the firmware of the remote
> * processor.
> */
> -#define MAX_RPMSG_NUM_BUFS (512)
> +#define MAX_RPMSG_NUM_BUFS (256)
> #define MAX_RPMSG_BUF_SIZE (512)
>
> /*
> @@ -446,11 +448,8 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
> /* support multiple concurrent senders */
> mutex_lock(&vrp->tx_lock);
>
> - /*
> - * either pick the next unused tx buffer
> - * (half of our buffers are used for sending messages)
> - */
> - if (vrp->last_sbuf < vrp->num_bufs / 2)
> + /* either pick the next unused tx buffer */
> + if (vrp->last_sbuf < vrp->num_sbufs)
> ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> /* or recycle a used one */
> else
> @@ -897,19 +896,20 @@ 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;
> + if (virtqueue_get_vring_size(vrp->rvq) < MAX_RPMSG_NUM_BUFS)
> + vrp->num_rbufs = virtqueue_get_vring_size(vrp->rvq);
> + else
> + vrp->num_rbufs = MAX_RPMSG_NUM_BUFS;
> +
> + if (virtqueue_get_vring_size(vrp->svq) < MAX_RPMSG_NUM_BUFS)
> + vrp->num_sbufs = virtqueue_get_vring_size(vrp->svq);
> else
> - vrp->num_bufs = MAX_RPMSG_NUM_BUFS;
> + vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
>
> vrp->buf_size = MAX_RPMSG_BUF_SIZE;
>
> - total_buf_space = vrp->num_bufs * vrp->buf_size;
> + total_buf_space = (vrp->num_rbufs + vrp->num_sbufs) * vrp->buf_size;
>
> /* allocate coherent memory for the buffers */
> bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
> @@ -923,14 +923,14 @@ static int rpmsg_probe(struct virtio_device *vdev)
> dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
> bufs_va, &vrp->bufs_dma);
>
> - /* half of the buffers is dedicated for RX */
> + /* first part of the buffers is dedicated for RX */
> vrp->rbufs = bufs_va;
>
> - /* and half is dedicated for TX */
> - vrp->sbufs = bufs_va + total_buf_space / 2;
> + /* and second part is dedicated for TX */
> + vrp->sbufs = bufs_va + vrp->num_rbufs * vrp->buf_size;
>
> /* set up the receive buffers */
> - for (i = 0; i < vrp->num_bufs / 2; i++) {
> + for (i = 0; i < vrp->num_rbufs; i++) {
> struct scatterlist sg;
> void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
>
> @@ -999,7 +999,8 @@ 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 * vrp->buf_size;
> + unsigned int num_bufs = vrp->num_rbufs + vrp->num_sbufs;
> + size_t total_buf_space = num_bufs * vrp->buf_size;
> int ret;
>
> vdev->config->reset(vdev);
>

2019-05-09 12:03:51

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 2/3] rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately

Hello Xiang,

This patch has the opposite effect on my platform as DMA allocation is
aligned on 4k page.
For instance i declared:
- in RX 6 buffers (of 512 bytes)
- in TX 4 buffers ( of 512 bytes)

The result is (kernel trace)
[ 41.915896] virtio_rpmsg_bus virtio0: rx buffers: va ebb5f5ca, dma
0x0x10042000
[ 41.915922] virtio_rpmsg_bus virtio0: tx buffers: va a7865153, dma
0x0x10043000

The TX buffer memory is allocated on next 4k page...

Anyway separate the RX and TX allocation makes sense. This could also
allow to allocate buffers in 2 different memories.
For time being, issue is that only one memory area can be attached to
the virtio device for DMA allocation... and PA/DA translations are missing.
This means that we probably need (in a first step) a new remoteproc API
for memory allocation.
These memories should be declared and mmaped in rproc platform drivers
(memory region) or in resource table (carveout).
This is partially done in the API for the platform driver
(rproc_mem_entry_init) but not available for rproc clients.

Regards
Arnaud


On 1/31/19 4:41 PM, Xiang Xiao wrote:
> many dma allocator align the returned address with buffer size,
> so two small allocation could reduce the alignment requirement
> and save the the memory space wasted by the potential alignment.
>
> Signed-off-by: Xiang Xiao <[email protected]>
> ---
> drivers/rpmsg/virtio_rpmsg_bus.c | 58 +++++++++++++++++++++++-----------------
> 1 file changed, 34 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> index fb0d2eb..59c4554 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -40,7 +40,8 @@
> * @num_sbufs: total number of buffers for tx
> * @buf_size: size of one rx or tx buffer
> * @last_sbuf: index of last tx buffer used
> - * @bufs_dma: dma base addr of the buffers
> + * @rbufs_dma: dma base addr of rx buffers
> + * @sbufs_dma: dma base addr of tx buffers
> * @tx_lock: protects svq, sbufs and sleepers, to allow concurrent senders.
> * sending a message might require waking up a dozing remote
> * processor, which involves sleeping, hence the mutex.
> @@ -62,7 +63,8 @@ struct virtproc_info {
> unsigned int num_sbufs;
> unsigned int buf_size;
> int last_sbuf;
> - dma_addr_t bufs_dma;
> + dma_addr_t rbufs_dma;
> + dma_addr_t sbufs_dma;
> struct mutex tx_lock;
> struct idr endpoints;
> struct mutex endpoints_lock;
> @@ -872,9 +874,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> static const char * const names[] = { "input", "output" };
> struct virtqueue *vqs[2];
> struct virtproc_info *vrp;
> - void *bufs_va;
> int err = 0, i;
> - size_t total_buf_space;
> bool notify;
>
> vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
> @@ -909,25 +909,28 @@ static int rpmsg_probe(struct virtio_device *vdev)
>
> vrp->buf_size = MAX_RPMSG_BUF_SIZE;
>
> - total_buf_space = (vrp->num_rbufs + vrp->num_sbufs) * vrp->buf_size;
> -
> /* allocate coherent memory for the buffers */
> - bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
> - total_buf_space, &vrp->bufs_dma,
> - GFP_KERNEL);
> - if (!bufs_va) {
> + vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> + vrp->num_rbufs * vrp->buf_size,
> + &vrp->rbufs_dma, GFP_KERNEL);
> + if (!vrp->rbufs) {
> err = -ENOMEM;
> goto vqs_del;
> }
>
> - dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
> - bufs_va, &vrp->bufs_dma);
> + dev_dbg(&vdev->dev, "rx buffers: va %p, dma 0x%pad\n",
> + vrp->rbufs, &vrp->rbufs_dma);
>
> - /* first part of the buffers is dedicated for RX */
> - vrp->rbufs = bufs_va;
> + vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> + vrp->num_sbufs * vrp->buf_size,
> + &vrp->sbufs_dma, GFP_KERNEL);
> + if (!vrp->sbufs) {
> + err = -ENOMEM;
> + goto free_rbufs;
> + }
>
> - /* and second part is dedicated for TX */
> - vrp->sbufs = bufs_va + vrp->num_rbufs * vrp->buf_size;
> + dev_dbg(&vdev->dev, "tx buffers: va %p, dma 0x%pad\n",
> + vrp->sbufs, &vrp->sbufs_dma);
>
> /* set up the receive buffers */
> for (i = 0; i < vrp->num_rbufs; i++) {
> @@ -954,7 +957,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> if (!vrp->ns_ept) {
> dev_err(&vdev->dev, "failed to create the ns ept\n");
> err = -ENOMEM;
> - goto free_coherent;
> + goto free_sbufs;
> }
> }
>
> @@ -979,9 +982,14 @@ static int rpmsg_probe(struct virtio_device *vdev)
>
> return 0;
>
> -free_coherent:
> - dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
> - bufs_va, vrp->bufs_dma);
> +free_sbufs:
> + dma_free_coherent(vdev->dev.parent->parent,
> + vrp->num_sbufs * vrp->buf_size,
> + vrp->sbufs, vrp->sbufs_dma);
> +free_rbufs:
> + dma_free_coherent(vdev->dev.parent->parent,
> + vrp->num_rbufs * vrp->buf_size,
> + vrp->rbufs, vrp->rbufs_dma);
> vqs_del:
> vdev->config->del_vqs(vrp->vdev);
> free_vrp:
> @@ -999,8 +1007,6 @@ static int rpmsg_remove_device(struct device *dev, void *data)
> static void rpmsg_remove(struct virtio_device *vdev)
> {
> struct virtproc_info *vrp = vdev->priv;
> - unsigned int num_bufs = vrp->num_rbufs + vrp->num_sbufs;
> - size_t total_buf_space = num_bufs * vrp->buf_size;
> int ret;
>
> vdev->config->reset(vdev);
> @@ -1016,8 +1022,12 @@ static void rpmsg_remove(struct virtio_device *vdev)
>
> vdev->config->del_vqs(vrp->vdev);
>
> - dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
> - vrp->rbufs, vrp->bufs_dma);
> + dma_free_coherent(vdev->dev.parent->parent,
> + vrp->num_sbufs * vrp->buf_size,
> + vrp->sbufs, vrp->sbufs_dma);
> + dma_free_coherent(vdev->dev.parent->parent,
> + vrp->num_rbufs * vrp->buf_size,
> + vrp->rbufs, vrp->rbufs_dma);
>
> kfree(vrp);
> }
>

2019-05-09 12:37:20

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

Hello Xiang,

Similar mechanism has been proposed by Loic 2 years ago (link to the
series here https://lkml.org/lkml/2017/3/28/349).

Did you see them? Regarding history, patches seem just on hold...

Main differences (except interesting RX/TX size split) seems that you
- don't use the virtio_config_ops->get
- define a new feature VIRTIO_RPMSG_F_NS.

Regards
Arnaud


On 1/31/19 4:41 PM, Xiang Xiao wrote:
> 512 bytes isn't always suitable for all case, let firmware
> maker decide the best value from resource table.
> enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
>
> Signed-off-by: Xiang Xiao <[email protected]>
> ---
> drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
> include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
> 2 files changed, 56 insertions(+), 18 deletions(-)
> create mode 100644 include/uapi/linux/virtio_rpmsg.h
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> index 59c4554..049dd97 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -16,6 +16,7 @@
> #include <linux/virtio.h>
> #include <linux/virtio_ids.h>
> #include <linux/virtio_config.h>
> +#include <linux/virtio_rpmsg.h>
> #include <linux/scatterlist.h>
> #include <linux/dma-mapping.h>
> #include <linux/slab.h>
> @@ -38,7 +39,8 @@
> * @sbufs: kernel address of tx buffers
> * @num_rbufs: total number of buffers for rx
> * @num_sbufs: total number of buffers for tx
> - * @buf_size: size of one rx or tx buffer
> + * @rbuf_size: size of one rx buffer
> + * @sbuf_size: size of one tx buffer
> * @last_sbuf: index of last tx buffer used
> * @rbufs_dma: dma base addr of rx buffers
> * @sbufs_dma: dma base addr of tx buffers
> @@ -61,7 +63,8 @@ struct virtproc_info {
> void *rbufs, *sbufs;
> unsigned int num_rbufs;
> unsigned int num_sbufs;
> - unsigned int buf_size;
> + unsigned int rbuf_size;
> + unsigned int sbuf_size;
> int last_sbuf;
> dma_addr_t rbufs_dma;
> dma_addr_t sbufs_dma;
> @@ -73,9 +76,6 @@ struct virtproc_info {
> struct rpmsg_endpoint *ns_ept;
> };
>
> -/* The feature bitmap for virtio rpmsg */
> -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> -
> /**
> * struct rpmsg_hdr - common header for all rpmsg messages
> * @src: source address
> @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
>
> /* either pick the next unused tx buffer */
> if (vrp->last_sbuf < vrp->num_sbufs)
> - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
> /* or recycle a used one */
> else
> ret = virtqueue_get_buf(vrp->svq, &len);
> @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
> * messaging), or to improve the buffer allocator, to support
> * variable-length buffer sizes.
> */
> - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
> + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
> dev_err(dev, "message is too big (%d)\n", len);
> return -EMSGSIZE;
> }
> @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> * We currently use fixed-sized buffers, so trivially sanitize
> * the reported payload length.
> */
> - if (len > vrp->buf_size ||
> + if (len > vrp->rbuf_size ||
> msg->len > (len - sizeof(struct rpmsg_hdr))) {
> dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
> return -EINVAL;
> @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> dev_warn(dev, "msg received with no recipient\n");
>
> /* publish the real size of the buffer */
> - rpmsg_sg_init(&sg, msg, vrp->buf_size);
> + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
>
> /* add the buffer back to the remote processor's virtqueue */
> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
> @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
> else
> vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
>
> - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
> + /* try to get buffer size from config space */
> + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
> + /* note: virtio_rpmsg_config is defined from remote view */
> + virtio_cread(vdev, struct virtio_rpmsg_config,
> + txbuf_size, &vrp->rbuf_size);
> + virtio_cread(vdev, struct virtio_rpmsg_config,
> + rxbuf_size, &vrp->sbuf_size);
> + }
> +
> + /* use the default if resource table doesn't provide one */
> + if (!vrp->rbuf_size)
> + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
> + if (!vrp->sbuf_size)
> + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
>
> /* allocate coherent memory for the buffers */
> vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> - vrp->num_rbufs * vrp->buf_size,
> + vrp->num_rbufs * vrp->rbuf_size,
> &vrp->rbufs_dma, GFP_KERNEL);
> if (!vrp->rbufs) {
> err = -ENOMEM;
> @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> vrp->rbufs, &vrp->rbufs_dma);
>
> vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> - vrp->num_sbufs * vrp->buf_size,
> + vrp->num_sbufs * vrp->sbuf_size,
> &vrp->sbufs_dma, GFP_KERNEL);
> if (!vrp->sbufs) {
> err = -ENOMEM;
> @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
> /* set up the receive buffers */
> for (i = 0; i < vrp->num_rbufs; i++) {
> struct scatterlist sg;
> - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
> + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
>
> - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
> + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
>
> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
> GFP_KERNEL);
> @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
>
> free_sbufs:
> dma_free_coherent(vdev->dev.parent->parent,
> - vrp->num_sbufs * vrp->buf_size,
> + vrp->num_sbufs * vrp->sbuf_size,
> vrp->sbufs, vrp->sbufs_dma);
> free_rbufs:
> dma_free_coherent(vdev->dev.parent->parent,
> - vrp->num_rbufs * vrp->buf_size,
> + vrp->num_rbufs * vrp->rbuf_size,
> vrp->rbufs, vrp->rbufs_dma);
> vqs_del:
> vdev->config->del_vqs(vrp->vdev);
> @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
> vdev->config->del_vqs(vrp->vdev);
>
> dma_free_coherent(vdev->dev.parent->parent,
> - vrp->num_sbufs * vrp->buf_size,
> + vrp->num_sbufs * vrp->sbuf_size,
> vrp->sbufs, vrp->sbufs_dma);
> dma_free_coherent(vdev->dev.parent->parent,
> - vrp->num_rbufs * vrp->buf_size,
> + vrp->num_rbufs * vrp->rbuf_size,
> vrp->rbufs, vrp->rbufs_dma);
>
> kfree(vrp);
> @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
>
> static unsigned int features[] = {
> VIRTIO_RPMSG_F_NS,
> + VIRTIO_RPMSG_F_BUFSZ,
> };
>
> static struct virtio_driver virtio_ipc_driver = {
> diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
> new file mode 100644
> index 0000000..24fa0dd
> --- /dev/null
> +++ b/include/uapi/linux/virtio_rpmsg.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Copyright (C) Pinecone Inc. 2019
> + * Copyright (C) Xiang Xiao <[email protected]>
> + */
> +
> +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
> +#define _UAPI_LINUX_VIRTIO_RPMSG_H
> +
> +#include <linux/types.h>
> +
> +/* The feature bitmap for virtio rpmsg */
> +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
> +
> +struct virtio_rpmsg_config {
> + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
> + __u32 txbuf_size;
> + __u32 rxbuf_size;
> + __u32 reserved[14]; /* Reserve for the future use */
> + /* Put the customize config here */
> +} __attribute__((packed));
> +
> +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
>

2019-05-09 12:39:25

by xiang xiao

[permalink] [raw]
Subject: Re: [PATCH 2/3] rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately

On Thu, May 9, 2019 at 8:02 PM Arnaud Pouliquen <[email protected]> wrote:
>
> Hello Xiang,
>
> This patch has the opposite effect on my platform as DMA allocation is
> aligned on 4k page.
> For instance i declared:
> - in RX 6 buffers (of 512 bytes)
> - in TX 4 buffers ( of 512 bytes)
>

Yes, dma_init_coherent_memory always allocate memory by 4KB unit, but
this limitation is too waste memory for remoteproc/rpmsg. The attached
patch fix this problem by adding a new device tree option to customize
the unit size.

> The result is (kernel trace)
> [ 41.915896] virtio_rpmsg_bus virtio0: rx buffers: va ebb5f5ca, dma
> 0x0x10042000
> [ 41.915922] virtio_rpmsg_bus virtio0: tx buffers: va a7865153, dma
> 0x0x10043000
>
> The TX buffer memory is allocated on next 4k page...
>
> Anyway separate the RX and TX allocation makes sense. This could also
> allow to allocate buffers in 2 different memories.
> For time being, issue is that only one memory area can be attached to
> the virtio device for DMA allocation... and PA/DA translations are missing.
> This means that we probably need (in a first step) a new remoteproc API
> for memory allocation.
> These memories should be declared and mmaped in rproc platform drivers
> (memory region) or in resource table (carveout).
> This is partially done in the API for the platform driver
> (rproc_mem_entry_init) but not available for rproc clients.
>
> Regards
> Arnaud
>
>
> On 1/31/19 4:41 PM, Xiang Xiao wrote:
> > many dma allocator align the returned address with buffer size,
> > so two small allocation could reduce the alignment requirement
> > and save the the memory space wasted by the potential alignment.
> >
> > Signed-off-by: Xiang Xiao <[email protected]>
> > ---
> > drivers/rpmsg/virtio_rpmsg_bus.c | 58 +++++++++++++++++++++++-----------------
> > 1 file changed, 34 insertions(+), 24 deletions(-)
> >
> > diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> > index fb0d2eb..59c4554 100644
> > --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> > +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> > @@ -40,7 +40,8 @@
> > * @num_sbufs: total number of buffers for tx
> > * @buf_size: size of one rx or tx buffer
> > * @last_sbuf: index of last tx buffer used
> > - * @bufs_dma: dma base addr of the buffers
> > + * @rbufs_dma: dma base addr of rx buffers
> > + * @sbufs_dma: dma base addr of tx buffers
> > * @tx_lock: protects svq, sbufs and sleepers, to allow concurrent senders.
> > * sending a message might require waking up a dozing remote
> > * processor, which involves sleeping, hence the mutex.
> > @@ -62,7 +63,8 @@ struct virtproc_info {
> > unsigned int num_sbufs;
> > unsigned int buf_size;
> > int last_sbuf;
> > - dma_addr_t bufs_dma;
> > + dma_addr_t rbufs_dma;
> > + dma_addr_t sbufs_dma;
> > struct mutex tx_lock;
> > struct idr endpoints;
> > struct mutex endpoints_lock;
> > @@ -872,9 +874,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> > static const char * const names[] = { "input", "output" };
> > struct virtqueue *vqs[2];
> > struct virtproc_info *vrp;
> > - void *bufs_va;
> > int err = 0, i;
> > - size_t total_buf_space;
> > bool notify;
> >
> > vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
> > @@ -909,25 +909,28 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >
> > vrp->buf_size = MAX_RPMSG_BUF_SIZE;
> >
> > - total_buf_space = (vrp->num_rbufs + vrp->num_sbufs) * vrp->buf_size;
> > -
> > /* allocate coherent memory for the buffers */
> > - bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
> > - total_buf_space, &vrp->bufs_dma,
> > - GFP_KERNEL);
> > - if (!bufs_va) {
> > + vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> > + vrp->num_rbufs * vrp->buf_size,
> > + &vrp->rbufs_dma, GFP_KERNEL);
> > + if (!vrp->rbufs) {
> > err = -ENOMEM;
> > goto vqs_del;
> > }
> >
> > - dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n",
> > - bufs_va, &vrp->bufs_dma);
> > + dev_dbg(&vdev->dev, "rx buffers: va %p, dma 0x%pad\n",
> > + vrp->rbufs, &vrp->rbufs_dma);
> >
> > - /* first part of the buffers is dedicated for RX */
> > - vrp->rbufs = bufs_va;
> > + vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> > + vrp->num_sbufs * vrp->buf_size,
> > + &vrp->sbufs_dma, GFP_KERNEL);
> > + if (!vrp->sbufs) {
> > + err = -ENOMEM;
> > + goto free_rbufs;
> > + }
> >
> > - /* and second part is dedicated for TX */
> > - vrp->sbufs = bufs_va + vrp->num_rbufs * vrp->buf_size;
> > + dev_dbg(&vdev->dev, "tx buffers: va %p, dma 0x%pad\n",
> > + vrp->sbufs, &vrp->sbufs_dma);
> >
> > /* set up the receive buffers */
> > for (i = 0; i < vrp->num_rbufs; i++) {
> > @@ -954,7 +957,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> > if (!vrp->ns_ept) {
> > dev_err(&vdev->dev, "failed to create the ns ept\n");
> > err = -ENOMEM;
> > - goto free_coherent;
> > + goto free_sbufs;
> > }
> > }
> >
> > @@ -979,9 +982,14 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >
> > return 0;
> >
> > -free_coherent:
> > - dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
> > - bufs_va, vrp->bufs_dma);
> > +free_sbufs:
> > + dma_free_coherent(vdev->dev.parent->parent,
> > + vrp->num_sbufs * vrp->buf_size,
> > + vrp->sbufs, vrp->sbufs_dma);
> > +free_rbufs:
> > + dma_free_coherent(vdev->dev.parent->parent,
> > + vrp->num_rbufs * vrp->buf_size,
> > + vrp->rbufs, vrp->rbufs_dma);
> > vqs_del:
> > vdev->config->del_vqs(vrp->vdev);
> > free_vrp:
> > @@ -999,8 +1007,6 @@ static int rpmsg_remove_device(struct device *dev, void *data)
> > static void rpmsg_remove(struct virtio_device *vdev)
> > {
> > struct virtproc_info *vrp = vdev->priv;
> > - unsigned int num_bufs = vrp->num_rbufs + vrp->num_sbufs;
> > - size_t total_buf_space = num_bufs * vrp->buf_size;
> > int ret;
> >
> > vdev->config->reset(vdev);
> > @@ -1016,8 +1022,12 @@ static void rpmsg_remove(struct virtio_device *vdev)
> >
> > vdev->config->del_vqs(vrp->vdev);
> >
> > - dma_free_coherent(vdev->dev.parent->parent, total_buf_space,
> > - vrp->rbufs, vrp->bufs_dma);
> > + dma_free_coherent(vdev->dev.parent->parent,
> > + vrp->num_sbufs * vrp->buf_size,
> > + vrp->sbufs, vrp->sbufs_dma);
> > + dma_free_coherent(vdev->dev.parent->parent,
> > + vrp->num_rbufs * vrp->buf_size,
> > + vrp->rbufs, vrp->rbufs_dma);
> >
> > kfree(vrp);
> > }
> >


Attachments:
0001-dma-coherent-support-the-alignment-smaller-than-PAGE.patch (9.55 kB)

2019-05-09 13:02:36

by xiang xiao

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

On Thu, May 9, 2019 at 8:36 PM Arnaud Pouliquen <[email protected]> wrote:
>
> Hello Xiang,
>
> Similar mechanism has been proposed by Loic 2 years ago (link to the
> series here https://lkml.org/lkml/2017/3/28/349).
>
> Did you see them? Regarding history, patches seem just on hold...
>

Just saw this patchset, so it's common problem hit by many vendor,
rpmsg framework need to address it.:)

> Main differences (except interesting RX/TX size split) seems that you
> - don't use the virtio_config_ops->get

virtio_cread call virtio_config_ops->get internally, the ideal is same
for both patch, just the implementation detail is different.

> - define a new feature VIRTIO_RPMSG_F_NS.

I add this flag to keep the compatibility with old remote peer, and
also follow the common virito driver practice.

>
> Regards
> Arnaud
>
>
> On 1/31/19 4:41 PM, Xiang Xiao wrote:
> > 512 bytes isn't always suitable for all case, let firmware
> > maker decide the best value from resource table.
> > enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
> >
> > Signed-off-by: Xiang Xiao <[email protected]>
> > ---
> > drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
> > include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
> > 2 files changed, 56 insertions(+), 18 deletions(-)
> > create mode 100644 include/uapi/linux/virtio_rpmsg.h
> >
> > diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> > index 59c4554..049dd97 100644
> > --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> > +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> > @@ -16,6 +16,7 @@
> > #include <linux/virtio.h>
> > #include <linux/virtio_ids.h>
> > #include <linux/virtio_config.h>
> > +#include <linux/virtio_rpmsg.h>
> > #include <linux/scatterlist.h>
> > #include <linux/dma-mapping.h>
> > #include <linux/slab.h>
> > @@ -38,7 +39,8 @@
> > * @sbufs: kernel address of tx buffers
> > * @num_rbufs: total number of buffers for rx
> > * @num_sbufs: total number of buffers for tx
> > - * @buf_size: size of one rx or tx buffer
> > + * @rbuf_size: size of one rx buffer
> > + * @sbuf_size: size of one tx buffer
> > * @last_sbuf: index of last tx buffer used
> > * @rbufs_dma: dma base addr of rx buffers
> > * @sbufs_dma: dma base addr of tx buffers
> > @@ -61,7 +63,8 @@ struct virtproc_info {
> > void *rbufs, *sbufs;
> > unsigned int num_rbufs;
> > unsigned int num_sbufs;
> > - unsigned int buf_size;
> > + unsigned int rbuf_size;
> > + unsigned int sbuf_size;
> > int last_sbuf;
> > dma_addr_t rbufs_dma;
> > dma_addr_t sbufs_dma;
> > @@ -73,9 +76,6 @@ struct virtproc_info {
> > struct rpmsg_endpoint *ns_ept;
> > };
> >
> > -/* The feature bitmap for virtio rpmsg */
> > -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> > -
> > /**
> > * struct rpmsg_hdr - common header for all rpmsg messages
> > * @src: source address
> > @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
> >
> > /* either pick the next unused tx buffer */
> > if (vrp->last_sbuf < vrp->num_sbufs)
> > - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> > + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
> > /* or recycle a used one */
> > else
> > ret = virtqueue_get_buf(vrp->svq, &len);
> > @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
> > * messaging), or to improve the buffer allocator, to support
> > * variable-length buffer sizes.
> > */
> > - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
> > + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
> > dev_err(dev, "message is too big (%d)\n", len);
> > return -EMSGSIZE;
> > }
> > @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> > * We currently use fixed-sized buffers, so trivially sanitize
> > * the reported payload length.
> > */
> > - if (len > vrp->buf_size ||
> > + if (len > vrp->rbuf_size ||
> > msg->len > (len - sizeof(struct rpmsg_hdr))) {
> > dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
> > return -EINVAL;
> > @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> > dev_warn(dev, "msg received with no recipient\n");
> >
> > /* publish the real size of the buffer */
> > - rpmsg_sg_init(&sg, msg, vrp->buf_size);
> > + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
> >
> > /* add the buffer back to the remote processor's virtqueue */
> > err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
> > @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
> > else
> > vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
> >
> > - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
> > + /* try to get buffer size from config space */
> > + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
> > + /* note: virtio_rpmsg_config is defined from remote view */
> > + virtio_cread(vdev, struct virtio_rpmsg_config,
> > + txbuf_size, &vrp->rbuf_size);
> > + virtio_cread(vdev, struct virtio_rpmsg_config,
> > + rxbuf_size, &vrp->sbuf_size);
> > + }
> > +
> > + /* use the default if resource table doesn't provide one */
> > + if (!vrp->rbuf_size)
> > + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
> > + if (!vrp->sbuf_size)
> > + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
> >
> > /* allocate coherent memory for the buffers */
> > vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> > - vrp->num_rbufs * vrp->buf_size,
> > + vrp->num_rbufs * vrp->rbuf_size,
> > &vrp->rbufs_dma, GFP_KERNEL);
> > if (!vrp->rbufs) {
> > err = -ENOMEM;
> > @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> > vrp->rbufs, &vrp->rbufs_dma);
> >
> > vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> > - vrp->num_sbufs * vrp->buf_size,
> > + vrp->num_sbufs * vrp->sbuf_size,
> > &vrp->sbufs_dma, GFP_KERNEL);
> > if (!vrp->sbufs) {
> > err = -ENOMEM;
> > @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
> > /* set up the receive buffers */
> > for (i = 0; i < vrp->num_rbufs; i++) {
> > struct scatterlist sg;
> > - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
> > + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
> >
> > - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
> > + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
> >
> > err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
> > GFP_KERNEL);
> > @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >
> > free_sbufs:
> > dma_free_coherent(vdev->dev.parent->parent,
> > - vrp->num_sbufs * vrp->buf_size,
> > + vrp->num_sbufs * vrp->sbuf_size,
> > vrp->sbufs, vrp->sbufs_dma);
> > free_rbufs:
> > dma_free_coherent(vdev->dev.parent->parent,
> > - vrp->num_rbufs * vrp->buf_size,
> > + vrp->num_rbufs * vrp->rbuf_size,
> > vrp->rbufs, vrp->rbufs_dma);
> > vqs_del:
> > vdev->config->del_vqs(vrp->vdev);
> > @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
> > vdev->config->del_vqs(vrp->vdev);
> >
> > dma_free_coherent(vdev->dev.parent->parent,
> > - vrp->num_sbufs * vrp->buf_size,
> > + vrp->num_sbufs * vrp->sbuf_size,
> > vrp->sbufs, vrp->sbufs_dma);
> > dma_free_coherent(vdev->dev.parent->parent,
> > - vrp->num_rbufs * vrp->buf_size,
> > + vrp->num_rbufs * vrp->rbuf_size,
> > vrp->rbufs, vrp->rbufs_dma);
> >
> > kfree(vrp);
> > @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
> >
> > static unsigned int features[] = {
> > VIRTIO_RPMSG_F_NS,
> > + VIRTIO_RPMSG_F_BUFSZ,
> > };
> >
> > static struct virtio_driver virtio_ipc_driver = {
> > diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
> > new file mode 100644
> > index 0000000..24fa0dd
> > --- /dev/null
> > +++ b/include/uapi/linux/virtio_rpmsg.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> > +/*
> > + * Copyright (C) Pinecone Inc. 2019
> > + * Copyright (C) Xiang Xiao <[email protected]>
> > + */
> > +
> > +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
> > +#define _UAPI_LINUX_VIRTIO_RPMSG_H
> > +
> > +#include <linux/types.h>
> > +
> > +/* The feature bitmap for virtio rpmsg */
> > +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> > +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
> > +
> > +struct virtio_rpmsg_config {
> > + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
> > + __u32 txbuf_size;
> > + __u32 rxbuf_size;
> > + __u32 reserved[14]; /* Reserve for the future use */
> > + /* Put the customize config here */
> > +} __attribute__((packed));
> > +
> > +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
> >

2019-06-04 14:28:35

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

Hello Xiang,

On 5/9/19 3:00 PM, xiang xiao wrote:
> On Thu, May 9, 2019 at 8:36 PM Arnaud Pouliquen <[email protected]> wrote:
>>
>> Hello Xiang,
>>
>> Similar mechanism has been proposed by Loic 2 years ago (link to the
>> series here https://lkml.org/lkml/2017/3/28/349).
>>
>> Did you see them? Regarding history, patches seem just on hold...
>>
>
> Just saw this patchset, so it's common problem hit by many vendor,
> rpmsg framework need to address it.:)
>
>> Main differences (except interesting RX/TX size split) seems that you
>> - don't use the virtio_config_ops->get
>
> virtio_cread call virtio_config_ops->get internally, the ideal is same
> for both patch, just the implementation detail is different.
>
>> - define a new feature VIRTIO_RPMSG_F_NS.
>
> I add this flag to keep the compatibility with old remote peer, and
> also follow the common virito driver practice.
I discussed with Loic, he is ok to go further with your patch and
abandon his one. Please find some remarks below in-line
>
>>
>> Regards
>> Arnaud
>>
>>
>> On 1/31/19 4:41 PM, Xiang Xiao wrote:
>>> 512 bytes isn't always suitable for all case, let firmware
>>> maker decide the best value from resource table.
>>> enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
>>>
>>> Signed-off-by: Xiang Xiao <[email protected]>
>>> ---
>>> drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
>>> include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
>>> 2 files changed, 56 insertions(+), 18 deletions(-)
>>> create mode 100644 include/uapi/linux/virtio_rpmsg.h
>>>
>>> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
>>> index 59c4554..049dd97 100644
>>> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
>>> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
>>> @@ -16,6 +16,7 @@
>>> #include <linux/virtio.h>
>>> #include <linux/virtio_ids.h>
>>> #include <linux/virtio_config.h>
>>> +#include <linux/virtio_rpmsg.h>
>>> #include <linux/scatterlist.h>
>>> #include <linux/dma-mapping.h>
>>> #include <linux/slab.h>
>>> @@ -38,7 +39,8 @@
>>> * @sbufs: kernel address of tx buffers
>>> * @num_rbufs: total number of buffers for rx
>>> * @num_sbufs: total number of buffers for tx
>>> - * @buf_size: size of one rx or tx buffer
>>> + * @rbuf_size: size of one rx buffer
>>> + * @sbuf_size: size of one tx buffer
>>> * @last_sbuf: index of last tx buffer used
>>> * @rbufs_dma: dma base addr of rx buffers
>>> * @sbufs_dma: dma base addr of tx buffers
>>> @@ -61,7 +63,8 @@ struct virtproc_info {
>>> void *rbufs, *sbufs;
>>> unsigned int num_rbufs;
>>> unsigned int num_sbufs;
>>> - unsigned int buf_size;
>>> + unsigned int rbuf_size;
>>> + unsigned int sbuf_size;
>>> int last_sbuf;
>>> dma_addr_t rbufs_dma;
>>> dma_addr_t sbufs_dma;
>>> @@ -73,9 +76,6 @@ struct virtproc_info {
>>> struct rpmsg_endpoint *ns_ept;
>>> };
>>>
>>> -/* The feature bitmap for virtio rpmsg */
>>> -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
>>> -
>>> /**
>>> * struct rpmsg_hdr - common header for all rpmsg messages
>>> * @src: source address
>>> @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
>>>
>>> /* either pick the next unused tx buffer */
>>> if (vrp->last_sbuf < vrp->num_sbufs)
>>> - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
>>> + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
>>> /* or recycle a used one */
>>> else
>>> ret = virtqueue_get_buf(vrp->svq, &len);
>>> @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
>>> * messaging), or to improve the buffer allocator, to support
>>> * variable-length buffer sizes.
>>> */
>>> - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
>>> + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
>>> dev_err(dev, "message is too big (%d)\n", len);
>>> return -EMSGSIZE;
>>> }
>>> @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
>>> * We currently use fixed-sized buffers, so trivially sanitize
>>> * the reported payload length.
>>> */
>>> - if (len > vrp->buf_size ||
>>> + if (len > vrp->rbuf_size ||
>>> msg->len > (len - sizeof(struct rpmsg_hdr))) {
>>> dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
>>> return -EINVAL;
>>> @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
>>> dev_warn(dev, "msg received with no recipient\n");
>>>
>>> /* publish the real size of the buffer */
>>> - rpmsg_sg_init(&sg, msg, vrp->buf_size);
>>> + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
>>>
>>> /* add the buffer back to the remote processor's virtqueue */
>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
>>> @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>> else
>>> vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
>>>
>>> - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
>>> + /* try to get buffer size from config space */
>>> + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
>>> + /* note: virtio_rpmsg_config is defined from remote view */
>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
>>> + txbuf_size, &vrp->rbuf_size);
>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
>>> + rxbuf_size, &vrp->sbuf_size);
>>> + }
>>> +
>>> + /* use the default if resource table doesn't provide one */
>>> + if (!vrp->rbuf_size)
>>> + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
In this case constant should be renamed DEFAULT_RPMSG_BUF_SIZE as it is
no more a max value
>>> + if (!vrp->sbuf_size)
>>> + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
Here, if the config space exists you need to update it in consequence to
ensure coherency with the remote processor config.

>>>
>>> /* allocate coherent memory for the buffers */
>>> vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
>>> - vrp->num_rbufs * vrp->buf_size,
>>> + vrp->num_rbufs * vrp->rbuf_size,
>>> &vrp->rbufs_dma, GFP_KERNEL);
>>> if (!vrp->rbufs) {
>>> err = -ENOMEM;
>>> @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>> vrp->rbufs, &vrp->rbufs_dma);
>>>
>>> vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
>>> - vrp->num_sbufs * vrp->buf_size,
>>> + vrp->num_sbufs * vrp->sbuf_size,
>>> &vrp->sbufs_dma, GFP_KERNEL);
>>> if (!vrp->sbufs) {
>>> err = -ENOMEM;
>>> @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>> /* set up the receive buffers */
>>> for (i = 0; i < vrp->num_rbufs; i++) {
>>> struct scatterlist sg;
>>> - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
>>> + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
>>>
>>> - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
>>> + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
>>>
>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
>>> GFP_KERNEL);
>>> @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>>
>>> free_sbufs:
>>> dma_free_coherent(vdev->dev.parent->parent,
>>> - vrp->num_sbufs * vrp->buf_size,
>>> + vrp->num_sbufs * vrp->sbuf_size,
>>> vrp->sbufs, vrp->sbufs_dma);
>>> free_rbufs:
>>> dma_free_coherent(vdev->dev.parent->parent,
>>> - vrp->num_rbufs * vrp->buf_size,
>>> + vrp->num_rbufs * vrp->rbuf_size,
>>> vrp->rbufs, vrp->rbufs_dma);
>>> vqs_del:
>>> vdev->config->del_vqs(vrp->vdev);
>>> @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
>>> vdev->config->del_vqs(vrp->vdev);
>>>
>>> dma_free_coherent(vdev->dev.parent->parent,
>>> - vrp->num_sbufs * vrp->buf_size,
>>> + vrp->num_sbufs * vrp->sbuf_size,
>>> vrp->sbufs, vrp->sbufs_dma);
>>> dma_free_coherent(vdev->dev.parent->parent,
>>> - vrp->num_rbufs * vrp->buf_size,
>>> + vrp->num_rbufs * vrp->rbuf_size,
>>> vrp->rbufs, vrp->rbufs_dma);
>>>
>>> kfree(vrp);
>>> @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
>>>
>>> static unsigned int features[] = {
>>> VIRTIO_RPMSG_F_NS,
>>> + VIRTIO_RPMSG_F_BUFSZ,
>>> };
>>>
>>> static struct virtio_driver virtio_ipc_driver = {
>>> diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
>>> new file mode 100644
>>> index 0000000..24fa0dd
>>> --- /dev/null
>>> +++ b/include/uapi/linux/virtio_rpmsg.h
Strange to define a user space API for kernel usage need. Could you
elaborate?

>>> @@ -0,0 +1,24 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>>> +/*
>>> + * Copyright (C) Pinecone Inc. 2019
>>> + * Copyright (C) Xiang Xiao <[email protected]>
>>> + */
>>> +
>>> +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
>>> +#define _UAPI_LINUX_VIRTIO_RPMSG_H
>>> +
>>> +#include <linux/types.h>
>>> +
>>> +/* The feature bitmap for virtio rpmsg */
>>> +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
>>> +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
Would be useful to document it in rpmsg.txt
>>> +
>>> +struct virtio_rpmsg_config {
>>> + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
>>> + __u32 txbuf_size;
>>> + __u32 rxbuf_size;
>>> + __u32 reserved[14]; /* Reserve for the future use */
>>> + /* Put the customize config here */
>>> +} __attribute__((packed));
>>> +
Wouldn't it be better to add an identifier and a version fields at the
beginning of the structure? Idea would be to simplify a future extension
In this case is VIRTIO_RPMSG_F_BUFSZ still useful?

>>> +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
>>>
--
Thanks
Arnaud

2019-06-05 02:43:07

by xiang xiao

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

On Tue, Jun 4, 2019 at 10:25 PM Arnaud Pouliquen
<[email protected]> wrote:
>
> Hello Xiang,
>
> On 5/9/19 3:00 PM, xiang xiao wrote:
> > On Thu, May 9, 2019 at 8:36 PM Arnaud Pouliquen <[email protected]> wrote:
> >>
> >> Hello Xiang,
> >>
> >> Similar mechanism has been proposed by Loic 2 years ago (link to the
> >> series here https://lkml.org/lkml/2017/3/28/349).
> >>
> >> Did you see them? Regarding history, patches seem just on hold...
> >>
> >
> > Just saw this patchset, so it's common problem hit by many vendor,
> > rpmsg framework need to address it.:)
> >
> >> Main differences (except interesting RX/TX size split) seems that you
> >> - don't use the virtio_config_ops->get
> >
> > virtio_cread call virtio_config_ops->get internally, the ideal is same
> > for both patch, just the implementation detail is different.
> >
> >> - define a new feature VIRTIO_RPMSG_F_NS.
> >
> > I add this flag to keep the compatibility with old remote peer, and
> > also follow the common virito driver practice.
> I discussed with Loic, he is ok to go further with your patch and
> abandon his one. Please find some remarks below in-line
> >
> >>
> >> Regards
> >> Arnaud
> >>
> >>
> >> On 1/31/19 4:41 PM, Xiang Xiao wrote:
> >>> 512 bytes isn't always suitable for all case, let firmware
> >>> maker decide the best value from resource table.
> >>> enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
> >>>
> >>> Signed-off-by: Xiang Xiao <[email protected]>
> >>> ---
> >>> drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
> >>> include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
> >>> 2 files changed, 56 insertions(+), 18 deletions(-)
> >>> create mode 100644 include/uapi/linux/virtio_rpmsg.h
> >>>
> >>> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> >>> index 59c4554..049dd97 100644
> >>> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> >>> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> >>> @@ -16,6 +16,7 @@
> >>> #include <linux/virtio.h>
> >>> #include <linux/virtio_ids.h>
> >>> #include <linux/virtio_config.h>
> >>> +#include <linux/virtio_rpmsg.h>
> >>> #include <linux/scatterlist.h>
> >>> #include <linux/dma-mapping.h>
> >>> #include <linux/slab.h>
> >>> @@ -38,7 +39,8 @@
> >>> * @sbufs: kernel address of tx buffers
> >>> * @num_rbufs: total number of buffers for rx
> >>> * @num_sbufs: total number of buffers for tx
> >>> - * @buf_size: size of one rx or tx buffer
> >>> + * @rbuf_size: size of one rx buffer
> >>> + * @sbuf_size: size of one tx buffer
> >>> * @last_sbuf: index of last tx buffer used
> >>> * @rbufs_dma: dma base addr of rx buffers
> >>> * @sbufs_dma: dma base addr of tx buffers
> >>> @@ -61,7 +63,8 @@ struct virtproc_info {
> >>> void *rbufs, *sbufs;
> >>> unsigned int num_rbufs;
> >>> unsigned int num_sbufs;
> >>> - unsigned int buf_size;
> >>> + unsigned int rbuf_size;
> >>> + unsigned int sbuf_size;
> >>> int last_sbuf;
> >>> dma_addr_t rbufs_dma;
> >>> dma_addr_t sbufs_dma;
> >>> @@ -73,9 +76,6 @@ struct virtproc_info {
> >>> struct rpmsg_endpoint *ns_ept;
> >>> };
> >>>
> >>> -/* The feature bitmap for virtio rpmsg */
> >>> -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> >>> -
> >>> /**
> >>> * struct rpmsg_hdr - common header for all rpmsg messages
> >>> * @src: source address
> >>> @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
> >>>
> >>> /* either pick the next unused tx buffer */
> >>> if (vrp->last_sbuf < vrp->num_sbufs)
> >>> - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> >>> + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
> >>> /* or recycle a used one */
> >>> else
> >>> ret = virtqueue_get_buf(vrp->svq, &len);
> >>> @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
> >>> * messaging), or to improve the buffer allocator, to support
> >>> * variable-length buffer sizes.
> >>> */
> >>> - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
> >>> + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
> >>> dev_err(dev, "message is too big (%d)\n", len);
> >>> return -EMSGSIZE;
> >>> }
> >>> @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> >>> * We currently use fixed-sized buffers, so trivially sanitize
> >>> * the reported payload length.
> >>> */
> >>> - if (len > vrp->buf_size ||
> >>> + if (len > vrp->rbuf_size ||
> >>> msg->len > (len - sizeof(struct rpmsg_hdr))) {
> >>> dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
> >>> return -EINVAL;
> >>> @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> >>> dev_warn(dev, "msg received with no recipient\n");
> >>>
> >>> /* publish the real size of the buffer */
> >>> - rpmsg_sg_init(&sg, msg, vrp->buf_size);
> >>> + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
> >>>
> >>> /* add the buffer back to the remote processor's virtqueue */
> >>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
> >>> @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>> else
> >>> vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
> >>>
> >>> - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
> >>> + /* try to get buffer size from config space */
> >>> + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
> >>> + /* note: virtio_rpmsg_config is defined from remote view */
> >>> + virtio_cread(vdev, struct virtio_rpmsg_config,
> >>> + txbuf_size, &vrp->rbuf_size);
> >>> + virtio_cread(vdev, struct virtio_rpmsg_config,
> >>> + rxbuf_size, &vrp->sbuf_size);
> >>> + }
> >>> +
> >>> + /* use the default if resource table doesn't provide one */
> >>> + if (!vrp->rbuf_size)
> >>> + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
> In this case constant should be renamed DEFAULT_RPMSG_BUF_SIZE as it is
> no more a max value

Yes, DEFAULT_RPMSG_BUF_SIZE is more reasonable now.

> >>> + if (!vrp->sbuf_size)
> >>> + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
> Here, if the config space exists you need to update it in consequence to
> ensure coherency with the remote processor config.

The update is already done in if (virtio_has_feature(vdev,
VIRTIO_RPMSG_F_BUFSZ)), here just handle the zero value in config
space which mean the remote side want to use the default value even
VIRTIO_RPMSG_F_BUFSZ set.
For example:
1.remote side want to change one direction buffer size, but keep
another direction as default
2.or remote side want to change other config options(define in the
furture) not the buffer size

>
> >>>
> >>> /* allocate coherent memory for the buffers */
> >>> vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_rbufs * vrp->buf_size,
> >>> + vrp->num_rbufs * vrp->rbuf_size,
> >>> &vrp->rbufs_dma, GFP_KERNEL);
> >>> if (!vrp->rbufs) {
> >>> err = -ENOMEM;
> >>> @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>> vrp->rbufs, &vrp->rbufs_dma);
> >>>
> >>> vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_sbufs * vrp->buf_size,
> >>> + vrp->num_sbufs * vrp->sbuf_size,
> >>> &vrp->sbufs_dma, GFP_KERNEL);
> >>> if (!vrp->sbufs) {
> >>> err = -ENOMEM;
> >>> @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>> /* set up the receive buffers */
> >>> for (i = 0; i < vrp->num_rbufs; i++) {
> >>> struct scatterlist sg;
> >>> - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
> >>> + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
> >>>
> >>> - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
> >>> + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
> >>>
> >>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
> >>> GFP_KERNEL);
> >>> @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>>
> >>> free_sbufs:
> >>> dma_free_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_sbufs * vrp->buf_size,
> >>> + vrp->num_sbufs * vrp->sbuf_size,
> >>> vrp->sbufs, vrp->sbufs_dma);
> >>> free_rbufs:
> >>> dma_free_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_rbufs * vrp->buf_size,
> >>> + vrp->num_rbufs * vrp->rbuf_size,
> >>> vrp->rbufs, vrp->rbufs_dma);
> >>> vqs_del:
> >>> vdev->config->del_vqs(vrp->vdev);
> >>> @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
> >>> vdev->config->del_vqs(vrp->vdev);
> >>>
> >>> dma_free_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_sbufs * vrp->buf_size,
> >>> + vrp->num_sbufs * vrp->sbuf_size,
> >>> vrp->sbufs, vrp->sbufs_dma);
> >>> dma_free_coherent(vdev->dev.parent->parent,
> >>> - vrp->num_rbufs * vrp->buf_size,
> >>> + vrp->num_rbufs * vrp->rbuf_size,
> >>> vrp->rbufs, vrp->rbufs_dma);
> >>>
> >>> kfree(vrp);
> >>> @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
> >>>
> >>> static unsigned int features[] = {
> >>> VIRTIO_RPMSG_F_NS,
> >>> + VIRTIO_RPMSG_F_BUFSZ,
> >>> };
> >>>
> >>> static struct virtio_driver virtio_ipc_driver = {
> >>> diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
> >>> new file mode 100644
> >>> index 0000000..24fa0dd
> >>> --- /dev/null
> >>> +++ b/include/uapi/linux/virtio_rpmsg.h
> Strange to define a user space API for kernel usage need. Could you
> elaborate?

I just follow the practice other virtio drivers(e.g.
include/uapi/virtio_net.h) applied, but rpmsg driver don't need to
talk with the host VM software like other virtio driver, yes this
header file isn't really needed.

> >>> @@ -0,0 +1,24 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >>> +/*
> >>> + * Copyright (C) Pinecone Inc. 2019
> >>> + * Copyright (C) Xiang Xiao <[email protected]>
> >>> + */
> >>> +
> >>> +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
> >>> +#define _UAPI_LINUX_VIRTIO_RPMSG_H
> >>> +
> >>> +#include <linux/types.h>
> >>> +
> >>> +/* The feature bitmap for virtio rpmsg */
> >>> +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> >>> +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
> Would be useful to document it in rpmsg.txt

Good point, but it is better to put them into this document:
https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html
like other vritio driver spec.

> >>> +
> >>> +struct virtio_rpmsg_config {
> >>> + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
> >>> + __u32 txbuf_size;
> >>> + __u32 rxbuf_size;
> >>> + __u32 reserved[14]; /* Reserve for the future use */
> >>> + /* Put the customize config here */
> >>> +} __attribute__((packed));
> >>> +
> Wouldn't it be better to add an identifier and a version fields at the
> beginning of the structure? Idea would be to simplify a future extension
> In this case is VIRTIO_RPMSG_F_BUFSZ still useful?
>

Yes, I consider this option before, but after review all
include/uapi/virtio_*.h, I found that virito driver prefer feature
bits than version number to handle the compability issue.
For example, if we need introduce more options in the furture, we need:
1.Add new feature bit to notice the option exist
2.Allocate the field from reserved space

> >>> +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
> >>>
> --
> Thanks
> Arnaud

2019-06-05 04:35:43

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

On Thu 31 Jan 07:41 PST 2019, Xiang Xiao wrote:

> Hi,
> This series enhance the buffer allocation by:
> 1.Support the different buffer number in rx/tx direction
> 2.Get the individual rx/tx buffer size from config space
>
> Here is the related OpenAMP change:
> https://github.com/OpenAMP/open-amp/pull/155
>

This looks pretty reasonable, but can you confirm that it's possible to
use new firmware with an old Linux kernel when introducing this?


But ever since we discussed Loic's similar proposal earlier I've been
questioning if the fixed buffer size isn't just an artifact of how we
preallocate our buffers. The virtqueue seems to support arbitrary sizes
of buffers and I see that the receive function in OpenAMP has been fixed
to put back the buffer of the size that was received, rather than 512
bytes. So it seems like Linux would be able to send whatever size
messages to OpenAMP it would handle it.

The question is if we could do the same in the other direction, perhaps
by letting the OpenAMP side do it's message allocation when it's
sending, rather than Linux pushing inbufs to be filled by the remote.

This would remove the problem of always having suboptimal buffer sizes.

Regards,
Bjorn

> Xiang Xiao (3):
> rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv
> rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately
> rpmsg: virtio_rpmsg_bus: get buffer size from config space
>
> drivers/rpmsg/virtio_rpmsg_bus.c | 127 +++++++++++++++++++++++---------------
> include/uapi/linux/virtio_rpmsg.h | 24 +++++++
> 2 files changed, 100 insertions(+), 51 deletions(-)
> create mode 100644 include/uapi/linux/virtio_rpmsg.h
>
> --
> 2.7.4
>

2019-06-05 07:34:49

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

Hi Bjorn,

On 6/5/19 6:34 AM, Bjorn Andersson wrote:
> On Thu 31 Jan 07:41 PST 2019, Xiang Xiao wrote:
>
>> Hi,
>> This series enhance the buffer allocation by:
>> 1.Support the different buffer number in rx/tx direction
>> 2.Get the individual rx/tx buffer size from config space
>>
>> Here is the related OpenAMP change:
>> https://github.com/OpenAMP/open-amp/pull/155
>>
>
> This looks pretty reasonable, but can you confirm that it's possible to
> use new firmware with an old Linux kernel when introducing this?
>
>
> But ever since we discussed Loic's similar proposal earlier I've been
> questioning if the fixed buffer size isn't just an artifact of how we
> preallocate our buffers. The virtqueue seems to support arbitrary sizes
> of buffers and I see that the receive function in OpenAMP has been fixed
> to put back the buffer of the size that was received, rather than 512
> bytes. So it seems like Linux would be able to send whatever size
> messages to OpenAMP it would handle it.
>
> The question is if we could do the same in the other direction, perhaps
> by letting the OpenAMP side do it's message allocation when it's
> sending, rather than Linux pushing inbufs to be filled by the remote.

IMHO, both could be useful and could be not correlated.
On-the fly buffer allocation seems more efficient but needs an
allocator.This can be a generic allocator (with a va to da) for system
where large amount of memories are accessible from both side.

Now what about system with small shared memory? In this case you have to
deal with a limited/optimized memory chunk. To avoid memory
fragmentation the allocator should have a pre-reserved buffers pool(so
similar to existing implementation). This serie seems useful to optimize
the size of the pre-reserved pool.

>
> This would remove the problem of always having suboptimal buffer sizes.
>
> Regards,
> Bjorn
>
>> Xiang Xiao (3):
>> rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv
>> rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately
>> rpmsg: virtio_rpmsg_bus: get buffer size from config space
>>
>> drivers/rpmsg/virtio_rpmsg_bus.c | 127 +++++++++++++++++++++++---------------
>> include/uapi/linux/virtio_rpmsg.h | 24 +++++++
>> 2 files changed, 100 insertions(+), 51 deletions(-)
>> create mode 100644 include/uapi/linux/virtio_rpmsg.h
>>
>> --
>> 2.7.4
>>

--

Regards,
Arnaud

2019-06-05 08:05:52

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space



On 6/5/19 4:40 AM, xiang xiao wrote:
> On Tue, Jun 4, 2019 at 10:25 PM Arnaud Pouliquen
> <[email protected]> wrote:
>>
>> Hello Xiang,
>>
>> On 5/9/19 3:00 PM, xiang xiao wrote:
>>> On Thu, May 9, 2019 at 8:36 PM Arnaud Pouliquen <[email protected]> wrote:
>>>>
>>>> Hello Xiang,
>>>>
>>>> Similar mechanism has been proposed by Loic 2 years ago (link to the
>>>> series here https://lkml.org/lkml/2017/3/28/349).
>>>>
>>>> Did you see them? Regarding history, patches seem just on hold...
>>>>
>>>
>>> Just saw this patchset, so it's common problem hit by many vendor,
>>> rpmsg framework need to address it.:)
>>>
>>>> Main differences (except interesting RX/TX size split) seems that you
>>>> - don't use the virtio_config_ops->get
>>>
>>> virtio_cread call virtio_config_ops->get internally, the ideal is same
>>> for both patch, just the implementation detail is different.
>>>
>>>> - define a new feature VIRTIO_RPMSG_F_NS.
>>>
>>> I add this flag to keep the compatibility with old remote peer, and
>>> also follow the common virito driver practice.
>> I discussed with Loic, he is ok to go further with your patch and
>> abandon his one. Please find some remarks below in-line
>>>
>>>>
>>>> Regards
>>>> Arnaud
>>>>
>>>>
>>>> On 1/31/19 4:41 PM, Xiang Xiao wrote:
>>>>> 512 bytes isn't always suitable for all case, let firmware
>>>>> maker decide the best value from resource table.
>>>>> enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
>>>>>
>>>>> Signed-off-by: Xiang Xiao <[email protected]>
>>>>> ---
>>>>> drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
>>>>> include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
>>>>> 2 files changed, 56 insertions(+), 18 deletions(-)
>>>>> create mode 100644 include/uapi/linux/virtio_rpmsg.h
>>>>>
>>>>> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
>>>>> index 59c4554..049dd97 100644
>>>>> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
>>>>> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
>>>>> @@ -16,6 +16,7 @@
>>>>> #include <linux/virtio.h>
>>>>> #include <linux/virtio_ids.h>
>>>>> #include <linux/virtio_config.h>
>>>>> +#include <linux/virtio_rpmsg.h>
>>>>> #include <linux/scatterlist.h>
>>>>> #include <linux/dma-mapping.h>
>>>>> #include <linux/slab.h>
>>>>> @@ -38,7 +39,8 @@
>>>>> * @sbufs: kernel address of tx buffers
>>>>> * @num_rbufs: total number of buffers for rx
>>>>> * @num_sbufs: total number of buffers for tx
>>>>> - * @buf_size: size of one rx or tx buffer
>>>>> + * @rbuf_size: size of one rx buffer
>>>>> + * @sbuf_size: size of one tx buffer
>>>>> * @last_sbuf: index of last tx buffer used
>>>>> * @rbufs_dma: dma base addr of rx buffers
>>>>> * @sbufs_dma: dma base addr of tx buffers
>>>>> @@ -61,7 +63,8 @@ struct virtproc_info {
>>>>> void *rbufs, *sbufs;
>>>>> unsigned int num_rbufs;
>>>>> unsigned int num_sbufs;
>>>>> - unsigned int buf_size;
>>>>> + unsigned int rbuf_size;
>>>>> + unsigned int sbuf_size;
>>>>> int last_sbuf;
>>>>> dma_addr_t rbufs_dma;
>>>>> dma_addr_t sbufs_dma;
>>>>> @@ -73,9 +76,6 @@ struct virtproc_info {
>>>>> struct rpmsg_endpoint *ns_ept;
>>>>> };
>>>>>
>>>>> -/* The feature bitmap for virtio rpmsg */
>>>>> -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
>>>>> -
>>>>> /**
>>>>> * struct rpmsg_hdr - common header for all rpmsg messages
>>>>> * @src: source address
>>>>> @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
>>>>>
>>>>> /* either pick the next unused tx buffer */
>>>>> if (vrp->last_sbuf < vrp->num_sbufs)
>>>>> - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
>>>>> + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
>>>>> /* or recycle a used one */
>>>>> else
>>>>> ret = virtqueue_get_buf(vrp->svq, &len);
>>>>> @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
>>>>> * messaging), or to improve the buffer allocator, to support
>>>>> * variable-length buffer sizes.
>>>>> */
>>>>> - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
>>>>> + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
>>>>> dev_err(dev, "message is too big (%d)\n", len);
>>>>> return -EMSGSIZE;
>>>>> }
>>>>> @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
>>>>> * We currently use fixed-sized buffers, so trivially sanitize
>>>>> * the reported payload length.
>>>>> */
>>>>> - if (len > vrp->buf_size ||
>>>>> + if (len > vrp->rbuf_size ||
>>>>> msg->len > (len - sizeof(struct rpmsg_hdr))) {
>>>>> dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
>>>>> return -EINVAL;
>>>>> @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
>>>>> dev_warn(dev, "msg received with no recipient\n");
>>>>>
>>>>> /* publish the real size of the buffer */
>>>>> - rpmsg_sg_init(&sg, msg, vrp->buf_size);
>>>>> + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
>>>>>
>>>>> /* add the buffer back to the remote processor's virtqueue */
>>>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
>>>>> @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>>>> else
>>>>> vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
>>>>>
>>>>> - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
>>>>> + /* try to get buffer size from config space */
>>>>> + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
>>>>> + /* note: virtio_rpmsg_config is defined from remote view */
>>>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
>>>>> + txbuf_size, &vrp->rbuf_size);
>>>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
>>>>> + rxbuf_size, &vrp->sbuf_size);
>>>>> + }
>>>>> +
>>>>> + /* use the default if resource table doesn't provide one */
>>>>> + if (!vrp->rbuf_size)
>>>>> + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
>> In this case constant should be renamed DEFAULT_RPMSG_BUF_SIZE as it is
>> no more a max value
>
> Yes, DEFAULT_RPMSG_BUF_SIZE is more reasonable now.
>
>>>>> + if (!vrp->sbuf_size)
>>>>> + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
>> Here, if the config space exists you need to update it in consequence to
>> ensure coherency with the remote processor config.
>
> The update is already done in if (virtio_has_feature(vdev,
> VIRTIO_RPMSG_F_BUFSZ)), here just handle the zero value in config
> space which mean the remote side want to use the default value even
> VIRTIO_RPMSG_F_BUFSZ set.
> For example:
> 1.remote side want to change one direction buffer size, but keep
> another direction as default
> 2.or remote side want to change other config options(define in the
> furture) not the buffer size

In code above i can see a virtio_cread of the config structure, but no
writing of it...
I mentioned the configs space in the resource table itself.
Without an update, you must ensure that both have the same default
value... In addition, it makes sense that the master can update the
buffer size according to some other constraints.

>
>>
>>>>>
>>>>> /* allocate coherent memory for the buffers */
>>>>> vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_rbufs * vrp->buf_size,
>>>>> + vrp->num_rbufs * vrp->rbuf_size,
>>>>> &vrp->rbufs_dma, GFP_KERNEL);
>>>>> if (!vrp->rbufs) {
>>>>> err = -ENOMEM;
>>>>> @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>>>> vrp->rbufs, &vrp->rbufs_dma);
>>>>>
>>>>> vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_sbufs * vrp->buf_size,
>>>>> + vrp->num_sbufs * vrp->sbuf_size,
>>>>> &vrp->sbufs_dma, GFP_KERNEL);
>>>>> if (!vrp->sbufs) {
>>>>> err = -ENOMEM;
>>>>> @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>>>> /* set up the receive buffers */
>>>>> for (i = 0; i < vrp->num_rbufs; i++) {
>>>>> struct scatterlist sg;
>>>>> - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
>>>>> + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
>>>>>
>>>>> - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
>>>>> + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
>>>>>
>>>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
>>>>> GFP_KERNEL);
>>>>> @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
>>>>>
>>>>> free_sbufs:
>>>>> dma_free_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_sbufs * vrp->buf_size,
>>>>> + vrp->num_sbufs * vrp->sbuf_size,
>>>>> vrp->sbufs, vrp->sbufs_dma);
>>>>> free_rbufs:
>>>>> dma_free_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_rbufs * vrp->buf_size,
>>>>> + vrp->num_rbufs * vrp->rbuf_size,
>>>>> vrp->rbufs, vrp->rbufs_dma);
>>>>> vqs_del:
>>>>> vdev->config->del_vqs(vrp->vdev);
>>>>> @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
>>>>> vdev->config->del_vqs(vrp->vdev);
>>>>>
>>>>> dma_free_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_sbufs * vrp->buf_size,
>>>>> + vrp->num_sbufs * vrp->sbuf_size,
>>>>> vrp->sbufs, vrp->sbufs_dma);
>>>>> dma_free_coherent(vdev->dev.parent->parent,
>>>>> - vrp->num_rbufs * vrp->buf_size,
>>>>> + vrp->num_rbufs * vrp->rbuf_size,
>>>>> vrp->rbufs, vrp->rbufs_dma);
>>>>>
>>>>> kfree(vrp);
>>>>> @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
>>>>>
>>>>> static unsigned int features[] = {
>>>>> VIRTIO_RPMSG_F_NS,
>>>>> + VIRTIO_RPMSG_F_BUFSZ,
>>>>> };
>>>>>
>>>>> static struct virtio_driver virtio_ipc_driver = {
>>>>> diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
>>>>> new file mode 100644
>>>>> index 0000000..24fa0dd
>>>>> --- /dev/null
>>>>> +++ b/include/uapi/linux/virtio_rpmsg.h
>> Strange to define a user space API for kernel usage need. Could you
>> elaborate?
>
> I just follow the practice other virtio drivers(e.g.
> include/uapi/virtio_net.h) applied, but rpmsg driver don't need to
> talk with the host VM software like other virtio driver, yes this
> header file isn't really needed.
>
>>>>> @@ -0,0 +1,24 @@
>>>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>>>>> +/*
>>>>> + * Copyright (C) Pinecone Inc. 2019
>>>>> + * Copyright (C) Xiang Xiao <[email protected]>
>>>>> + */
>>>>> +
>>>>> +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
>>>>> +#define _UAPI_LINUX_VIRTIO_RPMSG_H
>>>>> +
>>>>> +#include <linux/types.h>
>>>>> +
>>>>> +/* The feature bitmap for virtio rpmsg */
>>>>> +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
>>>>> +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
>> Would be useful to document it in rpmsg.txt
>
> Good point, but it is better to put them into this document:
> https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html
> like other vritio driver spec.
>
>>>>> +
>>>>> +struct virtio_rpmsg_config {
>>>>> + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
>>>>> + __u32 txbuf_size;
>>>>> + __u32 rxbuf_size;
>>>>> + __u32 reserved[14]; /* Reserve for the future use */
>>>>> + /* Put the customize config here */
>>>>> +} __attribute__((packed));
>>>>> +
>> Wouldn't it be better to add an identifier and a version fields at the
>> beginning of the structure? Idea would be to simplify a future extension
>> In this case is VIRTIO_RPMSG_F_BUFSZ still useful?
>>
>
> Yes, I consider this option before, but after review all
> include/uapi/virtio_*.h, I found that virito driver prefer feature
> bits than version number to handle the compability issue.
> For example, if we need introduce more options in the furture, we need:
> 1.Add new feature bit to notice the option exist
> 2.Allocate the field from reserved space
>
>>>>> +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
>>>>>
>> --
>> Thanks
>> Arnaud

2019-06-05 08:36:37

by xiang xiao

[permalink] [raw]
Subject: Re: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

On Wed, Jun 5, 2019 at 3:33 PM Arnaud Pouliquen <[email protected]> wrote:
>
> Hi Bjorn,
>
> On 6/5/19 6:34 AM, Bjorn Andersson wrote:
> > On Thu 31 Jan 07:41 PST 2019, Xiang Xiao wrote:
> >
> >> Hi,
> >> This series enhance the buffer allocation by:
> >> 1.Support the different buffer number in rx/tx direction
> >> 2.Get the individual rx/tx buffer size from config space
> >>
> >> Here is the related OpenAMP change:
> >> https://github.com/OpenAMP/open-amp/pull/155
> >>
> >
> > This looks pretty reasonable, but can you confirm that it's possible to
> > use new firmware with an old Linux kernel when introducing this?
> >
> >
> > But ever since we discussed Loic's similar proposal earlier I've been
> > questioning if the fixed buffer size isn't just an artifact of how we
> > preallocate our buffers. The virtqueue seems to support arbitrary sizes
> > of buffers and I see that the receive function in OpenAMP has been fixed
> > to put back the buffer of the size that was received, rather than 512
> > bytes. So it seems like Linux would be able to send whatever size
> > messages to OpenAMP it would handle it.
> >
> > The question is if we could do the same in the other direction, perhaps
> > by letting the OpenAMP side do it's message allocation when it's
> > sending, rather than Linux pushing inbufs to be filled by the remote.
>
> IMHO, both could be useful and could be not correlated.
> On-the fly buffer allocation seems more efficient but needs an
> allocator.This can be a generic allocator (with a va to da) for system
> where large amount of memories are accessible from both side.
>
> Now what about system with small shared memory? In this case you have to
> deal with a limited/optimized memory chunk. To avoid memory
> fragmentation the allocator should have a pre-reserved buffers pool(so
> similar to existing implementation). This serie seems useful to optimize
> the size of the pre-reserved pool.
>

Maybe we can reuse rxbuf_size/txbuf_size to trigger the different
allocation policy:
1.If buf_size equal 0xfffffff, turn on the dynamic allocator
2.If buf_size equall 0, turn on the fixed allocator with the default buffer size
3.otherwise, turn on the fixed allocator with the configed buffer size
So, both requirement could be satisfied without breaking the compatibility.

> >
> > This would remove the problem of always having suboptimal buffer sizes.
> >
> > Regards,
> > Bjorn
> >
> >> Xiang Xiao (3):
> >> rpmsg: virtio_rpmsg_bus: allow the different vring size for send/recv
> >> rpmsg: virtio_rpmsg_bus: allocate rx/tx buffer separately
> >> rpmsg: virtio_rpmsg_bus: get buffer size from config space
> >>
> >> drivers/rpmsg/virtio_rpmsg_bus.c | 127 +++++++++++++++++++++++---------------
> >> include/uapi/linux/virtio_rpmsg.h | 24 +++++++
> >> 2 files changed, 100 insertions(+), 51 deletions(-)
> >> create mode 100644 include/uapi/linux/virtio_rpmsg.h
> >>
> >> --
> >> 2.7.4
> >>
>
> --
>
> Regards,
> Arnaud

2019-06-05 08:38:28

by xiang xiao

[permalink] [raw]
Subject: Re: [PATCH 3/3] rpmsg: virtio_rpmsg_bus: get buffer size from config space

On Wed, Jun 5, 2019 at 4:02 PM Arnaud Pouliquen <[email protected]> wrote:
>
>
>
> On 6/5/19 4:40 AM, xiang xiao wrote:
> > On Tue, Jun 4, 2019 at 10:25 PM Arnaud Pouliquen
> > <[email protected]> wrote:
> >>
> >> Hello Xiang,
> >>
> >> On 5/9/19 3:00 PM, xiang xiao wrote:
> >>> On Thu, May 9, 2019 at 8:36 PM Arnaud Pouliquen <[email protected]> wrote:
> >>>>
> >>>> Hello Xiang,
> >>>>
> >>>> Similar mechanism has been proposed by Loic 2 years ago (link to the
> >>>> series here https://lkml.org/lkml/2017/3/28/349).
> >>>>
> >>>> Did you see them? Regarding history, patches seem just on hold...
> >>>>
> >>>
> >>> Just saw this patchset, so it's common problem hit by many vendor,
> >>> rpmsg framework need to address it.:)
> >>>
> >>>> Main differences (except interesting RX/TX size split) seems that you
> >>>> - don't use the virtio_config_ops->get
> >>>
> >>> virtio_cread call virtio_config_ops->get internally, the ideal is same
> >>> for both patch, just the implementation detail is different.
> >>>
> >>>> - define a new feature VIRTIO_RPMSG_F_NS.
> >>>
> >>> I add this flag to keep the compatibility with old remote peer, and
> >>> also follow the common virito driver practice.
> >> I discussed with Loic, he is ok to go further with your patch and
> >> abandon his one. Please find some remarks below in-line
> >>>
> >>>>
> >>>> Regards
> >>>> Arnaud
> >>>>
> >>>>
> >>>> On 1/31/19 4:41 PM, Xiang Xiao wrote:
> >>>>> 512 bytes isn't always suitable for all case, let firmware
> >>>>> maker decide the best value from resource table.
> >>>>> enable by VIRTIO_RPMSG_F_BUFSZ feature bit.
> >>>>>
> >>>>> Signed-off-by: Xiang Xiao <[email protected]>
> >>>>> ---
> >>>>> drivers/rpmsg/virtio_rpmsg_bus.c | 50 +++++++++++++++++++++++++--------------
> >>>>> include/uapi/linux/virtio_rpmsg.h | 24 +++++++++++++++++++
> >>>>> 2 files changed, 56 insertions(+), 18 deletions(-)
> >>>>> create mode 100644 include/uapi/linux/virtio_rpmsg.h
> >>>>>
> >>>>> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> >>>>> index 59c4554..049dd97 100644
> >>>>> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> >>>>> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> >>>>> @@ -16,6 +16,7 @@
> >>>>> #include <linux/virtio.h>
> >>>>> #include <linux/virtio_ids.h>
> >>>>> #include <linux/virtio_config.h>
> >>>>> +#include <linux/virtio_rpmsg.h>
> >>>>> #include <linux/scatterlist.h>
> >>>>> #include <linux/dma-mapping.h>
> >>>>> #include <linux/slab.h>
> >>>>> @@ -38,7 +39,8 @@
> >>>>> * @sbufs: kernel address of tx buffers
> >>>>> * @num_rbufs: total number of buffers for rx
> >>>>> * @num_sbufs: total number of buffers for tx
> >>>>> - * @buf_size: size of one rx or tx buffer
> >>>>> + * @rbuf_size: size of one rx buffer
> >>>>> + * @sbuf_size: size of one tx buffer
> >>>>> * @last_sbuf: index of last tx buffer used
> >>>>> * @rbufs_dma: dma base addr of rx buffers
> >>>>> * @sbufs_dma: dma base addr of tx buffers
> >>>>> @@ -61,7 +63,8 @@ struct virtproc_info {
> >>>>> void *rbufs, *sbufs;
> >>>>> unsigned int num_rbufs;
> >>>>> unsigned int num_sbufs;
> >>>>> - unsigned int buf_size;
> >>>>> + unsigned int rbuf_size;
> >>>>> + unsigned int sbuf_size;
> >>>>> int last_sbuf;
> >>>>> dma_addr_t rbufs_dma;
> >>>>> dma_addr_t sbufs_dma;
> >>>>> @@ -73,9 +76,6 @@ struct virtproc_info {
> >>>>> struct rpmsg_endpoint *ns_ept;
> >>>>> };
> >>>>>
> >>>>> -/* The feature bitmap for virtio rpmsg */
> >>>>> -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> >>>>> -
> >>>>> /**
> >>>>> * struct rpmsg_hdr - common header for all rpmsg messages
> >>>>> * @src: source address
> >>>>> @@ -452,7 +452,7 @@ static void *get_a_tx_buf(struct virtproc_info *vrp)
> >>>>>
> >>>>> /* either pick the next unused tx buffer */
> >>>>> if (vrp->last_sbuf < vrp->num_sbufs)
> >>>>> - ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> >>>>> + ret = vrp->sbufs + vrp->sbuf_size * vrp->last_sbuf++;
> >>>>> /* or recycle a used one */
> >>>>> else
> >>>>> ret = virtqueue_get_buf(vrp->svq, &len);
> >>>>> @@ -578,7 +578,7 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
> >>>>> * messaging), or to improve the buffer allocator, to support
> >>>>> * variable-length buffer sizes.
> >>>>> */
> >>>>> - if (len > vrp->buf_size - sizeof(struct rpmsg_hdr)) {
> >>>>> + if (len > vrp->sbuf_size - sizeof(struct rpmsg_hdr)) {
> >>>>> dev_err(dev, "message is too big (%d)\n", len);
> >>>>> return -EMSGSIZE;
> >>>>> }
> >>>>> @@ -718,7 +718,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> >>>>> * We currently use fixed-sized buffers, so trivially sanitize
> >>>>> * the reported payload length.
> >>>>> */
> >>>>> - if (len > vrp->buf_size ||
> >>>>> + if (len > vrp->rbuf_size ||
> >>>>> msg->len > (len - sizeof(struct rpmsg_hdr))) {
> >>>>> dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
> >>>>> return -EINVAL;
> >>>>> @@ -751,7 +751,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> >>>>> dev_warn(dev, "msg received with no recipient\n");
> >>>>>
> >>>>> /* publish the real size of the buffer */
> >>>>> - rpmsg_sg_init(&sg, msg, vrp->buf_size);
> >>>>> + rpmsg_sg_init(&sg, msg, vrp->rbuf_size);
> >>>>>
> >>>>> /* add the buffer back to the remote processor's virtqueue */
> >>>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
> >>>>> @@ -907,11 +907,24 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>>>> else
> >>>>> vrp->num_sbufs = MAX_RPMSG_NUM_BUFS;
> >>>>>
> >>>>> - vrp->buf_size = MAX_RPMSG_BUF_SIZE;
> >>>>> + /* try to get buffer size from config space */
> >>>>> + if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_BUFSZ)) {
> >>>>> + /* note: virtio_rpmsg_config is defined from remote view */
> >>>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
> >>>>> + txbuf_size, &vrp->rbuf_size);
> >>>>> + virtio_cread(vdev, struct virtio_rpmsg_config,
> >>>>> + rxbuf_size, &vrp->sbuf_size);
> >>>>> + }
> >>>>> +
> >>>>> + /* use the default if resource table doesn't provide one */
> >>>>> + if (!vrp->rbuf_size)
> >>>>> + vrp->rbuf_size = MAX_RPMSG_BUF_SIZE;
> >> In this case constant should be renamed DEFAULT_RPMSG_BUF_SIZE as it is
> >> no more a max value
> >
> > Yes, DEFAULT_RPMSG_BUF_SIZE is more reasonable now.
> >
> >>>>> + if (!vrp->sbuf_size)
> >>>>> + vrp->sbuf_size = MAX_RPMSG_BUF_SIZE;
> >> Here, if the config space exists you need to update it in consequence to
> >> ensure coherency with the remote processor config.
> >
> > The update is already done in if (virtio_has_feature(vdev,
> > VIRTIO_RPMSG_F_BUFSZ)), here just handle the zero value in config
> > space which mean the remote side want to use the default value even
> > VIRTIO_RPMSG_F_BUFSZ set.
> > For example:
> > 1.remote side want to change one direction buffer size, but keep
> > another direction as default
> > 2.or remote side want to change other config options(define in the
> > furture) not the buffer size
>
> In code above i can see a virtio_cread of the config structure, but no
> writing of it...
> I mentioned the configs space in the resource table itself.
> Without an update, you must ensure that both have the same default
> value... In addition, it makes sense that the master can update the
> buffer size according to some other constraints.

Get your point, thanks.

>
> >
> >>
> >>>>>
> >>>>> /* allocate coherent memory for the buffers */
> >>>>> vrp->rbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_rbufs * vrp->buf_size,
> >>>>> + vrp->num_rbufs * vrp->rbuf_size,
> >>>>> &vrp->rbufs_dma, GFP_KERNEL);
> >>>>> if (!vrp->rbufs) {
> >>>>> err = -ENOMEM;
> >>>>> @@ -922,7 +935,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>>>> vrp->rbufs, &vrp->rbufs_dma);
> >>>>>
> >>>>> vrp->sbufs = dma_alloc_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_sbufs * vrp->buf_size,
> >>>>> + vrp->num_sbufs * vrp->sbuf_size,
> >>>>> &vrp->sbufs_dma, GFP_KERNEL);
> >>>>> if (!vrp->sbufs) {
> >>>>> err = -ENOMEM;
> >>>>> @@ -935,9 +948,9 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>>>> /* set up the receive buffers */
> >>>>> for (i = 0; i < vrp->num_rbufs; i++) {
> >>>>> struct scatterlist sg;
> >>>>> - void *cpu_addr = vrp->rbufs + i * vrp->buf_size;
> >>>>> + void *cpu_addr = vrp->rbufs + i * vrp->rbuf_size;
> >>>>>
> >>>>> - rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size);
> >>>>> + rpmsg_sg_init(&sg, cpu_addr, vrp->rbuf_size);
> >>>>>
> >>>>> err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
> >>>>> GFP_KERNEL);
> >>>>> @@ -984,11 +997,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
> >>>>>
> >>>>> free_sbufs:
> >>>>> dma_free_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_sbufs * vrp->buf_size,
> >>>>> + vrp->num_sbufs * vrp->sbuf_size,
> >>>>> vrp->sbufs, vrp->sbufs_dma);
> >>>>> free_rbufs:
> >>>>> dma_free_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_rbufs * vrp->buf_size,
> >>>>> + vrp->num_rbufs * vrp->rbuf_size,
> >>>>> vrp->rbufs, vrp->rbufs_dma);
> >>>>> vqs_del:
> >>>>> vdev->config->del_vqs(vrp->vdev);
> >>>>> @@ -1023,10 +1036,10 @@ static void rpmsg_remove(struct virtio_device *vdev)
> >>>>> vdev->config->del_vqs(vrp->vdev);
> >>>>>
> >>>>> dma_free_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_sbufs * vrp->buf_size,
> >>>>> + vrp->num_sbufs * vrp->sbuf_size,
> >>>>> vrp->sbufs, vrp->sbufs_dma);
> >>>>> dma_free_coherent(vdev->dev.parent->parent,
> >>>>> - vrp->num_rbufs * vrp->buf_size,
> >>>>> + vrp->num_rbufs * vrp->rbuf_size,
> >>>>> vrp->rbufs, vrp->rbufs_dma);
> >>>>>
> >>>>> kfree(vrp);
> >>>>> @@ -1039,6 +1052,7 @@ static struct virtio_device_id id_table[] = {
> >>>>>
> >>>>> static unsigned int features[] = {
> >>>>> VIRTIO_RPMSG_F_NS,
> >>>>> + VIRTIO_RPMSG_F_BUFSZ,
> >>>>> };
> >>>>>
> >>>>> static struct virtio_driver virtio_ipc_driver = {
> >>>>> diff --git a/include/uapi/linux/virtio_rpmsg.h b/include/uapi/linux/virtio_rpmsg.h
> >>>>> new file mode 100644
> >>>>> index 0000000..24fa0dd
> >>>>> --- /dev/null
> >>>>> +++ b/include/uapi/linux/virtio_rpmsg.h
> >> Strange to define a user space API for kernel usage need. Could you
> >> elaborate?
> >
> > I just follow the practice other virtio drivers(e.g.
> > include/uapi/virtio_net.h) applied, but rpmsg driver don't need to
> > talk with the host VM software like other virtio driver, yes this
> > header file isn't really needed.
> >
> >>>>> @@ -0,0 +1,24 @@
> >>>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >>>>> +/*
> >>>>> + * Copyright (C) Pinecone Inc. 2019
> >>>>> + * Copyright (C) Xiang Xiao <[email protected]>
> >>>>> + */
> >>>>> +
> >>>>> +#ifndef _UAPI_LINUX_VIRTIO_RPMSG_H
> >>>>> +#define _UAPI_LINUX_VIRTIO_RPMSG_H
> >>>>> +
> >>>>> +#include <linux/types.h>
> >>>>> +
> >>>>> +/* The feature bitmap for virtio rpmsg */
> >>>>> +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
> >>>>> +#define VIRTIO_RPMSG_F_BUFSZ 2 /* RP get buffer size from config space */
> >> Would be useful to document it in rpmsg.txt
> >
> > Good point, but it is better to put them into this document:
> > https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html
> > like other vritio driver spec.
> >
> >>>>> +
> >>>>> +struct virtio_rpmsg_config {
> >>>>> + /* The tx/rx individual buffer size(if VIRTIO_RPMSG_F_BUFSZ) */
> >>>>> + __u32 txbuf_size;
> >>>>> + __u32 rxbuf_size;
> >>>>> + __u32 reserved[14]; /* Reserve for the future use */
> >>>>> + /* Put the customize config here */
> >>>>> +} __attribute__((packed));
> >>>>> +
> >> Wouldn't it be better to add an identifier and a version fields at the
> >> beginning of the structure? Idea would be to simplify a future extension
> >> In this case is VIRTIO_RPMSG_F_BUFSZ still useful?
> >>
> >
> > Yes, I consider this option before, but after review all
> > include/uapi/virtio_*.h, I found that virito driver prefer feature
> > bits than version number to handle the compability issue.
> > For example, if we need introduce more options in the furture, we need:
> > 1.Add new feature bit to notice the option exist
> > 2.Allocate the field from reserved space
> >
> >>>>> +#endif /* _UAPI_LINUX_VIRTIO_RPMSG_H */
> >>>>>
> >> --
> >> Thanks
> >> Arnaud

2019-07-01 06:21:48

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

On Wed 05 Jun 00:33 PDT 2019, Arnaud Pouliquen wrote:

> Hi Bjorn,
>
> On 6/5/19 6:34 AM, Bjorn Andersson wrote:
> > On Thu 31 Jan 07:41 PST 2019, Xiang Xiao wrote:
> >
> >> Hi,
> >> This series enhance the buffer allocation by:
> >> 1.Support the different buffer number in rx/tx direction
> >> 2.Get the individual rx/tx buffer size from config space
> >>
> >> Here is the related OpenAMP change:
> >> https://github.com/OpenAMP/open-amp/pull/155
> >>
> >
> > This looks pretty reasonable, but can you confirm that it's possible to
> > use new firmware with an old Linux kernel when introducing this?
> >
> >
> > But ever since we discussed Loic's similar proposal earlier I've been
> > questioning if the fixed buffer size isn't just an artifact of how we
> > preallocate our buffers. The virtqueue seems to support arbitrary sizes
> > of buffers and I see that the receive function in OpenAMP has been fixed
> > to put back the buffer of the size that was received, rather than 512
> > bytes. So it seems like Linux would be able to send whatever size
> > messages to OpenAMP it would handle it.
> >
> > The question is if we could do the same in the other direction, perhaps
> > by letting the OpenAMP side do it's message allocation when it's
> > sending, rather than Linux pushing inbufs to be filled by the remote.
>
> IMHO, both could be useful and could be not correlated.
> On-the fly buffer allocation seems more efficient but needs an
> allocator.This can be a generic allocator (with a va to da) for system
> where large amount of memories are accessible from both side.
>
> Now what about system with small shared memory? In this case you have to
> deal with a limited/optimized memory chunk. To avoid memory
> fragmentation the allocator should have a pre-reserved buffers pool(so
> similar to existing implementation). This serie seems useful to optimize
> the size of the pre-reserved pool.
>

Having an implementation that uses small fixed size buffers seems very
reasonable and I'm in favour of making the message size configurable.

I would however prefer to have this implemented in a way where the
remote side should not be receiving messages in a way that's based on
the remote side's allocation parameters.


I don't think this series prevents the introduction of such isolation,
but it would render this code unnecessary.

Regards,
Bjorn

2023-10-24 08:10:03

by Arnaud POULIQUEN

[permalink] [raw]
Subject: RE: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

Hello Divin,

This development is currently on hold, but several people seem interested in it.
I suggest that you reply directly to the email thread to continue the discussion and address the remoteproc mailing list

Regards,
Arnaud

>From: Divin Raj <[email protected]>
>Sent: Monday, October 23, 2023 12:44 PM
>To: [email protected]; Xiang Xiao <[email protected]>; [email protected]; Ohad Ben Cohen <[email protected]>; Bjorn Andersson <[email protected]>; Arnaud >POULIQUEN <[email protected]>; xiang xiao <[email protected]>
>Cc: [email protected]; [email protected]
>Subject: Re: [PATCH 0/3] Enhance virtio rpmsg bus driver buffer allocation

>Hello all,
>I am reaching out with reference to the patch discussed here: https://lore.kernel.org/all/CAH2Cfb-sv3SAL8bcczC-Dc3_r58MYZCS7s7zGtn1Qfo3mmBqVg@mail.gmail.com/
>I've been keenly following the developments around enhancing buffer allocation strategies, especially those focused on dynamic buffer sizing and the considerations for systems under varying memory >constraints. This work is highly relevant to several projects I am involved in, and I am quite interested in its progression. May I kindly request an update on the current phase of these initiatives? >Additionally, I am eager to know if there would be an opportunity for me to contribute to enhancing the patch, possibly by working on improvements or assisting in verification processes.
>Furthermore, if there are any condensed resources, summaries, or specific threads that encapsulate recent advancements or discussions on this topic, I would be grateful to receive directions to them.
>I appreciate everyone's dedicated efforts and invaluable contributions to this area of development. Looking forward to the updates.
>Regards Divin
>IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not >disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ST Restricted