mirror of
https://github.com/OpenAMP/open-amp.git
synced 2026-10-02 18:23:21 +08:00
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:
committed by
Wendy Liang
parent
3d6d92cc95
commit
b16ca550f1
File diff suppressed because it is too large
Load Diff
@@ -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);} \
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user