mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 22:20:01 +08:00
0dccc8ba21
debug.h is a NuttX-specific, non-POSIX header. Placing it in the top-level include/ directory creates naming conflicts with external projects that define their own debug.h. This commit moves the canonical header to include/nuttx/debug.h, following the NuttX convention for non-POSIX/non-standard headers, and updates all in-tree references. A backward-compatibility shim is left at include/debug.h that emits a deprecation #warning and re-includes <nuttx/debug.h>, allowing out-of-tree code to continue building while migrating. Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
553 lines
16 KiB
C
553 lines
16 KiB
C
/****************************************************************************
|
|
* drivers/rpmsg/rpmsg_router_hub.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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 <nuttx/config.h>
|
|
|
|
#include <nuttx/debug.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <sys/param.h>
|
|
|
|
#include <nuttx/mutex.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/wqueue.h>
|
|
|
|
#include "rpmsg_router.h"
|
|
|
|
/****************************************************************************
|
|
* Rpmsg-router Model:
|
|
*
|
|
* +------+ +------+ +------+
|
|
* | edge |<----->| hub |<----->| edge |
|
|
* +------+ +------+ +------+
|
|
*
|
|
* Description:
|
|
* edge CPUs (edge) are physically linked to the central router cpu (hub),
|
|
* edge CPUs' communication reply on hub cpu message forwarding.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct rpmsg_router_hub_s
|
|
{
|
|
struct rpmsg_endpoint ept[2];
|
|
struct work_s work;
|
|
char cpuname[2][RPMSG_ROUTER_CPUNAME_LEN];
|
|
mutex_t lock;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_cb
|
|
*
|
|
* Description:
|
|
* This is the callback function for router core.
|
|
* It will receive data from source edge core by ept(r:peer_cpu:name),
|
|
* and send data to peer edge's endpoint.
|
|
*
|
|
* Parameters:
|
|
* ept - endpoint for communicating with edge core (r:peer_cpu:name)
|
|
* data - received data
|
|
* len - received data length
|
|
* src - source address
|
|
* priv - save peer edge core rpmsg_endpoint (r:src_cpu:name)
|
|
*
|
|
* Returned Values:
|
|
* Returns number of bytes it has sent or negative error value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int rpmsg_router_hub_cb(FAR struct rpmsg_endpoint *ept,
|
|
FAR void *data, size_t len,
|
|
uint32_t src, FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_endpoint *peer_ept = priv;
|
|
|
|
/* Retransmit data to dest edge core */
|
|
|
|
if (peer_ept == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
rpmsg_send_offchannel_raw(peer_ept, peer_ept->addr,
|
|
peer_ept->dest_addr, data, len, true);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_ept_release
|
|
*
|
|
* Description:
|
|
* This is the release endpoint callback function for router core.
|
|
*
|
|
* Parameters:
|
|
* ept - rpmsg_endpoint for communicating with edge core (r:cpu:name)
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_hub_ept_release(FAR struct rpmsg_endpoint *ept)
|
|
{
|
|
kmm_free(ept);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_unbind
|
|
*
|
|
* Description:
|
|
* This is the unbind callback function for router core.
|
|
* it will send NS_DESTROY to peer endpoint and destroy source endpoint.
|
|
*
|
|
* Parameters:
|
|
* ept - rpmsg_endpoint for communicating with edge core (r:cpu:name)
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_hub_unbind(FAR struct rpmsg_endpoint *ept)
|
|
{
|
|
FAR struct rpmsg_endpoint *peer_ept = ept->priv;
|
|
FAR struct rpmsg_device *rdev = peer_ept->rdev;
|
|
|
|
rpmsg_destroy_ept(ept);
|
|
if (peer_ept->cb)
|
|
{
|
|
rpmsg_send_ns_message(peer_ept, RPMSG_NS_DESTROY);
|
|
metal_mutex_acquire(&rdev->lock);
|
|
rpmsg_ept_decref(peer_ept);
|
|
metal_mutex_release(&rdev->lock);
|
|
}
|
|
else
|
|
{
|
|
kmm_free(peer_ept);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_bound
|
|
*
|
|
* Description:
|
|
* This is the bound callback function for router core.
|
|
* It will create endpoint to source edge after peer's endpoint is bound.
|
|
*
|
|
* Parameters:
|
|
* ept - peer's endpoint for communicating with edge core (r:src_cpu:name)
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_hub_bound(FAR struct rpmsg_endpoint *ept)
|
|
{
|
|
FAR struct rpmsg_endpoint *src_ept = ept->priv;
|
|
FAR struct rpmsg_device *src_rdev = src_ept->rdev;
|
|
FAR struct rpmsg_device *rdev = ept->rdev;
|
|
int ret;
|
|
|
|
/* Create endpoint (r:peer_cpu:name) and send ACK to source edge core */
|
|
|
|
ret = rpmsg_create_ept(src_ept, src_ept->rdev, src_ept->name,
|
|
RPMSG_ADDR_ANY, src_ept->dest_addr,
|
|
rpmsg_router_hub_cb, rpmsg_router_hub_unbind);
|
|
DEBUGASSERT(ret == RPMSG_SUCCESS);
|
|
|
|
metal_mutex_acquire(&rdev->lock);
|
|
rpmsg_ept_incref(ept);
|
|
metal_mutex_release(&rdev->lock);
|
|
|
|
metal_mutex_acquire(&src_rdev->lock);
|
|
rpmsg_ept_incref(src_ept);
|
|
metal_mutex_release(&src_rdev->lock);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_match
|
|
*
|
|
* Description:
|
|
* This function is used to match the router core device.
|
|
* rpmsg_router_hub_bind will be called if the device is matched.
|
|
*
|
|
* Parameters:
|
|
* rdev - real rpmsg device
|
|
* priv - rpmsg router hub for router core
|
|
* name - endpoint name (r:peer_cpu:name)
|
|
* dest - destination address
|
|
*
|
|
* Returned Values:
|
|
* true on success; false on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static bool rpmsg_router_hub_match(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv, FAR const char *name,
|
|
uint32_t dest)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = priv;
|
|
int i;
|
|
|
|
if (strncmp(name, RPMSG_ROUTER_NAME_PREFIX, RPMSG_ROUTER_NAME_PREFIX_LEN))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* Must match both source edge CPU and dest edge CPU simultaneously */
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (strcmp(rpmsg_get_cpuname(rdev), hub->cpuname[i]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (strncmp(name + RPMSG_ROUTER_NAME_PREFIX_LEN,
|
|
hub->cpuname[1 - i], strlen(hub->cpuname[1 - i])))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return i < 2;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_bind
|
|
*
|
|
* Description:
|
|
* This function is used to bind the router core device.
|
|
* It will try to create endpoint (r:src_cpu:name) to peer cpu.
|
|
* The source endpoint information will be saved in the private field of
|
|
* the peer endpoint.
|
|
*
|
|
* Parameters:
|
|
* rdev - real rpmsg device
|
|
* priv - rpmsg router hub for router core
|
|
* name - source edge core endpoint name (r:peer_cpu:name)
|
|
* dest - destination address
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_hub_bind(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv, FAR const char *name,
|
|
uint32_t dest)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = priv;
|
|
FAR struct rpmsg_endpoint *src_ept;
|
|
FAR struct rpmsg_endpoint *peer_ept;
|
|
FAR struct rpmsg_device *peer_rdev;
|
|
char peer_name[RPMSG_NAME_SIZE];
|
|
int ret;
|
|
int i;
|
|
|
|
nxmutex_lock(&hub->lock);
|
|
metal_mutex_acquire(&rdev->lock);
|
|
if (rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest))
|
|
{
|
|
metal_mutex_release(&rdev->lock);
|
|
nxmutex_unlock(&hub->lock);
|
|
return;
|
|
}
|
|
|
|
metal_mutex_release(&rdev->lock);
|
|
|
|
/* Try to create endpoint name(r:src_cpu:name) of another dest cpu */
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (!strcmp(hub->cpuname[i], rpmsg_get_cpuname(rdev)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
DEBUGASSERT(i < 2);
|
|
|
|
peer_rdev = hub->ept[1 - i].rdev;
|
|
snprintf(peer_name, RPMSG_NAME_SIZE,
|
|
RPMSG_ROUTER_NAME_PREFIX"%s%s", hub->cpuname[i],
|
|
name + RPMSG_ROUTER_NAME_PREFIX_LEN +
|
|
strlen(hub->cpuname[1 - i]));
|
|
|
|
src_ept = kmm_zalloc(sizeof(*src_ept));
|
|
peer_ept = kmm_zalloc(sizeof(*peer_ept));
|
|
|
|
DEBUGASSERT(src_ept && peer_ept);
|
|
|
|
/* Save information for the source ept(r:peer_cpu:name) */
|
|
|
|
src_ept->priv = peer_ept;
|
|
src_ept->rdev = rdev;
|
|
src_ept->dest_addr = dest;
|
|
src_ept->release_cb = rpmsg_router_hub_ept_release;
|
|
strlcpy(src_ept->name, name, sizeof(src_ept->name));
|
|
|
|
/* Create endpoint (r:src_cpu:name) to the peer cpu */
|
|
|
|
peer_ept->priv = src_ept;
|
|
peer_ept->ns_bound_cb = rpmsg_router_hub_bound;
|
|
peer_ept->release_cb = rpmsg_router_hub_ept_release;
|
|
ret = rpmsg_create_ept(peer_ept, peer_rdev, peer_name,
|
|
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
|
|
rpmsg_router_hub_cb,
|
|
rpmsg_router_hub_unbind);
|
|
if (ret < 0)
|
|
{
|
|
kmm_free(peer_ept);
|
|
kmm_free(src_ept);
|
|
}
|
|
|
|
nxmutex_unlock(&hub->lock);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_bound
|
|
*
|
|
* Description:
|
|
* This function is used to send tx/rx buffer size
|
|
* when both cores are ready
|
|
*
|
|
* Parameters:
|
|
* ept - rpmsg endpoint for communicating with edge core
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_bound(FAR struct rpmsg_endpoint *ept)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = ept->priv;
|
|
struct rpmsg_router_s msg;
|
|
int ret;
|
|
int i;
|
|
|
|
if (!is_rpmsg_ept_ready(&hub->ept[0]) ||
|
|
!is_rpmsg_ept_ready(&hub->ept[1]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
msg.cmd = RPMSG_ROUTER_CREATE;
|
|
msg.tx_len = MIN(rpmsg_get_rx_buffer_size(&hub->ept[i]),
|
|
rpmsg_get_tx_buffer_size(&hub->ept[1 - i]));
|
|
msg.rx_len = MIN(rpmsg_get_tx_buffer_size(&hub->ept[i]),
|
|
rpmsg_get_rx_buffer_size(&hub->ept[1 - i]));
|
|
strlcpy(msg.cpuname, hub->cpuname[i], sizeof(msg.cpuname));
|
|
ret = rpmsg_send(&hub->ept[i], &msg, sizeof(msg));
|
|
DEBUGASSERT(ret >= 0);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_notify_edge
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_notify_edge(FAR void *arg)
|
|
{
|
|
FAR struct rpmsg_endpoint *ept = arg;
|
|
FAR struct rpmsg_router_hub_s *hub = ept->priv;
|
|
struct rpmsg_router_s msg;
|
|
int i;
|
|
|
|
msg.cmd = rpmsg_is_running(ept->rdev) ?
|
|
RPMSG_ROUTER_RESUME : RPMSG_ROUTER_SUSPEND;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (strcmp(rpmsg_get_cpuname(ept->rdev), hub->cpuname[i]))
|
|
{
|
|
rpmsg_send(&hub->ept[i], &msg, sizeof(msg));
|
|
}
|
|
}
|
|
|
|
rpmsg_ept_decref(&hub->ept[0]);
|
|
rpmsg_ept_decref(&hub->ept[1]);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_cb
|
|
****************************************************************************/
|
|
|
|
static int rpmsg_router_cb(FAR struct rpmsg_endpoint *ept, FAR void *data,
|
|
size_t len, uint32_t src, FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = ept->priv;
|
|
|
|
/* Send pm signal to the other edge core */
|
|
|
|
if (data == NULL && is_rpmsg_ept_ready(&hub->ept[0]) &&
|
|
is_rpmsg_ept_ready(&hub->ept[1]))
|
|
{
|
|
rpmsg_ept_incref(&hub->ept[0]);
|
|
rpmsg_ept_incref(&hub->ept[1]);
|
|
work_queue(HPWORK, &hub->work, rpmsg_router_notify_edge, ept, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_created
|
|
*
|
|
* Description:
|
|
* This function is used to create endpoint to edge core,
|
|
* for synchronizing ready messages.
|
|
*
|
|
* Parameters:
|
|
* rdev - real rpmsg device
|
|
* priv - rpmsg router hub
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_created(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = priv;
|
|
char name[RPMSG_NAME_SIZE];
|
|
int ret;
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (strcmp(rpmsg_get_cpuname(rdev), hub->cpuname[i]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
hub->ept[i].priv = hub;
|
|
hub->ept[i].ns_bound_cb = rpmsg_router_bound;
|
|
snprintf(name, RPMSG_NAME_SIZE, RPMSG_ROUTER_NAME"%s",
|
|
hub->cpuname[1 - i]);
|
|
|
|
ret = rpmsg_create_ept(&hub->ept[i], rdev, name,
|
|
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
|
|
rpmsg_router_cb, NULL);
|
|
DEBUGASSERT(ret == RPMSG_SUCCESS);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_destroy
|
|
*
|
|
* Description:
|
|
* This function is used to destroy the rpmsg router hub.
|
|
*
|
|
* Parameters:
|
|
* priv - rpmsg router hub
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void rpmsg_router_destroy(FAR struct rpmsg_device *rdev,
|
|
FAR void *priv)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub = priv;
|
|
struct rpmsg_router_s msg;
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (strcmp(rpmsg_get_cpuname(rdev), hub->cpuname[i]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
rpmsg_destroy_ept(&hub->ept[i]);
|
|
|
|
/* Notify the other edge core to destroy router device */
|
|
|
|
if (is_rpmsg_ept_ready(&hub->ept[1 - i]))
|
|
{
|
|
msg.cmd = RPMSG_ROUTER_DESTROY;
|
|
rpmsg_send(&hub->ept[1 - i], &msg, sizeof(msg));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: rpmsg_router_hub_init
|
|
*
|
|
* Description:
|
|
* This function is used to initialize the rpmsg router hub.
|
|
*
|
|
* Parameters:
|
|
* edge0 - edge cpu name
|
|
* edge1 - edge cpu name
|
|
*
|
|
* Returned Values:
|
|
* OK on success; A negated errno value is returned on any failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int rpmsg_router_hub_init(FAR const char *edge0,
|
|
FAR const char *edge1)
|
|
{
|
|
FAR struct rpmsg_router_hub_s *hub;
|
|
int ret;
|
|
|
|
if (edge0 == NULL || edge1 == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
hub = kmm_zalloc(sizeof(*hub));
|
|
if (hub == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
nxmutex_init(&hub->lock);
|
|
strlcpy(hub->cpuname[0], edge0, sizeof(hub->cpuname[0]));
|
|
strlcpy(hub->cpuname[1], edge1, sizeof(hub->cpuname[1]));
|
|
|
|
/* Register callback for retranmitting data between edge cores */
|
|
|
|
ret = rpmsg_register_callback(hub,
|
|
rpmsg_router_created,
|
|
rpmsg_router_destroy,
|
|
rpmsg_router_hub_match,
|
|
rpmsg_router_hub_bind);
|
|
if (ret < 0)
|
|
{
|
|
rpmsgerr("Register rpmsg callback failed: %d\n", ret);
|
|
nxmutex_destroy(&hub->lock);
|
|
kmm_free(hub);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|