rpmsg: add physical transport layer support

Rpmsg Physical Transport Layer is a new rpmsg transport, it's a
common part for the physical communication based rpmsg transport
layers such as Rpmsg-SPI and Rpmsg-Uart.

It implements three common parts:
1. Implement the NuttX and OpenAMP rpmsg frameworks' ops and the
rpmsg name service;
2. The buffer management and provide some APIs to lower layer to use;

Signed-off-by: liaoao <liaoao@xiaomi.com>
This commit is contained in:
liaoao 2024-01-04 14:10:44 +08:00 committed by Xiang Xiao
parent 1e212981b9
commit 6d604ec487
6 changed files with 1119 additions and 0 deletions

View File

@ -27,6 +27,12 @@ if(CONFIG_RPMSG)
list(APPEND SRCS rpmsg_ping.c)
endif()
if(CONFIG_RPMSG_PORT)
list(APPEND SRCS rpmsg_port.c)
target_include_directories(drivers
PRIVATE ${NUTTX_DIR}/openamp/open-amp/lib)
endif()
if(CONFIG_RPMSG_VIRTIO)
list(APPEND SRCS rpmsg_virtio.c)
endif()

View File

@ -21,6 +21,12 @@ config RPMSG_PING
This is for debugging & profiling, create ping rpmsg
channel, user can use it to get send/recv speed & latency.
config RPMSG_PORT
bool
default n
---help---
Rpmsg port transport layer used for cross chip communication.
endif # RPMSG
config RPMSG_VIRTIO

View File

@ -28,6 +28,11 @@ ifeq ($(CONFIG_RPMSG_PING),y)
CSRCS += rpmsg_ping.c
endif
ifeq ($(CONFIG_RPMSG_PORT),y)
CSRCS += rpmsg_port.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)openamp$(DELIM)open-amp$(DELIM)lib
endif
ifeq ($(CONFIG_RPMSG_VIRTIO),y)
CSRCS += rpmsg_virtio.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)openamp$(DELIM)open-amp$(DELIM)lib

743
drivers/rpmsg/rpmsg_port.c Normal file
View File

@ -0,0 +1,743 @@
/****************************************************************************
* drivers/rpmsg/rpmsg_port.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <metal/atomic.h>
#include <metal/mutex.h>
#include <rpmsg/rpmsg_internal.h>
#include "rpmsg_port.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define RPMSG_PORT_BUF_TO_NODE(q,b) ((q)->node + ((FAR void *)(b) - (q)->buf) / (q)->len)
#define RPMSG_PORT_NODE_TO_BUF(q,n) ((q)->buf + (((n) - (q)->node)) * (q)->len)
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static FAR const char *rpmsg_port_get_cpuname(FAR struct rpmsg_s *rpmsg);
static int rpmsg_port_get_tx_buffer_size(FAR struct rpmsg_s *rpmsg);
static int rpmsg_port_get_rx_buffer_size(FAR struct rpmsg_s *rpmsg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct rpmsg_ops_s g_rpmsg_port_ops =
{
NULL,
NULL,
NULL,
NULL,
NULL,
rpmsg_port_get_cpuname,
rpmsg_port_get_tx_buffer_size,
rpmsg_port_get_rx_buffer_size,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: rpmsg_port_post
****************************************************************************/
static void rpmsg_port_post(FAR sem_t *sem)
{
int count = 0;
nxsem_get_value(sem, &count);
while (count++ <= 0)
{
nxsem_post(sem);
}
}
/****************************************************************************
* Name: rpmsg_port_add_node
****************************************************************************/
static void rpmsg_port_add_node(FAR struct rpmsg_port_list_s *list,
FAR struct list_node *node)
{
irqstate_t flags;
flags = spin_lock_irqsave(&list->lock);
list_add_tail(&list->head, node);
list->num++;
spin_unlock_irqrestore(&list->lock, flags);
}
/****************************************************************************
* Name: rpmsg_port_remove_node
****************************************************************************/
static FAR struct list_node *
rpmsg_port_remove_node(FAR struct rpmsg_port_list_s *list)
{
FAR struct list_node *node;
irqstate_t flags;
flags = spin_lock_irqsave(&list->lock);
node = list_remove_head(&list->head);
if (node != NULL)
{
list->num--;
}
spin_unlock_irqrestore(&list->lock, flags);
return node;
}
/****************************************************************************
* Name: rpmsg_port_destroy_queue
*
* Description:
* Free memory alloced by rpmsg_port_create_queue.
*
****************************************************************************/
static void rpmsg_port_destroy_queue(FAR struct rpmsg_port_queue_s *queue)
{
if (queue->alloced)
{
kmm_free(queue->buf);
}
kmm_free(queue->node);
nxsem_destroy(&queue->free.sem);
nxsem_destroy(&queue->ready.sem);
}
/****************************************************************************
* Name: rpmsg_port_create_queue
****************************************************************************/
static int rpmsg_port_create_queue(FAR struct rpmsg_port_queue_s *queue,
uint32_t count, uint32_t len,
FAR void *buf)
{
FAR struct list_node *node;
node = kmm_malloc(count * sizeof(struct list_node));
if (node == NULL)
{
return -ENOMEM;
}
queue->node = node;
/* Check if buffer space needed to be malloced internal. */
if (buf == NULL)
{
buf = kmm_malloc(count * len);
if (buf == NULL)
{
kmm_free(queue->node);
return -ENOMEM;
}
queue->alloced = true;
}
queue->len = len;
queue->buf = buf;
/* Init free list */
spin_lock_init(&queue->free.lock);
nxsem_init(&queue->free.sem, 0, 0);
list_initialize(&queue->free.head);
while (count--)
{
rpmsg_port_add_node(&queue->free, node);
node++;
}
/* Init ready list */
spin_lock_init(&queue->ready.lock);
nxsem_init(&queue->ready.sem, 0, 0);
list_initialize(&queue->ready.head);
return 0;
}
/****************************************************************************
* Name: rpmsg_port_create_queues
****************************************************************************/
static int
rpmsg_port_create_queues(FAR struct rpmsg_port_s *port,
FAR const struct rpmsg_port_config_s *cfg)
{
int ret;
ret = rpmsg_port_create_queue(&port->txq, cfg->txnum,
cfg->txlen, cfg->txbuf);
if (ret < 0)
{
return ret;
}
ret = rpmsg_port_create_queue(&port->rxq, cfg->rxnum,
cfg->rxlen, cfg->rxbuf);
if (ret < 0)
{
rpmsg_port_destroy_queue(&port->txq);
return ret;
}
return 0;
}
/****************************************************************************
* Name: rpmsg_port_destroy_queues
****************************************************************************/
static void rpmsg_port_destroy_queues(FAR struct rpmsg_port_s *port)
{
rpmsg_port_destroy_queue(&port->txq);
rpmsg_port_destroy_queue(&port->rxq);
}
/****************************************************************************
* Name: rpmsg_port_get_tx_payload_buffer
****************************************************************************/
static FAR void *
rpmsg_port_get_tx_payload_buffer(FAR struct rpmsg_device *rdev,
FAR uint32_t *len, int wait)
{
FAR struct rpmsg_port_s *port =
metal_container_of(rdev, struct rpmsg_port_s, rdev);
FAR struct rpmsg_port_header_s *hdr =
rpmsg_port_queue_get_available_buffer(&port->txq, wait);
if (hdr == NULL)
{
return NULL;
}
*len = hdr->len - sizeof(struct rpmsg_port_header_s) -
sizeof(struct rpmsg_hdr);
return RPMSG_LOCATE_DATA(hdr->buf);
}
/****************************************************************************
* Name: rpmsg_port_send_offchannel_nocopy
****************************************************************************/
static int rpmsg_port_send_offchannel_nocopy(FAR struct rpmsg_device *rdev,
uint32_t src, uint32_t dst,
FAR const void *data, int len)
{
FAR struct rpmsg_port_s *port =
metal_container_of(rdev, struct rpmsg_port_s, rdev);
FAR struct rpmsg_port_header_s *hdr;
FAR struct rpmsg_hdr *rp_hdr;
rp_hdr = RPMSG_LOCATE_HDR(data);
rp_hdr->dst = dst;
rp_hdr->src = src;
rp_hdr->len = len;
rp_hdr->reserved = 0;
rp_hdr->flags = 0;
hdr = metal_container_of(rp_hdr, struct rpmsg_port_header_s, buf);
hdr->len = sizeof(struct rpmsg_port_header_s) +
sizeof(struct rpmsg_hdr) + len;
rpmsg_port_queue_add_buffer(&port->txq, hdr);
port->ops->kick(port);
return len;
}
/****************************************************************************
* Name: rpmsg_port_send_offchannel_raw
****************************************************************************/
static int rpmsg_port_send_offchannel_raw(FAR struct rpmsg_device *rdev,
uint32_t src, uint32_t dst,
FAR const void *data,
int len, int wait)
{
uint32_t buflen;
FAR void *buf;
buf = rpmsg_port_get_tx_payload_buffer(rdev, &buflen, wait);
if (buf == NULL)
{
return RPMSG_ERR_NO_BUFF;
}
RPMSG_ASSERT(len <= buflen, "Send size larger than buffer size\n");
memcpy(buf, data, len);
return rpmsg_port_send_offchannel_nocopy(rdev, src, dst, buf, len);
}
/****************************************************************************
* Name: rpmsg_port_hold_rx_buffer
****************************************************************************/
static void rpmsg_port_hold_rx_buffer(FAR struct rpmsg_device *rdev,
FAR void *rxbuf)
{
FAR struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(rxbuf);
atomic_fetch_add(&rp_hdr->reserved, 1 << RPMSG_BUF_HELD_SHIFT);
}
/****************************************************************************
* Name: rpmsg_port_release_rx_buffer
****************************************************************************/
static void rpmsg_port_release_rx_buffer(FAR struct rpmsg_device *rdev,
FAR void *rxbuf)
{
FAR struct rpmsg_port_s *port =
metal_container_of(rdev, struct rpmsg_port_s, rdev);
FAR struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(rxbuf);
FAR struct rpmsg_port_header_s *hdr =
metal_container_of(rp_hdr, struct rpmsg_port_header_s, buf);
uint32_t reserved =
atomic_fetch_sub(&rp_hdr->reserved, 1 << RPMSG_BUF_HELD_SHIFT);
if ((reserved & RPMSG_BUF_HELD_MASK) == (1 << RPMSG_BUF_HELD_SHIFT))
{
rpmsg_port_queue_return_buffer(&port->rxq, hdr);
}
}
/****************************************************************************
* Name: rpmsg_port_release_tx_buffer
****************************************************************************/
static int rpmsg_port_release_tx_buffer(FAR struct rpmsg_device *rdev,
FAR void *txbuf)
{
FAR struct rpmsg_port_s *port =
metal_container_of(rdev, struct rpmsg_port_s, rdev);
FAR struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(txbuf);
FAR struct rpmsg_port_header_s *hdr =
metal_container_of(rp_hdr, struct rpmsg_port_header_s, buf);
rpmsg_port_queue_return_buffer(&port->txq, hdr);
return RPMSG_SUCCESS;
}
/****************************************************************************
* Name: rpmsg_port_rx_callback
****************************************************************************/
static void rpmsg_port_rx_callback(FAR struct rpmsg_port_s *port,
FAR struct rpmsg_port_header_s *hdr)
{
FAR struct rpmsg_device *rdev = &port->rdev;
FAR struct rpmsg_hdr *rp_hdr = (FAR struct rpmsg_hdr *)hdr->buf;
FAR void *data = RPMSG_LOCATE_DATA(rp_hdr);
FAR struct rpmsg_endpoint *ept;
int status;
metal_mutex_acquire(&rdev->lock);
ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst);
rpmsg_ept_incref(ept);
metal_mutex_release(&rdev->lock);
rpmsg_port_hold_rx_buffer(rdev, data);
if (ept != NULL)
{
if (ept->dest_addr == RPMSG_ADDR_ANY)
{
ept->dest_addr = rp_hdr->src;
}
status = ept->cb(ept, data, rp_hdr->len, rp_hdr->src, ept->priv);
if (status < 0)
{
RPMSG_ASSERT(0, "unexpected callback status\n");
}
}
rpmsg_port_release_rx_buffer(rdev, data);
metal_mutex_acquire(&rdev->lock);
rpmsg_ept_decref(ept);
metal_mutex_release(&rdev->lock);
}
/****************************************************************************
* Name: rpmsg_port_ns_callback
****************************************************************************/
static int rpmsg_port_ns_callback(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len, uint32_t src,
FAR void *priv)
{
FAR struct rpmsg_device *rdev = ept->rdev;
FAR struct rpmsg_ns_msg *msg = data;
FAR const char *name = msg->name;
uint32_t dest = msg->addr;
bool decref = false;
if (len != sizeof(*msg))
{
return RPMSG_SUCCESS;
}
metal_mutex_acquire(&rdev->lock);
ept = rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest);
if (msg->flags == RPMSG_NS_DESTROY)
{
if (ept != NULL)
{
ept->dest_addr = RPMSG_ADDR_ANY;
if (ept->release_cb != NULL)
{
rpmsg_ept_incref(ept);
decref = true;
}
}
metal_mutex_release(&rdev->lock);
if (ept != NULL && ept->ns_unbind_cb != NULL)
{
ept->ns_unbind_cb(ept);
}
if (rdev->ns_unbind_cb != NULL)
{
rdev->ns_unbind_cb(rdev, name, dest);
}
if (decref)
{
metal_mutex_acquire(&rdev->lock);
rpmsg_ept_decref(ept);
metal_mutex_release(&rdev->lock);
}
}
else if (msg->flags == RPMSG_NS_CREATE)
{
if (ept == NULL)
{
metal_mutex_release(&rdev->lock);
if (rdev->ns_bind_cb != NULL)
{
rdev->ns_bind_cb(rdev, name, dest);
}
}
else if (ept->dest_addr == RPMSG_ADDR_ANY)
{
ept->dest_addr = dest;
metal_mutex_release(&rdev->lock);
if (ept->name[0] && rdev->support_ack)
{
rpmsg_send_ns_message(ept, RPMSG_NS_CREATE_ACK);
}
/* Notify application that the endpoint has been bound */
if (ept->ns_bound_cb != NULL)
{
ept->ns_bound_cb(ept);
}
}
else
{
metal_mutex_release(&rdev->lock);
}
}
else
{
/* RPMSG_NS_CREATE_ACK */
if (ept != NULL && ept->dest_addr == RPMSG_ADDR_ANY)
{
ept->dest_addr = dest;
metal_mutex_release(&rdev->lock);
if (ept->ns_bound_cb != NULL)
{
ept->ns_bound_cb(ept);
}
}
else
{
metal_mutex_release(&rdev->lock);
}
}
return RPMSG_SUCCESS;
}
/****************************************************************************
* Name: rpmsg_port_get_cpuname
****************************************************************************/
static FAR const char *rpmsg_port_get_cpuname(FAR struct rpmsg_s *rpmsg)
{
FAR struct rpmsg_port_s *port = (FAR struct rpmsg_port_s *)rpmsg;
return port->cpuname;
}
/****************************************************************************
* Name: rpmsg_port_get_tx_buffer_size
****************************************************************************/
static int rpmsg_port_get_tx_buffer_size(FAR struct rpmsg_s *rpmsg)
{
FAR struct rpmsg_port_s *port = (FAR struct rpmsg_port_s *)rpmsg;
return port->txq.len - sizeof(struct rpmsg_port_header_s) -
sizeof(struct rpmsg_hdr);
}
/****************************************************************************
* Name: rpmsg_port_get_rx_buffer_size
****************************************************************************/
static int rpmsg_port_get_rx_buffer_size(FAR struct rpmsg_s *rpmsg)
{
FAR struct rpmsg_port_s *port = (FAR struct rpmsg_port_s *)rpmsg;
return port->rxq.len - sizeof(struct rpmsg_port_header_s) -
sizeof(struct rpmsg_hdr);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rpmsg_port_initialize
****************************************************************************/
int rpmsg_port_initialize(FAR struct rpmsg_port_s *port,
FAR const struct rpmsg_port_config_s *cfg,
FAR const struct rpmsg_port_ops_s *ops)
{
FAR struct rpmsg_device *rdev;
int ret;
if (port == NULL || cfg == NULL || ops == NULL)
{
return -EINVAL;
}
ret = rpmsg_port_create_queues(port, cfg);
if (ret < 0)
{
return ret;
}
port->ops = ops;
strlcpy(port->cpuname, cfg->remotecpu, RPMSG_NAME_SIZE);
rdev = &port->rdev;
memset(rdev, 0, sizeof(*rdev));
metal_mutex_init(&rdev->lock);
rdev->ns_bind_cb = rpmsg_ns_bind;
rdev->ns_unbind_cb = rpmsg_ns_unbind;
rdev->ops.send_offchannel_raw = rpmsg_port_send_offchannel_raw;
rdev->ops.hold_rx_buffer = rpmsg_port_hold_rx_buffer;
rdev->ops.release_rx_buffer = rpmsg_port_release_rx_buffer;
rdev->ops.get_tx_payload_buffer = rpmsg_port_get_tx_payload_buffer;
rdev->ops.send_offchannel_nocopy = rpmsg_port_send_offchannel_nocopy;
rdev->ops.release_tx_buffer = rpmsg_port_release_tx_buffer;
metal_list_init(&rdev->endpoints);
rdev->support_ack = true;
rdev->support_ns = true;
rpmsg_register_endpoint(rdev, &rdev->ns_ept, "NS", RPMSG_NS_EPT_ADDR,
RPMSG_NS_EPT_ADDR, rpmsg_port_ns_callback, NULL);
port->ops->register_callback(port, rpmsg_port_rx_callback);
return 0;
}
/****************************************************************************
* Name: rpmsg_port_uninitialize
****************************************************************************/
void rpmsg_port_uninitialize(FAR struct rpmsg_port_s *port)
{
FAR struct rpmsg_device *rdev = &port->rdev;
FAR struct metal_list *node;
FAR struct rpmsg_endpoint *ept;
while (!metal_list_is_empty(&rdev->endpoints))
{
node = rdev->endpoints.next;
ept = metal_container_of(node, struct rpmsg_endpoint, node);
rpmsg_destroy_ept(ept);
if (ept->ns_unbind_cb)
{
ept->ns_unbind_cb(ept);
}
}
metal_mutex_deinit(&rdev->lock);
rpmsg_port_destroy_queues(port);
}
/****************************************************************************
* Name: rpmsg_port_queue_get_available_buffer
****************************************************************************/
FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_available_buffer(FAR struct rpmsg_port_queue_s *queue,
bool wait)
{
FAR struct list_node *node;
FAR struct rpmsg_port_header_s *hdr;
for (; ; )
{
node = rpmsg_port_remove_node(&queue->free);
if (node)
{
hdr = RPMSG_PORT_NODE_TO_BUF(queue, node);
hdr->len = queue->len;
return hdr;
}
else if (!wait)
{
return NULL;
}
nxsem_wait_uninterruptible(&queue->free.sem);
}
}
/****************************************************************************
* Name: rpmsg_port_queue_return_buffer
****************************************************************************/
FAR void rpmsg_port_queue_return_buffer(FAR struct rpmsg_port_queue_s *queue,
FAR struct rpmsg_port_header_s *hdr)
{
FAR struct list_node *node = RPMSG_PORT_BUF_TO_NODE(queue, hdr);
rpmsg_port_add_node(&queue->free, node);
rpmsg_port_post(&queue->free.sem);
}
/****************************************************************************
* Name: rpmsg_port_queue_get_buffer
****************************************************************************/
FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_buffer(FAR struct rpmsg_port_queue_s *queue, bool wait)
{
FAR struct list_node *node;
for (; ; )
{
node = rpmsg_port_remove_node(&queue->ready);
if (node)
{
return RPMSG_PORT_NODE_TO_BUF(queue, node);
}
else if (!wait)
{
return NULL;
}
nxsem_wait_uninterruptible(&queue->ready.sem);
}
}
/****************************************************************************
* Name: rpmsg_port_queue_add_buffer
****************************************************************************/
void rpmsg_port_queue_add_buffer(FAR struct rpmsg_port_queue_s *queue,
FAR struct rpmsg_port_header_s *hdr)
{
FAR struct list_node *node = RPMSG_PORT_BUF_TO_NODE(queue, hdr);
rpmsg_port_add_node(&queue->ready, node);
rpmsg_port_post(&queue->ready.sem);
}
/****************************************************************************
* Name: rpmsg_port_queue_navail
****************************************************************************/
uint32_t rpmsg_port_queue_navail(FAR struct rpmsg_port_queue_s *queue)
{
return atomic_load(&queue->free.num);
}
/****************************************************************************
* Name: rpmsg_port_register
****************************************************************************/
int rpmsg_port_register(FAR struct rpmsg_port_s *port)
{
char name[64];
int ret;
snprintf(name, sizeof(name), "/dev/rpmsg/%s", port->cpuname);
ret = rpmsg_register(name, &port->rpmsg, &g_rpmsg_port_ops);
if (ret < 0)
{
return ret;
}
rpmsg_device_created(&port->rpmsg);
return ret;
}
/****************************************************************************
* Name: rpmsg_port_unregister
****************************************************************************/
void rpmsg_port_unregister(FAR struct rpmsg_port_s *port)
{
char name[64];
rpmsg_device_destory(&port->rpmsg);
snprintf(name, sizeof(name), "/dev/rpmsg/%s", port->cpuname);
rpmsg_unregister(name, &port->rpmsg);
}

305
drivers/rpmsg/rpmsg_port.h Normal file
View File

@ -0,0 +1,305 @@
/****************************************************************************
* drivers/rpmsg/rpmsg_port.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __DRIVERS_RPMSG_RPMSG_PORT_H
#define __DRIVERS_RPMSG_RPMSG_PORT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdbool.h>
#include <nuttx/list.h>
#include <nuttx/spinlock.h>
#include <nuttx/semaphore.h>
#include <nuttx/rpmsg/rpmsg.h>
#include <nuttx/rpmsg/rpmsg_port.h>
/****************************************************************************
* Public Types
****************************************************************************/
/* This header is for physical layer's use */
begin_packed_struct struct rpmsg_port_header_s
{
uint16_t crc; /* CRC of current port data frame */
uint16_t cmd; /* Reserved for uart/spi port driver */
uint32_t avail; /* Available rx buffer of peer side */
uint32_t len; /* Data frame length */
uint32_t seq; /* Sequence number of current data frame */
uint8_t buf[0]; /* Payload buffer */
} end_packed_struct;
struct rpmsg_port_list_s
{
uint32_t num; /* Number of buffers */
sem_t sem; /* Used to wait for buffer */
spinlock_t lock; /* List lock */
struct list_node head; /* List head */
};
struct rpmsg_port_queue_s
{
/* Indicate buffers current queue managed is dynamic alloced */
bool alloced;
/* Buffer array's base address of current queue managed */
FAR void *buf;
/* Node related to buffer for buffer management */
FAR struct list_node *node;
/* Length of buffers current queue managed */
uint32_t len;
/* Free list of buffers which have not been occupied data yet */
struct rpmsg_port_list_s free;
/* Ready list of buffers which have been occupied data already */
struct rpmsg_port_list_s ready;
};
struct rpmsg_port_s;
typedef void (*rpmsg_port_rx_cb_t)(FAR struct rpmsg_port_s *port,
FAR struct rpmsg_port_header_s *hdr);
struct rpmsg_port_ops_s
{
/* Kick driver there is buffer to be sent of the tx queue */
CODE void (*kick)(FAR struct rpmsg_port_s *port);
/* Register callback function which should be invoked when there is
* date received to the rx queue by driver
*/
CODE void (*register_callback)(FAR struct rpmsg_port_s *port,
rpmsg_port_rx_cb_t callback);
};
struct rpmsg_port_s
{
struct rpmsg_s rpmsg;
struct rpmsg_device rdev; /* Rpmsg device object */
struct rpmsg_port_queue_s txq; /* Port tx queue */
struct rpmsg_port_queue_s rxq; /* Port rx queue */
/* Remote cpu name of this port connected to */
char cpuname[RPMSG_NAME_SIZE];
/* Ops need implemented by drivers under port layer */
const FAR struct rpmsg_port_ops_s *ops;
};
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: rpmsg_port_queue_get_available_buffer
*
* Description:
* Get buffer from free list of the queue.
*
* Input Parameters:
* queue - The queue to be getten from.
* wait - If wait or not when there is no available buffer of the queue.
*
* Returned Value:
* A struct rpmsg_port_header_s's pointer on success or NULL on failure.
* The len of struct rpmsg_port_header_s indicates the sum of struct
* rpmsg_port_header_s's size and the data size can be used.
*
****************************************************************************/
FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_available_buffer(FAR struct rpmsg_port_queue_s *queue,
bool wait);
/****************************************************************************
* Name: rpmsg_port_queue_return_buffer
*
* Description:
* Return buffer to free list of the queue.
*
* Input Parameters:
* queue - The queue to be returned to.
* hdr - Pointer to the struct rpmsg_port_header_s to be returned.
*
* Returned Value:
* No return value.
*
****************************************************************************/
void rpmsg_port_queue_return_buffer(FAR struct rpmsg_port_queue_s *queue,
FAR struct rpmsg_port_header_s *hdr);
/****************************************************************************
* Name: rpmsg_port_queue_get_buffer
*
* Description:
* Get buffer from ready list of the queue.
*
* Input Parameters:
* queue - The queue to be getten from.
* wait - If wait or not when there is no used buffer of the queue.
*
* Returned Value:
* A struct rpmsg_port_header_s's pointer on success or NULL on failure.
* The len of struct rpmsg_port_header_s indicates the sum of struct
* rpmsg_port_header_s's size and the data size has be used.
*
****************************************************************************/
FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_buffer(FAR struct rpmsg_port_queue_s *queue,
bool wait);
/****************************************************************************
* Name: rpmsg_port_queue_add_buffer
*
* Description:
* Add buffer to ready list of the queue.
*
* Input Parameters:
* queue - The queue to be added to.
* hdr - Pointer to the struct rpmsg_port_header_s to be added. The
* length of it must be set before this function invoked.
*
* Returned Value:
* No return value.
*
****************************************************************************/
void rpmsg_port_queue_add_buffer(FAR struct rpmsg_port_queue_s *queue,
FAR struct rpmsg_port_header_s *hdr);
/****************************************************************************
* Name: rpmsg_port_queue_navail
*
* Description:
* Get available buffer number of free list of the queue.
*
* Input Parameters:
* queue - The queue is to be calculated.
*
* Returned Value:
* Number of available buffers.
*
****************************************************************************/
uint32_t rpmsg_port_queue_navail(FAR struct rpmsg_port_queue_s *queue);
/****************************************************************************
* Name: rpmsg_port_initialize
*
* Description:
* Init port layer by port's configuration. rpmsg port layer creates and
* manages queues used for communication of two cpus.
*
* Input Parameters:
* port - The port to be inited.
* cfg - Port configuration.
* ops - Operation implemented by drivers under port layer.
*
* Returned Value:
* Zero on success or an negative value on failure.
*
****************************************************************************/
int rpmsg_port_initialize(FAR struct rpmsg_port_s *port,
FAR const struct rpmsg_port_config_s *cfg,
FAR const struct rpmsg_port_ops_s *ops);
/****************************************************************************
* Name: rpmsg_port_uninitialize
*
* Description:
* uninit rpmsg port.
*
* Input Parameters:
* port - The port to be uninited.
*
* Returned Value:
* No return value.
*
****************************************************************************/
void rpmsg_port_uninitialize(FAR struct rpmsg_port_s *port);
/****************************************************************************
* Name: rpmsg_port_register
*
* Description:
* Invoked to create a rpmsg character device when a connection between
* two cpus has established.
*
* Input Parameters:
* port - The port has established a connection.
*
* Returned Value:
* Zero on success or an negative value on failure.
*
****************************************************************************/
int rpmsg_port_register(FAR struct rpmsg_port_s *port);
/****************************************************************************
* Name: rpmsg_port_unregister
*
* Description:
* Invoked to unregister the rpmsg character device.
*
* Input Parameters:
* port - The port has established a connection.
*
* Returned Value:
* No return value.
*
****************************************************************************/
void rpmsg_port_unregister(FAR struct rpmsg_port_s *port);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif
#endif /* __DRIVERS_RPMSG_RPMSG_PORT_H */

View File

@ -0,0 +1,54 @@
/****************************************************************************
* include/nuttx/rpmsg/rpmsg_port.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_RPMSG_RPMSG_PORT_H
#define __INCLUDE_NUTTX_RPMSG_RPMSG_PORT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#ifdef CONFIG_RPMSG_PORT
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct rpmsg_port_config_s
{
FAR const char *remotecpu;
uint32_t txnum; /* Number of tx buffer. */
uint32_t rxnum; /* Number of rx buffer. */
uint32_t txlen; /* Length of a single tx buffer. */
uint32_t rxlen; /* Length of a single rx buffer. */
/* Pointer to whole tx/rx buffer, if it was null, transport layer will
* alloc internal.
*/
FAR void *txbuf;
FAR void *rxbuf;
};
#endif /* CONFIG_RPMSG_PORT */
#endif /* __INCLUDE_NUTTX_RPMSG_RPMSG_PORT_H */