aboutsummaryrefslogtreecommitdiff
path: root/kernel/rpmsg/ethosu_rpmsg_mailbox.c
diff options
context:
space:
mode:
authorMikael Olsson <mikael.olsson@arm.com>2024-02-07 11:22:26 +0100
committerMikael Olsson <mikael.olsson@arm.com>2024-02-12 13:04:41 +0100
commitd4ad9e55cb8e17a4a42b3a94c64e6bc48529b26e (patch)
tree9084d770574bc2a278ddfa121985ac030f711daa /kernel/rpmsg/ethosu_rpmsg_mailbox.c
parent09cdc30b3b3a52176cd02518c07d5f44c1ce8dd1 (diff)
downloadethos-u-linux-driver-stack-d4ad9e55cb8e17a4a42b3a94c64e6bc48529b26e.tar.gz
Restructure kernel driver source tree
As a first step to have a clearer separation of the different parts of the kernel driver, the source files have been placed into separate directories according to their purpose and the different parts are only allowed to use headers from another part in the include folder. Files have been renamed accordingly to namespace them by their purpose. Change-Id: I75e09ebf0002c99a22b6d4b09d34504d186c32b3 Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Diffstat (limited to 'kernel/rpmsg/ethosu_rpmsg_mailbox.c')
-rw-r--r--kernel/rpmsg/ethosu_rpmsg_mailbox.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/kernel/rpmsg/ethosu_rpmsg_mailbox.c b/kernel/rpmsg/ethosu_rpmsg_mailbox.c
new file mode 100644
index 0000000..11ac414
--- /dev/null
+++ b/kernel/rpmsg/ethosu_rpmsg_mailbox.c
@@ -0,0 +1,363 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2020-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * 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.
+ */
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#include <rpmsg/ethosu_rpmsg_mailbox.h>
+
+#include <common/ethosu_buffer.h>
+#include <common/ethosu_device.h>
+#include <common/ethosu_dma_mem.h>
+#include <rpmsg/ethosu_rpmsg.h>
+
+#include <rpmsg/ethosu_rpmsg_network.h>
+
+#include <linux/atomic.h>
+#include <linux/jiffies.h>
+#include <linux/resource.h>
+#include <linux/uio.h>
+#include <linux/bug.h>
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#ifndef fallthrough
+#if __has_attribute(__fallthrough__)
+#define fallthrough __attribute__((__fallthrough__))
+#else
+#define fallthrough do {} while (0) /* fallthrough */
+#endif
+#endif
+
+/****************************************************************************
+ * Defines
+ ****************************************************************************/
+
+#define MAILBOX_SEND_TIMEOUT_MS 15000
+
+/****************************************************************************
+ * Functions
+ ****************************************************************************/
+
+/**
+ * ethosu_send_locked() - Blocking mailbox message sender
+ *
+ * Context: Can sleep and must be called with the device mutex locked.
+ *
+ * Return: 0 on success, else error code.
+ */
+static int ethosu_send_locked(struct ethosu_mailbox *mbox,
+ void *data,
+ size_t length)
+{
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ struct device *dev = mbox->dev;
+ long timeout = msecs_to_jiffies(MAILBOX_SEND_TIMEOUT_MS);
+ bool try_send = !wq_has_sleeper(&mbox->send_queue);
+ int ret;
+
+ might_sleep();
+
+ /* Exclusive wait to only wake up one task at a time */
+ add_wait_queue_exclusive(&mbox->send_queue, &wait);
+ for (;;) {
+ /* Stop if the mailbox is closing down */
+ if (atomic_read(&mbox->done)) {
+ ret = -ENODEV;
+ break;
+ }
+
+ /* Attempt to send if queue is empty or task was woken up */
+ if (try_send) {
+ ret = rpmsg_trysend(mbox->ept, data, length);
+ if (ret != -ENOMEM)
+ break;
+ } else {
+ try_send = true;
+ }
+
+ /* Unlock device mutex while waiting to not block other tasks */
+ device_unlock(dev);
+ timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout);
+ device_lock(dev);
+
+ /* Stop if the wait was interrupted */
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+
+ if (!timeout) {
+ ret = -ETIME;
+ break;
+ }
+ }
+
+ remove_wait_queue(&mbox->send_queue, &wait);
+
+ /*
+ * If the message was sent successfully, there may be more TX buffers
+ * available so wake up the next waiting task.
+ */
+ if (!ret && wq_has_sleeper(&mbox->send_queue))
+ wake_up(&mbox->send_queue);
+
+ return ret;
+}
+
+static void ethosu_core_buffer_dma_mem_set(struct ethosu_dma_mem *dma_mem,
+ struct ethosu_core_buffer *cbuf)
+{
+ cbuf->ptr = (uint32_t)dma_mem->dma_addr;
+ cbuf->size = (uint32_t)dma_mem->size;
+}
+
+int ethosu_mailbox_register(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg)
+{
+ WARN_ON_ONCE(!mutex_is_locked(&mbox->dev->mutex));
+ msg->id = idr_alloc_cyclic(&mbox->msg_idr, msg, 0, INT_MAX, GFP_KERNEL);
+ if (msg->id < 0)
+ return msg->id;
+
+ return 0;
+}
+
+void ethosu_mailbox_deregister(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg)
+{
+ WARN_ON_ONCE(!mutex_is_locked(&mbox->dev->mutex));
+ idr_remove(&mbox->msg_idr, msg->id);
+}
+
+struct ethosu_mailbox_msg *ethosu_mailbox_find(struct ethosu_mailbox *mbox,
+ int msg_id,
+ uint32_t msg_type)
+{
+ struct ethosu_mailbox_msg *ptr;
+
+ WARN_ON_ONCE(!mutex_is_locked(&mbox->dev->mutex));
+ ptr = (struct ethosu_mailbox_msg *)idr_find(&mbox->msg_idr, msg_id);
+
+ if (ptr == NULL)
+ return ERR_PTR(-ENOENT);
+
+ if (ptr->type != msg_type)
+ return ERR_PTR(-EINVAL);
+
+ return ptr;
+}
+
+void ethosu_mailbox_fail(struct ethosu_mailbox *mbox)
+{
+ struct ethosu_mailbox_msg *cur;
+ int id;
+
+ WARN_ON_ONCE(!mutex_is_locked(&mbox->dev->mutex));
+ idr_for_each_entry(&mbox->msg_idr, cur, id) {
+ cur->fail(cur);
+ }
+}
+
+int ethosu_mailbox_ping(struct ethosu_mailbox *mbox)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_PING,
+ }
+ };
+
+ return ethosu_send_locked(mbox, &rpmsg, sizeof(rpmsg.header));
+}
+
+int ethosu_mailbox_pong(struct ethosu_mailbox *mbox)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_PONG,
+ }
+ };
+
+ return ethosu_send_locked(mbox, &rpmsg, sizeof(rpmsg.header));
+}
+
+int ethosu_mailbox_version_request(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_VERSION_REQ,
+ .msg_id = msg->id
+ }
+ };
+
+ msg->type = rpmsg.header.type;
+
+ return ethosu_send_locked(mbox, &rpmsg, sizeof(rpmsg.header));
+}
+
+int ethosu_mailbox_capabilities_request(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_CAPABILITIES_REQ,
+ .msg_id = msg->id
+ }
+ };
+
+ msg->type = rpmsg.header.type;
+
+ return ethosu_send_locked(mbox, &rpmsg, sizeof(rpmsg.header));
+}
+
+int ethosu_mailbox_inference(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg,
+ uint32_t ifm_count,
+ struct ethosu_buffer **ifm,
+ uint32_t ofm_count,
+ struct ethosu_buffer **ofm,
+ struct ethosu_network *network,
+ uint8_t *pmu_event_config,
+ uint8_t pmu_event_config_count,
+ uint8_t pmu_cycle_counter_enable)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_INFERENCE_REQ,
+ .msg_id = msg->id
+ }
+ };
+ struct ethosu_core_msg_inference_req *inf_req = &rpmsg.inf_req;
+ uint32_t i;
+
+ msg->type = rpmsg.header.type;
+
+ /* 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.");
+
+ return -EINVAL;
+ }
+
+ inf_req->ifm_count = ifm_count;
+ inf_req->ofm_count = ofm_count;
+ inf_req->pmu_cycle_counter_enable = pmu_cycle_counter_enable;
+
+ for (i = 0; i < ifm_count; i++)
+ ethosu_core_buffer_dma_mem_set(ifm[i]->dma_mem,
+ &inf_req->ifm[i]);
+
+ for (i = 0; i < ofm_count; i++)
+ ethosu_core_buffer_dma_mem_set(ofm[i]->dma_mem,
+ &inf_req->ofm[i]);
+
+ for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++)
+ inf_req->pmu_event_config[i] = pmu_event_config[i];
+
+ if (network->dma_mem != NULL) {
+ inf_req->network.type = ETHOSU_CORE_NETWORK_BUFFER;
+ ethosu_core_buffer_dma_mem_set(network->dma_mem,
+ &inf_req->network.buffer);
+ } else {
+ inf_req->network.type = ETHOSU_CORE_NETWORK_INDEX;
+ inf_req->network.index = network->index;
+ }
+
+ return ethosu_send_locked(mbox, &rpmsg,
+ sizeof(rpmsg.header) + sizeof(rpmsg.inf_req));
+}
+
+int ethosu_mailbox_network_info_request(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg,
+ struct ethosu_network *network)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type = ETHOSU_CORE_MSG_NETWORK_INFO_REQ,
+ .msg_id = msg->id
+ }
+ };
+ struct ethosu_core_msg_network_info_req *info_req = &rpmsg.net_info_req;
+
+ msg->type = rpmsg.header.type;
+
+ if (network->dma_mem != NULL) {
+ info_req->network.type = ETHOSU_CORE_NETWORK_BUFFER;
+ ethosu_core_buffer_dma_mem_set(network->dma_mem,
+ &info_req->network.buffer);
+ } else {
+ info_req->network.type = ETHOSU_CORE_NETWORK_INDEX;
+ info_req->network.index = network->index;
+ }
+
+ return ethosu_send_locked(mbox, &rpmsg,
+ sizeof(rpmsg.header) +
+ sizeof(rpmsg.net_info_req));
+}
+
+int ethosu_mailbox_cancel_inference(struct ethosu_mailbox *mbox,
+ struct ethosu_mailbox_msg *msg,
+ int inference_handle)
+{
+ struct ethosu_core_rpmsg rpmsg = {
+ .header = {
+ .magic = ETHOSU_CORE_MSG_MAGIC,
+ .type =
+ ETHOSU_CORE_MSG_CANCEL_INFERENCE_REQ,
+ .msg_id = msg->id
+ },
+ .cancel_req = {
+ .inference_handle = inference_handle
+ }
+ };
+
+ msg->type = rpmsg.header.type;
+
+ return ethosu_send_locked(mbox, &rpmsg,
+ sizeof(rpmsg.header) +
+ sizeof(rpmsg.cancel_req));
+}
+
+int ethosu_mailbox_init(struct ethosu_mailbox *mbox,
+ struct device *dev,
+ struct rpmsg_endpoint *ept)
+{
+ mbox->dev = dev;
+ mbox->ept = ept;
+ idr_init(&mbox->msg_idr);
+ init_waitqueue_head(&mbox->send_queue);
+
+ return 0;
+}
+
+void ethosu_mailbox_deinit(struct ethosu_mailbox *mbox)
+{
+ atomic_set(&mbox->done, 1);
+ wake_up_all(&mbox->send_queue);
+}