aboutsummaryrefslogtreecommitdiff
path: root/kernel/rpmsg/ethosu_rpmsg_network_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rpmsg/ethosu_rpmsg_network_info.c')
-rw-r--r--kernel/rpmsg/ethosu_rpmsg_network_info.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/kernel/rpmsg/ethosu_rpmsg_network_info.c b/kernel/rpmsg/ethosu_rpmsg_network_info.c
new file mode 100644
index 0000000..0e54d87
--- /dev/null
+++ b/kernel/rpmsg/ethosu_rpmsg_network_info.c
@@ -0,0 +1,187 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2022-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_network_info.h>
+
+#include <common/ethosu_device.h>
+#include <rpmsg/ethosu_rpmsg_network.h>
+#include <uapi/ethosu.h>
+
+#include <linux/bug.h>
+
+#define NETWORK_INFO_RESP_TIMEOUT_MS 3000
+
+static inline int ethosu_network_info_send(struct ethosu_network_info *info,
+ struct ethosu_mailbox *mailbox)
+{
+ /* Send network info request to firmware */
+ return ethosu_mailbox_network_info_request(mailbox,
+ &info->msg,
+ info->net);
+}
+
+static void ethosu_network_info_fail(struct ethosu_mailbox_msg *msg)
+{
+ struct ethosu_network_info *info =
+ container_of(msg, typeof(*info), msg);
+
+ if (completion_done(&info->done))
+ return;
+
+ info->errno = -EFAULT;
+ complete(&info->done);
+}
+
+int ethosu_network_info_request(struct device *dev,
+ struct ethosu_mailbox *mailbox,
+ struct ethosu_network *net,
+ struct ethosu_uapi_network_info *uapi)
+{
+ struct ethosu_network_info *info;
+ int ret;
+ int timeout;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = dev;
+ info->net = net;
+ info->uapi = uapi;
+ init_completion(&info->done);
+ info->msg.fail = ethosu_network_info_fail;
+
+ ret = ethosu_mailbox_register(mailbox, &info->msg);
+ if (ret < 0)
+ goto kfree;
+
+ /* Get reference to network */
+ ethosu_network_get(info->net);
+
+ ret = ethosu_network_info_send(info, mailbox);
+ if (ret)
+ goto deregister;
+
+ dev_dbg(dev,
+ "Network info create. info=0x%pK, net=0x%pK, msg.id=0x%x\n",
+ info, info->net, info->msg.id);
+
+ /* Unlock the device mutex and wait for completion */
+ device_unlock(dev);
+ timeout = wait_for_completion_timeout(&info->done,
+ msecs_to_jiffies(
+ NETWORK_INFO_RESP_TIMEOUT_MS));
+ device_lock(dev);
+
+ if (0 == timeout) {
+ dev_warn(dev, "Network info timed out. info=0x%pK",
+ info);
+
+ ret = -ETIME;
+ goto deregister;
+ }
+
+ ret = info->errno;
+
+deregister:
+ ethosu_mailbox_deregister(mailbox, &info->msg);
+ ethosu_network_put(info->net);
+
+kfree:
+ dev_dbg(dev,
+ "Network info destroy. info=0x%pK, msg.id=0x%x\n",
+ info, info->msg.id);
+ devm_kfree(dev, info);
+
+ return ret;
+}
+
+void ethosu_network_info_rsp(struct ethosu_mailbox *mailbox,
+ int msg_id,
+ struct ethosu_core_msg_network_info_rsp *rsp)
+{
+ int ret;
+ struct device *dev = mailbox->dev;
+ struct ethosu_mailbox_msg *msg;
+ struct ethosu_network_info *info;
+ uint32_t i;
+ const size_t rsp_desc_size = sizeof(rsp->desc);
+
+ BUILD_BUG_ON(rsp_desc_size != sizeof(info->uapi->desc));
+
+ msg = ethosu_mailbox_find(mailbox, msg_id,
+ ETHOSU_CORE_MSG_NETWORK_INFO_REQ);
+ if (IS_ERR(msg)) {
+ dev_warn(dev,
+ "Id for network info msg not found. Id=0x%x: %ld\n",
+ msg_id, PTR_ERR(msg));
+
+ return;
+ }
+
+ info = container_of(msg, typeof(*info), msg);
+
+ if (completion_done(&info->done))
+ return;
+
+ info->errno = 0;
+
+ if (rsp->status != ETHOSU_CORE_STATUS_OK) {
+ dev_err(dev, "Failed to get information about the network\n");
+ info->errno = -EBADF;
+ goto signal_complete;
+ }
+
+ if (rsp->ifm_count > ETHOSU_FD_MAX || rsp->ofm_count > ETHOSU_FD_MAX) {
+ dev_err(dev,
+ "Invalid number of IFMs/OFMs in network info: IFMs=%u OFMs=%u\n",
+ rsp->ifm_count, rsp->ofm_count);
+ info->errno = -ENFILE;
+ goto signal_complete;
+ }
+
+ if (strnlen(rsp->desc, rsp_desc_size) == rsp_desc_size) {
+ dev_err(dev,
+ "Description in network info is not null-terminated\n");
+ info->errno = -EMSGSIZE;
+ goto signal_complete;
+ }
+
+ ret = strscpy(info->uapi->desc, rsp->desc, sizeof(info->uapi->desc));
+ if (ret < 0) {
+ dev_err(dev, "Failed to copy network info description\n");
+ info->errno = ret;
+ goto signal_complete;
+ }
+
+ info->uapi->ifm_count = rsp->ifm_count;
+ for (i = 0; i < rsp->ifm_count; i++)
+ info->uapi->ifm_size[i] = rsp->ifm_size[i];
+
+ info->uapi->ofm_count = rsp->ofm_count;
+ for (i = 0; i < rsp->ofm_count; i++)
+ info->uapi->ofm_size[i] = rsp->ofm_size[i];
+
+signal_complete:
+ complete(&info->done);
+}