[PATCH 2/8] ethosu: Use RPMsg messaging protocol based on i.MX Rpmsg implementation
Alison Wang
alison.wang at nxp.com
Thu Jun 15 22:59:07 PDT 2023
RPMsg is used for the communication mechanism between Cortex-A and
Cortex-M for Ethos-U driver.
Signed-off-by: Lei Xu <lei.xu at nxp.com>
Signed-off-by: Alison Wang <alison.wang at nxp.com>
Reviewed-by: Peng Fan <peng.fan at nxp.com>
---
drivers/firmware/ethosu/Makefile | 2 +-
drivers/firmware/ethosu/ethosu_device.c | 143 ++++----
drivers/firmware/ethosu/ethosu_device.h | 8 +-
drivers/firmware/ethosu/ethosu_driver.c | 23 +-
drivers/firmware/ethosu/ethosu_inference.c | 2 +-
drivers/firmware/ethosu/ethosu_mailbox.c | 377 ---------------------
drivers/firmware/ethosu/ethosu_mailbox.h | 140 --------
drivers/firmware/ethosu/ethosu_rpmsg.c | 235 +++++++++++++
drivers/firmware/ethosu/ethosu_rpmsg.h | 73 ++++
9 files changed, 383 insertions(+), 620 deletions(-)
delete mode 100644 drivers/firmware/ethosu/ethosu_mailbox.c
delete mode 100644 drivers/firmware/ethosu/ethosu_mailbox.h
create mode 100644 drivers/firmware/ethosu/ethosu_rpmsg.c
create mode 100644 drivers/firmware/ethosu/ethosu_rpmsg.h
diff --git a/drivers/firmware/ethosu/Makefile b/drivers/firmware/ethosu/Makefile
index 933efee1b22f..0b3fe72c9c4f 100644
--- a/drivers/firmware/ethosu/Makefile
+++ b/drivers/firmware/ethosu/Makefile
@@ -24,5 +24,5 @@ ethosu-objs := ethosu_driver.o \
ethosu_buffer.o \
ethosu_device.o \
ethosu_inference.o \
- ethosu_mailbox.o \
+ ethosu_rpmsg.o \
ethosu_network.o
diff --git a/drivers/firmware/ethosu/ethosu_device.c b/drivers/firmware/ethosu/ethosu_device.c
index e6f1e8012b06..b2d4737080ac 100644
--- a/drivers/firmware/ethosu/ethosu_device.c
+++ b/drivers/firmware/ethosu/ethosu_device.c
@@ -1,5 +1,6 @@
/*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
+ * Copyright 2020-2022 NXP
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -121,76 +122,76 @@ static int ethosu_capability_rsp(struct ethosu_device *edev,
}
/* Incoming messages */
-static int ethosu_handle_msg(struct ethosu_device *edev)
+static int ethosu_handle_msg(struct ethosu_device *edev, void *data)
{
- int ret;
- struct ethosu_core_msg header;
-
- union {
- struct ethosu_core_msg_err error;
- struct ethosu_core_inference_rsp inf;
- struct ethosu_core_msg_version version;
- struct ethosu_core_msg_capabilities_rsp capabilities;
- } data;
-
- /* Read message */
- ret = ethosu_mailbox_read(&edev->mailbox, &header, &data, sizeof(data));
- if (ret)
- return ret;
-
- switch (header.type) {
+ int ret = 0;
+ struct ethosu_core_msg *header = (struct ethosu_core_msg *)data;
+ struct ethosu_core_msg_err *error =
+ (struct ethosu_core_msg_err *)
+ ((char *)data + sizeof(struct ethosu_core_msg));
+ struct ethosu_core_inference_rsp *rsp =
+ (struct ethosu_core_inference_rsp *)
+ ((char *)data + sizeof(struct ethosu_core_msg));
+ struct ethosu_core_msg_version *version =
+ (struct ethosu_core_msg_version *)
+ ((char *)data + sizeof(struct ethosu_core_msg));
+ struct ethosu_core_msg_capabilities_rsp *capabilities =
+ (struct ethosu_core_msg_capabilities_rsp *)
+ ((char *)data + sizeof(struct ethosu_core_msg));
+
+ switch (header->type) {
case ETHOSU_CORE_MSG_ERR:
- if (header.length != sizeof(data.error)) {
+ if (header->length != sizeof(struct ethosu_core_msg_err)) {
dev_warn(edev->dev,
- "Msg: Error message of incorrect size. size=%u, expected=%zu\n", header.length,
- sizeof(data.error));
+ "Msg: Error message of incorrect size. size=%u, expected=%zu\n", header->length,
+ sizeof(struct ethosu_core_msg_err));
ret = -EBADMSG;
break;
}
- data.error.msg[sizeof(data.error.msg) - 1] = '\0';
+ error->msg[sizeof(error->msg) - 1] = '\0';
dev_warn(edev->dev, "Msg: Error. type=%u, msg=\"%s\"\n",
- data.error.type, data.error.msg);
+ error->type, error->msg);
ret = -EBADMSG;
break;
case ETHOSU_CORE_MSG_PING:
dev_info(edev->dev, "Msg: Ping\n");
- ret = ethosu_mailbox_pong(&edev->mailbox);
+ ret = ethosu_rpmsg_pong(&edev->erp);
break;
case ETHOSU_CORE_MSG_PONG:
dev_info(edev->dev, "Msg: Pong\n");
break;
case ETHOSU_CORE_MSG_INFERENCE_RSP:
- if (header.length != sizeof(data.inf)) {
+ if (header->length != sizeof(struct ethosu_core_inference_rsp)) {
dev_warn(edev->dev,
- "Msg: Inference response of incorrect size. size=%u, expected=%zu\n", header.length,
- sizeof(data.inf));
+ "Msg: Inference response of incorrect size. size=%u, expected=%zu\n", header->length,
+ sizeof(struct ethosu_core_inference_rsp));
ret = -EBADMSG;
break;
}
dev_info(edev->dev,
"Msg: Inference response. user_arg=0x%llx, ofm_count=%u, status=%u\n",
- data.inf.user_arg, data.inf.ofm_count,
- data.inf.status);
- ethosu_inference_rsp(edev, &data.inf);
+ rsp->user_arg, rsp->ofm_count,
+ rsp->status);
+ ethosu_inference_rsp(edev, rsp);
break;
case ETHOSU_CORE_MSG_VERSION_RSP:
- if (header.length != sizeof(data.version)) {
+ if (header->length != sizeof(struct ethosu_core_msg_version)) {
dev_warn(edev->dev,
- "Msg: Version response of incorrect size. size=%u, expected=%zu\n", header.length,
- sizeof(data.version));
+ "Msg: Version response of incorrect size. size=%u, expected=%zu\n", header->length,
+ sizeof(struct ethosu_core_msg_version));
ret = -EBADMSG;
break;
}
dev_info(edev->dev, "Msg: Version response v%u.%u.%u\n",
- data.version.major, data.version.minor,
- data.version.patch);
+ version->major, version->minor,
+ version->patch);
/* Check major and minor version match, else return error */
- if (data.version.major != ETHOSU_CORE_MSG_VERSION_MAJOR ||
- data.version.minor != ETHOSU_CORE_MSG_VERSION_MINOR) {
+ if (version->major != ETHOSU_CORE_MSG_VERSION_MAJOR ||
+ version->minor != ETHOSU_CORE_MSG_VERSION_MINOR) {
dev_warn(edev->dev, "Msg: Version mismatch detected! ");
dev_warn(edev->dev, "Local version: v%u.%u.%u\n",
ETHOSU_CORE_MSG_VERSION_MAJOR,
@@ -200,32 +201,32 @@ static int ethosu_handle_msg(struct ethosu_device *edev)
break;
case ETHOSU_CORE_MSG_CAPABILITIES_RSP:
- if (header.length != sizeof(data.capabilities)) {
+ if (header->length != sizeof(struct ethosu_core_msg_capabilities_rsp)) {
dev_warn(edev->dev,
- "Msg: Capabilities response of incorrect size. size=%u, expected=%zu\n", header.length,
- sizeof(data.capabilities));
+ "Msg: Capabilities response of incorrect size. size=%u, expected=%zu\n", header->length,
+ sizeof(struct ethosu_core_msg_capabilities_rsp));
ret = -EBADMSG;
break;
}
dev_info(edev->dev,
"Msg: Capabilities response ua%llx vs%hhu v%hhu.%hhu p%hhu av%hhu.%hhu.%hhu dv%hhu.%hhu.%hhu mcc%hhu csv%hhu cd%hhu\n",
- data.capabilities.user_arg,
- data.capabilities.version_status,
- data.capabilities.version_major,
- data.capabilities.version_minor,
- data.capabilities.product_major,
- data.capabilities.arch_major_rev,
- data.capabilities.arch_minor_rev,
- data.capabilities.arch_patch_rev,
- data.capabilities.driver_major_rev,
- data.capabilities.driver_minor_rev,
- data.capabilities.driver_patch_rev,
- data.capabilities.macs_per_cc,
- data.capabilities.cmd_stream_version,
- data.capabilities.custom_dma);
-
- ret = ethosu_capability_rsp(edev, &data.capabilities);
+ capabilities->user_arg,
+ capabilities->version_status,
+ capabilities->version_major,
+ capabilities->version_minor,
+ capabilities->product_major,
+ capabilities->arch_major_rev,
+ capabilities->arch_minor_rev,
+ capabilities->arch_patch_rev,
+ capabilities->driver_major_rev,
+ capabilities->driver_minor_rev,
+ capabilities->driver_patch_rev,
+ capabilities->macs_per_cc,
+ capabilities->cmd_stream_version,
+ capabilities->custom_dma);
+
+ ret = ethosu_capability_rsp(edev, capabilities);
break;
default:
/* This should not happen due to version checks */
@@ -269,7 +270,7 @@ static int ethosu_send_capabilities_request(struct ethosu_device *edev,
init_completion(&cap->done);
list_add(&cap->list, &edev->capabilities_list);
- ret = ethosu_mailbox_capabilities_request(&edev->mailbox, cap);
+ ret = ethosu_rpmsg_capabilities_request(&edev->erp, cap);
if (0 != ret)
goto put_kref;
@@ -325,7 +326,7 @@ static long ethosu_ioctl(struct file *file,
switch (cmd) {
case ETHOSU_IOCTL_VERSION_REQ:
dev_info(edev->dev, "Ioctl: Send version request\n");
- ret = ethosu_mailbox_version_request(&edev->mailbox);
+ ret = ethosu_rpmsg_version_request(&edev->erp);
break;
case ETHOSU_IOCTL_CAPABILITIES_REQ:
dev_info(edev->dev, "Ioctl: Send capabilities request\n");
@@ -333,7 +334,7 @@ static long ethosu_ioctl(struct file *file,
break;
case ETHOSU_IOCTL_PING: {
dev_info(edev->dev, "Ioctl: Send ping\n");
- ret = ethosu_mailbox_ping(&edev->mailbox);
+ ret = ethosu_rpmsg_ping(&edev->erp);
break;
}
case ETHOSU_IOCTL_BUFFER_CREATE: {
@@ -373,7 +374,7 @@ static long ethosu_ioctl(struct file *file,
return ret;
}
-static void ethosu_mbox_rx(void *user_arg)
+static void ethosu_rpmsg_rx(void *user_arg, void *data)
{
struct ethosu_device *edev = user_arg;
int ret;
@@ -381,13 +382,8 @@ static void ethosu_mbox_rx(void *user_arg)
mutex_lock(&edev->mutex);
do {
- ret = ethosu_handle_msg(edev);
- if (ret && ret != -ENOMSG)
- /* Need to start over in case of error, empty the queue
- * by fast-forwarding read position to write position.
- * */
- ethosu_mailbox_reset(&edev->mailbox);
- } while (ret == 0);
+ ret = ethosu_handle_msg(edev, data);
+ } while (ret != 0);
mutex_unlock(&edev->mutex);
}
@@ -395,9 +391,7 @@ static void ethosu_mbox_rx(void *user_arg)
int ethosu_dev_init(struct ethosu_device *edev,
struct device *dev,
struct class *class,
- dev_t devt,
- struct resource *in_queue,
- struct resource *out_queue)
+ dev_t devt)
{
static const struct file_operations fops = {
.owner = THIS_MODULE,
@@ -423,8 +417,7 @@ int ethosu_dev_init(struct ethosu_device *edev,
dma_set_mask_and_coherent(edev->dev, DMA_BIT_MASK(DMA_ADDR_BITS));
- ret = ethosu_mailbox_init(&edev->mailbox, dev, in_queue, out_queue,
- ethosu_mbox_rx, edev);
+ ret = ethosu_rpmsg_init(&edev->erp, ethosu_rpmsg_rx, edev);
if (ret)
goto release_reserved_mem;
@@ -434,7 +427,7 @@ int ethosu_dev_init(struct ethosu_device *edev,
ret = cdev_add(&edev->cdev, edev->devt, 1);
if (ret) {
dev_err(edev->dev, "Failed to add character device.\n");
- goto deinit_mailbox;
+ goto deinit_rpmsg;
}
sysdev = device_create(edev->class, NULL, edev->devt, edev,
@@ -454,8 +447,8 @@ int ethosu_dev_init(struct ethosu_device *edev,
del_cdev:
cdev_del(&edev->cdev);
-deinit_mailbox:
- ethosu_mailbox_deinit(&edev->mailbox);
+deinit_rpmsg:
+ ethosu_rpmsg_deinit(&edev->erp);
release_reserved_mem:
of_reserved_mem_device_release(edev->dev);
@@ -465,7 +458,7 @@ int ethosu_dev_init(struct ethosu_device *edev,
void ethosu_dev_deinit(struct ethosu_device *edev)
{
- ethosu_mailbox_deinit(&edev->mailbox);
+ ethosu_rpmsg_deinit(&edev->erp);
device_destroy(edev->class, edev->cdev.dev);
cdev_del(&edev->cdev);
of_reserved_mem_device_release(edev->dev);
diff --git a/drivers/firmware/ethosu/ethosu_device.h b/drivers/firmware/ethosu/ethosu_device.h
index 3afdda84862d..3943c8df8f28 100644
--- a/drivers/firmware/ethosu/ethosu_device.h
+++ b/drivers/firmware/ethosu/ethosu_device.h
@@ -26,7 +26,7 @@
****************************************************************************/
#include "uapi/ethosu.h"
-#include "ethosu_mailbox.h"
+#include "ethosu_rpmsg.h"
#include <linux/device.h>
#include <linux/cdev.h>
@@ -48,7 +48,7 @@ struct ethosu_device {
struct class *class;
dev_t devt;
struct mutex mutex;
- struct ethosu_mailbox mailbox;
+ struct ethosu_rpmsg erp;
struct list_head capabilities_list;
struct list_head inference_list;
};
@@ -76,9 +76,7 @@ struct ethosu_capabilities {
int ethosu_dev_init(struct ethosu_device *edev,
struct device *dev,
struct class *class,
- dev_t devt,
- struct resource *in_queue,
- struct resource *out_queue);
+ dev_t devt);
/**
* ethosu_dev_deinit() - Initialize the device
diff --git a/drivers/firmware/ethosu/ethosu_driver.c b/drivers/firmware/ethosu/ethosu_driver.c
index 9d02431d3194..27931e9aa97c 100644
--- a/drivers/firmware/ethosu/ethosu_driver.c
+++ b/drivers/firmware/ethosu/ethosu_driver.c
@@ -1,5 +1,6 @@
/*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
+ * Copyright 2020-2022 NXP
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -55,8 +56,6 @@ static DECLARE_BITMAP(minors, MINOR_COUNT);
static int ethosu_pdev_probe(struct platform_device *pdev)
{
struct ethosu_device *edev;
- struct resource *in_queue_res;
- struct resource *out_queue_res;
int minor;
int ret;
@@ -69,23 +68,6 @@ static int ethosu_pdev_probe(struct platform_device *pdev)
return -ENOMEM;
}
- /* Get path to TCM memory */
- in_queue_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "in_queue");
- if (IS_ERR(in_queue_res)) {
- dev_err(&pdev->dev, "Failed to get in_queue resource.\n");
-
- return PTR_ERR(in_queue_res);
- }
-
- out_queue_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "out_queue");
- if (IS_ERR(out_queue_res)) {
- dev_err(&pdev->dev, "Failed to get out_queue resource.\n");
-
- return PTR_ERR(out_queue_res);
- }
-
/* Allocate memory for Arm Ethos-U device */
edev = devm_kzalloc(&pdev->dev, sizeof(*edev), GFP_KERNEL);
if (!edev)
@@ -95,8 +77,7 @@ static int ethosu_pdev_probe(struct platform_device *pdev)
/* Initialize device */
ret = ethosu_dev_init(edev, &pdev->dev, ethosu_class,
- MKDEV(MAJOR(devt), minor), in_queue_res,
- out_queue_res);
+ MKDEV(MAJOR(devt), minor));
if (ret)
goto free_dev;
diff --git a/drivers/firmware/ethosu/ethosu_inference.c b/drivers/firmware/ethosu/ethosu_inference.c
index 6fde92c148a0..853947a2334e 100644
--- a/drivers/firmware/ethosu/ethosu_inference.c
+++ b/drivers/firmware/ethosu/ethosu_inference.c
@@ -86,7 +86,7 @@ static int ethosu_inference_send(struct ethosu_inference *inf)
inf->status = ETHOSU_UAPI_STATUS_ERROR;
- ret = ethosu_mailbox_inference(&inf->edev->mailbox, inf,
+ ret = ethosu_rpmsg_inference(&inf->edev->erp, inf,
inf->ifm_count, inf->ifm,
inf->ofm_count, inf->ofm,
inf->net->buf,
diff --git a/drivers/firmware/ethosu/ethosu_mailbox.c b/drivers/firmware/ethosu/ethosu_mailbox.c
deleted file mode 100644
index 7f159f3b0a60..000000000000
--- a/drivers/firmware/ethosu/ethosu_mailbox.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
- *
- * This program is free software and is provided to you under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation, and any use by you of this program is subject to the terms
- * of such GNU licence.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can access it online at
- * http://www.gnu.org/licenses/gpl-2.0.html.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
-
-/****************************************************************************
- * Includes
- ****************************************************************************/
-
-#include "ethosu_mailbox.h"
-
-#include "ethosu_buffer.h"
-#include "ethosu_core_interface.h"
-#include "ethosu_device.h"
-
-#include <linux/resource.h>
-#include <linux/uio.h>
-
-/****************************************************************************
- * Functions
- ****************************************************************************/
-
-static void ethosu_core_set_size(struct ethosu_buffer *buf,
- struct ethosu_core_buffer *cbuf)
-{
- cbuf->ptr = (uint32_t)buf->dma_addr + buf->offset;
- cbuf->size = (uint32_t)buf->size;
-}
-
-static void ethosu_core_set_capacity(struct ethosu_buffer *buf,
- struct ethosu_core_buffer *cbuf)
-{
- cbuf->ptr = (uint32_t)buf->dma_addr + buf->offset + buf->size;
- cbuf->size = (uint32_t)buf->capacity - buf->offset - buf->size;
-}
-
-static size_t ethosu_queue_available(struct ethosu_core_queue *queue)
-{
- size_t size = queue->header.write - queue->header.read;
-
- if (queue->header.read > queue->header.write)
- size += queue->header.size;
-
- return size;
-}
-
-static size_t ethosu_queue_capacity(struct ethosu_core_queue *queue)
-{
- return queue->header.size - ethosu_queue_available(queue);
-}
-
-static int ethosu_queue_write(struct ethosu_mailbox *mbox,
- const struct kvec *vec,
- size_t length)
-{
- struct ethosu_core_queue *queue = mbox->in_queue;
- uint8_t *dst = &queue->data[0];
- uint32_t wpos = queue->header.write;
- size_t total_size;
- size_t i;
- int ret;
-
- for (i = 0, total_size = 0; i < length; i++)
- total_size += vec[i].iov_len;
-
- if (total_size > ethosu_queue_capacity(queue))
- return -EINVAL;
-
- for (i = 0; i < length; i++) {
- const uint8_t *src = vec[i].iov_base;
- const uint8_t *end = src + vec[i].iov_len;
-
- while (src < end) {
- dst[wpos] = *src++;
- wpos = (wpos + 1) % queue->header.size;
- }
- }
-
- queue->header.write = wpos;
-
- ret = mbox_send_message(mbox->tx, queue);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int ethosu_queue_write_msg(struct ethosu_mailbox *mbox,
- uint32_t type,
- void *data,
- size_t length)
-{
- struct ethosu_core_msg msg = {
- .magic = ETHOSU_CORE_MSG_MAGIC,
- .type = type, .length= length
- };
- const struct kvec vec[2] = {
- { &msg, sizeof(msg) },
- { data, length }
- };
-
- return ethosu_queue_write(mbox, vec, 2);
-}
-
-static int ethosu_queue_read(struct ethosu_mailbox *mbox,
- void *data,
- size_t length)
-{
- struct ethosu_core_queue *queue = mbox->out_queue;
- uint8_t *src = &queue->data[0];
- uint8_t *dst = (uint8_t *)data;
- const uint8_t *end = dst + length;
- uint32_t rpos = queue->header.read;
- size_t queue_avail = ethosu_queue_available(queue);
-
- if (length == 0)
- return 0;
- else if (queue_avail == 0)
- return -ENOMSG;
- else if (length > queue_avail)
- return -EBADMSG;
-
- while (dst < end) {
- *dst++ = src[rpos];
- rpos = (rpos + 1) % queue->header.size;
- }
-
- queue->header.read = rpos;
-
- return 0;
-}
-
-void ethosu_mailbox_reset(struct ethosu_mailbox *mbox)
-{
- mbox->out_queue->header.read = mbox->out_queue->header.write;
-}
-
-int ethosu_mailbox_read(struct ethosu_mailbox *mbox,
- struct ethosu_core_msg *header,
- void *data,
- size_t length)
-{
- int ret;
-
- /* Read message header magic */
- ret = ethosu_queue_read(mbox, header, sizeof(*header));
- if (ret) {
- if (ret != -ENOMSG)
- dev_warn(mbox->dev,
- "Msg: Failed to read message header\n");
-
- return ret;
- }
-
- if (header->magic != ETHOSU_CORE_MSG_MAGIC) {
- dev_warn(mbox->dev,
- "Msg: Invalid magic. Got: %08X but expected %08X\n",
- header->magic, ETHOSU_CORE_MSG_MAGIC);
-
- return -EINVAL;
- }
-
- dev_info(mbox->dev,
- "mbox: Read msg header. magic=%08X, type=%u, length=%u",
- header->magic, header->type, header->length);
-
- /* Check that payload is not larger than allocated buffer */
- if (header->length > length) {
- dev_warn(mbox->dev,
- "Msg: Buffer size (%zu) too small for message (%u)\n",
- sizeof(data), header->length);
-
- return -ENOMEM;
- }
-
- /* Read payload data */
- ret = ethosu_queue_read(mbox, data, header->length);
- if (ret) {
- dev_warn(mbox->dev, "Msg: Failed to read payload data\n");
-
- return -EBADMSG;
- }
-
- return 0;
-}
-
-int ethosu_mailbox_ping(struct ethosu_mailbox *mbox)
-{
- return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_PING, NULL, 0);
-}
-
-int ethosu_mailbox_pong(struct ethosu_mailbox *mbox)
-{
- return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_PONG, NULL, 0);
-}
-
-int ethosu_mailbox_version_request(struct ethosu_mailbox *mbox)
-{
- return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_VERSION_REQ, NULL,
- 0);
-}
-
-int ethosu_mailbox_capabilities_request(struct ethosu_mailbox *mbox,
- void *user_arg)
-{
- struct ethosu_core_capabilities_req req = {
- .user_arg = (ptrdiff_t)user_arg
- };
-
- return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_CAPABILITIES_REQ,
- &req,
- sizeof(req));
-}
-
-int ethosu_mailbox_inference(struct ethosu_mailbox *mbox,
- void *user_arg,
- uint32_t ifm_count,
- struct ethosu_buffer **ifm,
- uint32_t ofm_count,
- struct ethosu_buffer **ofm,
- struct ethosu_buffer *network,
- uint8_t *pmu_event_config,
- uint8_t pmu_event_config_count,
- uint8_t pmu_cycle_counter_enable)
-{
- struct ethosu_core_inference_req inf;
- uint32_t i;
-
- /* Verify that the uapi and core has the same number of pmus */
- if (pmu_event_config_count != ETHOSU_CORE_PMU_MAX) {
- dev_err(mbox->dev, "PMU count misconfigured.\n");
-
- return -EINVAL;
- }
-
- inf.user_arg = (ptrdiff_t)user_arg;
- inf.ifm_count = ifm_count;
- inf.ofm_count = ofm_count;
- inf.pmu_cycle_counter_enable = pmu_cycle_counter_enable;
-
- for (i = 0; i < ifm_count; i++)
- ethosu_core_set_size(ifm[i], &inf.ifm[i]);
-
- for (i = 0; i < ofm_count; i++)
- ethosu_core_set_capacity(ofm[i], &inf.ofm[i]);
-
- for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++)
- inf.pmu_event_config[i] = pmu_event_config[i];
-
- ethosu_core_set_size(network, &inf.network);
-
- return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_INFERENCE_REQ,
- &inf, sizeof(inf));
-}
-
-static void ethosu_mailbox_rx_work(struct work_struct *work)
-{
- struct ethosu_mailbox *mbox = container_of(work, typeof(*mbox), work);
-
- mbox->callback(mbox->user_arg);
-}
-
-static void ethosu_mailbox_rx_callback(struct mbox_client *client,
- void *message)
-{
- struct ethosu_mailbox *mbox =
- container_of(client, typeof(*mbox), client);
-
- dev_info(mbox->dev, "mbox: Received message.\n");
-
- queue_work(mbox->wq, &mbox->work);
-}
-
-static void ethosu_mailbox_tx_done(struct mbox_client *client,
- void *message,
- int r)
-{
- if (r)
- dev_warn(client->dev, "mbox: Failed sending message (%d)\n", r);
- else
- dev_info(client->dev, "mbox: Message sent\n");
-}
-
-int ethosu_mailbox_init(struct ethosu_mailbox *mbox,
- struct device *dev,
- struct resource *in_queue,
- struct resource *out_queue,
- ethosu_mailbox_cb callback,
- void *user_arg)
-{
- int ret;
-
- mbox->dev = dev;
- mbox->callback = callback;
- mbox->user_arg = user_arg;
-
- mbox->client.dev = dev;
- mbox->client.rx_callback = ethosu_mailbox_rx_callback;
- mbox->client.tx_prepare = NULL; /* preparation of data is handled
- * through the
- * queue functions */
- mbox->client.tx_done = ethosu_mailbox_tx_done;
- mbox->client.tx_block = true;
- mbox->client.knows_txdone = false;
- mbox->client.tx_tout = 500;
-
- mbox->in_queue = devm_ioremap_resource(mbox->dev, in_queue);
- if (IS_ERR(mbox->in_queue))
- return PTR_ERR(mbox->in_queue);
-
- mbox->out_queue = devm_ioremap_resource(mbox->dev, out_queue);
- if (IS_ERR(mbox->out_queue)) {
- ret = PTR_ERR(mbox->out_queue);
- goto unmap_in_queue;
- }
-
- mbox->wq = create_singlethread_workqueue("ethosu_workqueue");
- if (!mbox->wq) {
- dev_err(mbox->dev, "Failed to create work queue\n");
- ret = -EINVAL;
- goto unmap_out_queue;
- }
-
- INIT_WORK(&mbox->work, ethosu_mailbox_rx_work);
-
- mbox->tx = mbox_request_channel_byname(&mbox->client, "tx");
- if (IS_ERR(mbox->tx)) {
- dev_warn(mbox->dev, "mbox: Failed to request tx channel\n");
- ret = PTR_ERR(mbox->tx);
- goto workqueue_destroy;
- }
-
- mbox->rx = mbox_request_channel_byname(&mbox->client, "rx");
- if (IS_ERR(mbox->rx)) {
- dev_info(dev, "mbox: Using same channel for RX and TX\n");
- mbox->rx = mbox->tx;
- }
-
- return 0;
-
-workqueue_destroy:
- destroy_workqueue(mbox->wq);
-
-unmap_out_queue:
- devm_iounmap(mbox->dev, mbox->out_queue);
-
-unmap_in_queue:
- devm_iounmap(mbox->dev, mbox->in_queue);
-
- return ret;
-}
-
-void ethosu_mailbox_deinit(struct ethosu_mailbox *mbox)
-{
- if (mbox->rx != mbox->tx)
- mbox_free_channel(mbox->rx);
-
- mbox_free_channel(mbox->tx);
- destroy_workqueue(mbox->wq);
- devm_iounmap(mbox->dev, mbox->out_queue);
- devm_iounmap(mbox->dev, mbox->in_queue);
-}
diff --git a/drivers/firmware/ethosu/ethosu_mailbox.h b/drivers/firmware/ethosu/ethosu_mailbox.h
deleted file mode 100644
index 5cd5e62198b8..000000000000
--- a/drivers/firmware/ethosu/ethosu_mailbox.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
- *
- * This program is free software and is provided to you under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation, and any use by you of this program is subject to the terms
- * of such GNU licence.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can access it online at
- * http://www.gnu.org/licenses/gpl-2.0.html.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
-
-#ifndef ETHOSU_MAILBOX_H
-#define ETHOSU_MAILBOX_H
-
-/****************************************************************************
- * Includes
- ****************************************************************************/
-#include "ethosu_core_interface.h"
-
-#include <linux/types.h>
-#include <linux/mailbox_client.h>
-#include <linux/workqueue.h>
-
-/****************************************************************************
- * Types
- ****************************************************************************/
-
-struct device;
-struct ethosu_buffer;
-struct ethosu_device;
-struct ethosu_core_msg;
-struct ethosu_core_queue;
-struct resource;
-
-typedef void (*ethosu_mailbox_cb)(void *user_arg);
-
-struct ethosu_mailbox {
- struct device *dev;
- struct workqueue_struct *wq;
- struct work_struct work;
- struct ethosu_core_queue __iomem *in_queue;
- struct ethosu_core_queue __iomem *out_queue;
- struct mbox_client client;
- struct mbox_chan *rx;
- struct mbox_chan *tx;
- ethosu_mailbox_cb callback;
- void *user_arg;
-};
-
-/****************************************************************************
- * Functions
- ****************************************************************************/
-
-/**
- * ethosu_mailbox_init() - Initialize mailbox
- *
- * Return: 0 on success, else error code.
- */
-int ethosu_mailbox_init(struct ethosu_mailbox *mbox,
- struct device *dev,
- struct resource *in_queue,
- struct resource *out_queue,
- ethosu_mailbox_cb callback,
- void *user_arg);
-
-/**
- * ethosu_mailbox_deinit() - Deinitialize mailbox
- */
-void ethosu_mailbox_deinit(struct ethosu_mailbox *mbox);
-
-/**
- * ethosu_mailbox_read() - Read message from mailbox
- *
- * Return: 0 message read, else error code.
- */
-int ethosu_mailbox_read(struct ethosu_mailbox *mbox,
- struct ethosu_core_msg *header,
- void *data,
- size_t length);
-
-/**
- * ethosu_mailbox_reset() - Reset to end of queue
- */
-void ethosu_mailbox_reset(struct ethosu_mailbox *mbox);
-
-/**
- * ethosu_mailbox_ping() - Send ping message
- *
- * Return: 0 on success, else error code.
- */
-int ethosu_mailbox_ping(struct ethosu_mailbox *mbox);
-
-/**
- * ethosu_mailbox_pong() - Send pong response
- *
- * Return: 0 on success, else error code.
- */
-int ethosu_mailbox_pong(struct ethosu_mailbox *mbox);
-
-/**
- * ethosu_mailbox_version_response - Send version request
- *
- * Return: 0 on succes, else error code
- */
-int ethosu_mailbox_version_request(struct ethosu_mailbox *mbox);
-
-/**
- * ethosu_mailbox_capabilities_request() - Send capabilities request
- *
- * Return: 0 on success, else error code.
- */
-int ethosu_mailbox_capabilities_request(struct ethosu_mailbox *mbox,
- void *user_arg);
-
-/**
- * ethosu_mailbox_inference() - Send inference
- *
- * Return: 0 on success, else error code.
- */
-int ethosu_mailbox_inference(struct ethosu_mailbox *mbox,
- void *user_arg,
- uint32_t ifm_count,
- struct ethosu_buffer **ifm,
- uint32_t ofm_count,
- struct ethosu_buffer **ofm,
- struct ethosu_buffer *network,
- uint8_t *pmu_event_config,
- uint8_t pmu_event_config_count,
- uint8_t pmu_cycle_counter_enable);
-
-#endif /* ETHOSU_MAILBOX_H */
diff --git a/drivers/firmware/ethosu/ethosu_rpmsg.c b/drivers/firmware/ethosu/ethosu_rpmsg.c
new file mode 100644
index 000000000000..cb7e4556f635
--- /dev/null
+++ b/drivers/firmware/ethosu/ethosu_rpmsg.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020-2022 NXP
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/resource.h>
+#include <linux/rpmsg.h>
+#include <linux/uio.h>
+#include <linux/virtio.h>
+
+#include "ethosu_buffer.h"
+#include "ethosu_core_interface.h"
+#include "ethosu_device.h"
+
+struct ethosu_rpmsg *grp;
+
+#define MSG "ethosu say hello!"
+
+static void ethosu_core_set_size(struct ethosu_buffer *buf,
+ struct ethosu_core_buffer *cbuf)
+{
+ cbuf->ptr = (uint32_t)buf->dma_addr + buf->offset;
+ cbuf->size = (uint32_t)buf->size;
+}
+
+static void ethosu_core_set_capacity(struct ethosu_buffer *buf,
+ struct ethosu_core_buffer *cbuf)
+{
+ cbuf->ptr = (uint32_t)buf->dma_addr + buf->offset + buf->size;
+ cbuf->size = (uint32_t)buf->capacity - buf->offset - buf->size;
+}
+
+static int ethosu_rpmsg_send(struct ethosu_rpmsg *erp, uint32_t type)
+{
+ struct ethosu_core_msg msg;
+ struct rpmsg_device *rpdev = erp->rpdev;
+ int ret;
+
+ msg.magic = ETHOSU_CORE_MSG_MAGIC;
+ msg.type = type;
+ msg.length = 0;
+
+ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+ (void *)&msg, sizeof(msg), true);
+
+ ret = rpmsg_send(rpdev->ept, (void *)&msg, sizeof(msg));
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ethosu_rpmsg_ping(struct ethosu_rpmsg *erp)
+{
+ return ethosu_rpmsg_send(erp, ETHOSU_CORE_MSG_PING);
+}
+
+int ethosu_rpmsg_pong(struct ethosu_rpmsg *erp)
+{
+ return ethosu_rpmsg_send(erp, ETHOSU_CORE_MSG_PONG);
+}
+
+int ethosu_rpmsg_version_request(struct ethosu_rpmsg *erp)
+{
+ return ethosu_rpmsg_send(erp, ETHOSU_CORE_MSG_VERSION_REQ);
+}
+
+int ethosu_rpmsg_capabilities_request(struct ethosu_rpmsg *erp, void *user_arg)
+{
+ struct ethosu_core_msg msg = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_CAPABILITIES_REQ,
+ .length = sizeof(struct ethosu_core_capabilities_req)
+ };
+ struct ethosu_core_capabilities_req req = {
+ .user_arg = (uint64_t)user_arg
+ };
+ struct rpmsg_device *rpdev = erp->rpdev;
+ uint8_t data[sizeof(struct ethosu_core_msg) +
+ sizeof(struct ethosu_core_capabilities_req)];
+ int ret;
+
+ memcpy(data, &msg, sizeof(struct ethosu_core_msg));
+ memcpy(data + sizeof(struct ethosu_core_msg), &req,
+ sizeof(struct ethosu_core_capabilities_req));
+
+ ret = rpmsg_send(rpdev->ept, (void *)&data,
+ sizeof(struct ethosu_core_msg) +
+ sizeof(struct ethosu_core_capabilities_req));
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+int ethosu_rpmsg_inference(struct ethosu_rpmsg *erp,
+ void *user_arg,
+ uint32_t ifm_count,
+ struct ethosu_buffer **ifm,
+ uint32_t ofm_count,
+ struct ethosu_buffer **ofm,
+ struct ethosu_buffer *network,
+ uint8_t *pmu_event_config,
+ uint8_t pmu_event_config_count,
+ uint8_t pmu_cycle_counter_enable)
+{
+ struct ethosu_core_msg msg = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_INFERENCE_REQ,
+ .length = sizeof(struct ethosu_core_inference_req)
+ };
+ struct ethosu_core_inference_req req;
+ struct rpmsg_device *rpdev = erp->rpdev;
+ uint8_t data[sizeof(struct ethosu_core_msg) +
+ sizeof(struct ethosu_core_inference_req)];
+ int ret;
+ uint32_t i;
+
+ /* Verify that the uapi and core has the same number of pmus */
+ if (pmu_event_config_count != ETHOSU_CORE_PMU_MAX) {
+ dev_err(&rpdev->dev, "PMU count misconfigured.\n");
+
+ return -EINVAL;
+ }
+
+ req.user_arg = (uint64_t)user_arg;
+ req.ifm_count = ifm_count;
+ req.ofm_count = ofm_count;
+ req.pmu_cycle_counter_enable = pmu_cycle_counter_enable;
+
+ for (i = 0; i < ifm_count; i++)
+ ethosu_core_set_size(ifm[i], &req.ifm[i]);
+
+ for (i = 0; i < ofm_count; i++)
+ ethosu_core_set_capacity(ofm[i], &req.ofm[i]);
+
+ for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++)
+ req.pmu_event_config[i] = pmu_event_config[i];
+
+ ethosu_core_set_size(network, &req.network);
+
+ memcpy(data, &msg, sizeof(struct ethosu_core_msg));
+ memcpy(data + sizeof(struct ethosu_core_msg), &req,
+ sizeof(struct ethosu_core_inference_req));
+
+ ret = rpmsg_send(rpdev->ept, (void *)&data,
+ sizeof(struct ethosu_core_msg) +
+ sizeof(struct ethosu_core_inference_req));
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rpmsg_ethosu_cb(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct ethosu_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev);
+
+ if (len == 0)
+ return 0;
+
+ dev_dbg(&rpdev->dev, "msg(<- src 0x%x) len %d\n", src, len);
+
+ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+ data, len, true);
+
+ rpmsg->callback(rpmsg->user_arg, data);
+
+ return 0;
+}
+
+static int ethosu_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ int ret;
+
+ grp->rpdev = rpdev;
+ dev_set_drvdata(&rpdev->dev, grp);
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ ret = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ }
+
+ return 0;
+}
+
+static void ethosu_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ dev_info(&rpdev->dev, "rpmsg ethosu driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_ethosu_id_table[] = {
+ { .name = "rpmsg-ethosu-channel" },
+ { },
+};
+
+static struct rpmsg_driver ethosu_rpmsg_driver = {
+ .drv.name = KBUILD_MODNAME,
+ .drv.owner = THIS_MODULE,
+ .id_table = rpmsg_driver_ethosu_id_table,
+ .probe = ethosu_rpmsg_probe,
+ .callback = rpmsg_ethosu_cb,
+ .remove = ethosu_rpmsg_remove,
+};
+
+int ethosu_rpmsg_init(struct ethosu_rpmsg *erp,
+ ethosu_rpmsg_cb callback, void *user_arg)
+{
+ grp = erp;
+ erp->callback = callback;
+ erp->user_arg = user_arg;
+
+ return register_rpmsg_driver(ðosu_rpmsg_driver);
+}
+
+int ethosu_rpmsg_deinit(struct ethosu_rpmsg *erp)
+{
+ erp->callback = NULL;
+ erp->user_arg = NULL;
+ erp->rpdev = NULL;
+
+ unregister_rpmsg_driver(ðosu_rpmsg_driver);
+ return 0;
+}
diff --git a/drivers/firmware/ethosu/ethosu_rpmsg.h b/drivers/firmware/ethosu/ethosu_rpmsg.h
new file mode 100644
index 000000000000..dd08e0d7945b
--- /dev/null
+++ b/drivers/firmware/ethosu/ethosu_rpmsg.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020-2022 NXP
+ */
+
+#ifndef ETHOSU_RPMSG_H
+#define ETHOSU_RPMSG_H
+
+#include <linux/types.h>
+
+struct device;
+struct ethosu_buffer;
+struct ethosu_device;
+struct ethosu_core_msg;
+
+typedef void (*ethosu_rpmsg_cb)(void *user_arg, void *data);
+
+struct ethosu_rpmsg {
+ struct rpmsg_device *rpdev;
+ ethosu_rpmsg_cb callback;
+ void *user_arg;
+};
+/**
+ * ethosu_rpmsg_ping() - Send ping message
+ *
+ * Return: 0 on success, else error code.
+ */
+int ethosu_rpmsg_ping(struct ethosu_rpmsg *erp);
+
+/**
+ * ethosu_rpmsg_pong() - Send pong message
+ *
+ * Return: 0 on success, else error code.
+ */
+int ethosu_rpmsg_pong(struct ethosu_rpmsg *erp);
+
+/**
+ * ethosu_rpmsg_version_response - Send version request
+ *
+ * Return: 0 on success, else error code
+ */
+int ethosu_rpmsg_version_request(struct ethosu_rpmsg *erp);
+
+/**
+ * ethosu_rpmsg_capabilities_request - Send capabilities request
+ *
+ * Return: 0 on success, else error code
+ */
+int ethosu_rpmsg_capabilities_request(struct ethosu_rpmsg *erp,
+ void *user_arg);
+
+/**
+ * ethosu_rpmsg_inference() - Send inference
+ *
+ * Return: 0 on success, else error code.
+ */
+int ethosu_rpmsg_inference(struct ethosu_rpmsg *erp,
+ void *user_arg,
+ uint32_t ifm_count,
+ struct ethosu_buffer **ifm,
+ uint32_t ofm_count,
+ struct ethosu_buffer **ofm,
+ struct ethosu_buffer *network,
+ uint8_t *pmu_event_config,
+ uint8_t pmu_event_config_count,
+ uint8_t pmu_cycle_counter_enable
+ );
+
+int ethosu_rpmsg_init(struct ethosu_rpmsg *erp,
+ ethosu_rpmsg_cb callback, void *user_arg);
+
+int ethosu_rpmsg_deinit(struct ethosu_rpmsg *erp);
+#endif /* ETHOSU_RPMSG_H */
--
2.17.1
More information about the linux-arm-kernel
mailing list