Adding RPMsg Extension layer implementing zero-copy send and receive.

Signed-off-by: Marek Novak <marek.novak@nxp.com>
Signed-off-by: Wendy Liang <jliang@xilinx.com>
This commit is contained in:
Marek Novak (NXA17138)
2016-10-14 21:39:20 -07:00
committed by Wendy Liang
parent 3d6d92cc95
commit b16ca550f1
6 changed files with 365 additions and 6 deletions
File diff suppressed because it is too large Load Diff
+4
View File
@@ -79,6 +79,10 @@
#define RPMSG_ERR_DEV_INIT (RPMSG_ERROR_BASE - 7)
#define RPMSG_ERR_DEV_ADDR (RPMSG_ERROR_BASE - 8)
/* Zero-Copy extension macros */
#define RPMSG_HDR_FROM_BUF(buf) (struct rpmsg_hdr *)((char*)buf - \
sizeof(struct rpmsg_hdr))
#if (RPMSG_DEBUG == true)
#define RPMSG_ASSERT(_exp, _msg) do{ \
if (!(_exp)){ openamp_print("%s - "_msg, __func__); while(1);} \
+3 -1
View File
@@ -208,7 +208,7 @@ int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
struct metal_sg *sg, int writable,
boolean has_next);
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len);
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t *idx);
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx,
uint32_t * len);
@@ -230,4 +230,6 @@ void virtqueue_notification(struct virtqueue *vq);
uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
#endif /* VIRTQUEUE_H_ */
+140
View File
@@ -57,6 +57,7 @@
#include <string.h>
#include "openamp/rpmsg.h"
#include "metal/sys.h"
#include "metal/cache.h"
/**
* rpmsg_init
@@ -193,6 +194,7 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, uint32_t src,
rp_hdr->dst = dst;
rp_hdr->src = src;
rp_hdr->len = size;
rp_hdr->reserved = 0;
/* Copy data to rpmsg buffer. */
if (rdev->proc->sh_buff.io->mem_flags & METAL_IO_MAPPED)
@@ -254,6 +256,144 @@ int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl)
return length;
}
void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
{
struct rpmsg_hdr *rp_hdr = NULL;
if (!rpdev || !rxbuf)
return;
rp_hdr = RPMSG_HDR_FROM_BUF(rxbuf);
/* set held status to keep buffer */
rp_hdr->reserved |= RPMSG_BUF_HELD;
}
void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
{
struct rpmsg_hdr *hdr;
struct remote_device *rdev;
struct rpmsg_hdr_reserved * reserved = NULL;
struct metal_io_region *io;
unsigned int len;
if (!rpdev || !rxbuf)
return;
rdev = rpdev->rdev;
hdr = RPMSG_HDR_FROM_BUF(rxbuf);
/* Get the pointer to the reserved field that contains buffer size
* and the index */
reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
hdr->reserved &= (~RPMSG_BUF_HELD);
len = (unsigned int)virtqueue_get_buffer_length(rdev->rvq,
reserved->idx);
io = rdev->proc->sh_buff.io;
if (io) {
if (! (io->mem_flags & METAL_UNCACHED))
metal_cache_flush(rxbuf, len);
}
metal_mutex_acquire(&rdev->lock);
/* Return used buffer, with total length
(header length + buffer size). */
rpmsg_return_buffer(rdev, hdr, (unsigned long)len, reserved->idx);
metal_mutex_release(&rdev->lock);
}
void *rpmsg_get_tx_payload_buffer(struct rpmsg_channel *rpdev, uint32_t *size,
int wait)
{
struct rpmsg_hdr *hdr;
struct remote_device *rdev;
struct rpmsg_hdr_reserved *reserved;
unsigned short idx;
unsigned long buff_len, tick_count = 0;
if (!rpdev || !size)
return NULL;
rdev = rpdev->rdev;
metal_mutex_acquire(&rdev->lock);
/* Get tx buffer from vring */
hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
metal_mutex_release(&rdev->lock);
if (!hdr && !wait) {
return NULL;
} else {
while (!hdr) {
/*
* Wait parameter is true - pool the buffer for
* 15 secs as defined by the APIs.
*/
env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
metal_mutex_acquire(&rdev->lock);
hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
metal_mutex_release(&rdev->lock);
tick_count += RPMSG_TICKS_PER_INTERVAL;
if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) {
return NULL;
}
}
/* Store the index into the reserved field to be used when sending */
reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
reserved->idx = (uint16_t)idx;
/* Actual data buffer size is vring buffer size minus rpmsg header length */
*size = (uint32_t)(buff_len - sizeof(struct rpmsg_hdr));
return (void *)RPMSG_LOCATE_DATA(hdr);
}
}
int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, uint32_t src,
uint32_t dst, void *txbuf, int len)
{
struct rpmsg_hdr *hdr;
struct remote_device *rdev;
struct rpmsg_hdr_reserved * reserved = NULL;
int status;
if (!rpdev || !txbuf)
return RPMSG_ERR_PARAM;
rdev = rpdev->rdev;
hdr = RPMSG_HDR_FROM_BUF(txbuf);
/* Initialize RPMSG header. */
hdr->dst = dst;
hdr->src = src;
hdr->len = len;
hdr->flags = 0;
hdr->reserved &= (~RPMSG_BUF_HELD);
/* Get the pointer to the reserved field that contains buffer size and
* the index */
reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
metal_mutex_acquire(&rdev->lock);
status = rpmsg_enqueue_buffer(rdev, hdr,
(unsigned long)virtqueue_get_buffer_length(
rdev->tvq, reserved->idx),
reserved->idx);
if (status == RPMSG_SUCCESS) {
/* Let the other side know that there is a job to process. */
virtqueue_kick(rdev->tvq);
}
metal_mutex_release(&rdev->lock);
return status;
}
/**
* rpmsg_create_ept
*
+15 -4
View File
@@ -410,7 +410,7 @@ void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len,
void *data;
if (rdev->role == RPMSG_REMOTE) {
data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len);
data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len, idx);
if (data == RPMSG_NULL) {
data = sh_mem_get_buffer(rdev->mem_pool);
*len = RPMSG_BUFFER_SIZE;
@@ -441,7 +441,7 @@ void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
void *data;
if (rdev->role == RPMSG_REMOTE) {
data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len);
data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len, idx);
} else {
data =
virtqueue_get_available_buffer(rdev->rvq, idx,
@@ -456,6 +456,7 @@ void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
(unsigned int)(*len));
}
}
return data;
}
@@ -543,6 +544,7 @@ void rpmsg_rx_callback(struct virtqueue *vq)
struct rpmsg_channel *rp_chnl;
struct rpmsg_endpoint *rp_ept;
struct rpmsg_hdr *rp_hdr;
struct rpmsg_hdr_reserved *reserved;
struct metal_list *node;
unsigned long len;
unsigned short idx;
@@ -604,8 +606,17 @@ void rpmsg_rx_callback(struct virtqueue *vq)
metal_mutex_acquire(&rdev->lock);
/* Return used buffers. */
rpmsg_return_buffer(rdev, rp_hdr, len, idx);
/* Check whether callback wants to hold buffer */
if (rp_hdr->reserved & RPMSG_BUF_HELD)
{
/* 'rp_hdr->reserved' field is now used as storage for
* 'idx' to release buffer later */
reserved = (struct rpmsg_hdr_reserved*)&rp_hdr->reserved;
reserved->idx = (uint16_t)idx;
} else {
/* Return used buffers. */
rpmsg_return_buffer(rdev, rp_hdr, len, idx);
}
rp_hdr =
(struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
+9 -1
View File
@@ -266,10 +266,11 @@ int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
*
* @param vq - Pointer to VirtIO queue control block
* @param len - Length of conumed buffer
* @param idx - index of the buffer
*
* @return - Pointer to used buffer
*/
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len)
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t * idx)
{
struct vring_used_elem *uep;
void *cookie;
@@ -294,11 +295,18 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len)
cookie = vq->vq_descx[desc_idx].cookie;
vq->vq_descx[desc_idx].cookie = VQ_NULL;
if (idx != VQ_NULL)
*idx = used_idx;
VQUEUE_IDLE(vq);
return (cookie);
}
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx)
{
return vq->vq_ring.desc[idx].len;
}
/**
* virtqueue_free - Frees VirtIO queue resources
*