blob: 0df6c0727c518783ce43d698e5d6e639436afee7 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Kristofer Jonssonb42bc0b2023-01-04 17:09:28 +01002 * Copyright 2020-2023 Arm Limited and/or its affiliates
Kristofer Jonsson116a6352020-08-20 17:25:23 +02003 *
4 * This program is free software and is provided to you under the terms of the
5 * GNU General Public License version 2 as published by the Free Software
6 * Foundation, and any use by you of this program is subject to the terms
7 * of such GNU licence.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * SPDX-License-Identifier: GPL-2.0-only
19 */
20
21/****************************************************************************
22 * Includes
23 ****************************************************************************/
24
25#include "ethosu_device.h"
26
27#include "ethosu_buffer.h"
Kristofer Jonssond779a082023-01-04 17:09:47 +010028#include "ethosu_core_rpmsg.h"
Davide Grohmann32660f92022-04-27 16:49:07 +020029#include "ethosu_capabilities.h"
Kristofer Jonsson116a6352020-08-20 17:25:23 +020030#include "ethosu_inference.h"
Davide Grohmann7e8f5082022-03-23 12:48:45 +010031#include "ethosu_cancel_inference.h"
Kristofer Jonsson116a6352020-08-20 17:25:23 +020032#include "ethosu_network.h"
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +010033#include "ethosu_network_info.h"
Mikael Olsson7c843dc2023-08-03 12:41:48 +020034#include "ethosu_version.h"
Kristofer Jonsson116a6352020-08-20 17:25:23 +020035#include "uapi/ethosu.h"
36
Mikael Olsson099d90c2023-05-02 10:39:22 +020037#include <linux/dma-mapping.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020038#include <linux/errno.h>
39#include <linux/fs.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020040#include <linux/io.h>
41#include <linux/of_reserved_mem.h>
Kristofer Jonssonec477042023-01-20 13:38:13 +010042#include <linux/remoteproc.h>
Davide Grohmann35ce6c82021-06-01 15:03:51 +020043#include <linux/slab.h>
Kristofer Jonsson442fefb2022-03-17 17:15:52 +010044#include <linux/uaccess.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020045
46/****************************************************************************
Kristofer Jonsson074ef902023-01-23 13:05:36 +010047 * Defines
48 ****************************************************************************/
49
50#define MINOR_BASE 0 /* Minor version starts at 0 */
51#define MINOR_COUNT 64 /* Allocate minor versions */
52
Mikael Olsson099d90c2023-05-02 10:39:22 +020053#define DMA_ADDR_BITS 32 /* Number of address bits */
54
Kristofer Jonsson074ef902023-01-23 13:05:36 +010055/****************************************************************************
56 * Variables
57 ****************************************************************************/
58
59static DECLARE_BITMAP(minors, MINOR_COUNT);
60
61/****************************************************************************
Kristofer Jonsson116a6352020-08-20 17:25:23 +020062 * Functions
63 ****************************************************************************/
64
Jonny Svärd7c24c772021-01-14 19:53:17 +010065/* Incoming messages */
Kristofer Jonssonec477042023-01-20 13:38:13 +010066static int ethosu_handle_rpmsg(struct rpmsg_device *rpdev,
67 void *data,
68 int len,
69 void *priv,
70 u32 src)
Kristofer Jonsson116a6352020-08-20 17:25:23 +020071{
Kristofer Jonssond779a082023-01-04 17:09:47 +010072 struct ethosu_device *edev = dev_get_drvdata(&rpdev->dev);
Kristofer Jonsson074ef902023-01-23 13:05:36 +010073 struct device *dev = &edev->dev;
Kristofer Jonssond779a082023-01-04 17:09:47 +010074 struct ethosu_core_rpmsg *rpmsg = data;
75 int length = len - sizeof(rpmsg->header);
Jonny Svärd7c24c772021-01-14 19:53:17 +010076 int ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020077
Mikael Olssonfd6b8dc2023-05-10 14:46:30 +020078 if (unlikely(rpmsg->header.magic != ETHOSU_CORE_MSG_MAGIC)) {
79 dev_warn(dev, "Msg: Error invalid message magic. magic=0x%08x",
80 rpmsg->header.magic);
81
82 return -EBADMSG;
83 }
84
Mikael Olsson5fcc28c2023-05-16 16:53:09 +020085 device_lock(dev);
86
Kristofer Jonssond779a082023-01-04 17:09:47 +010087 dev_info(dev,
88 "Msg: magic=0x%08x, type=%u, msg_id=%llu",
89 rpmsg->header.magic, rpmsg->header.type, rpmsg->header.msg_id);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020090
Kristofer Jonssond779a082023-01-04 17:09:47 +010091 switch (rpmsg->header.type) {
Kristofer Jonsson074ef902023-01-23 13:05:36 +010092 case ETHOSU_CORE_MSG_ERR:
Kristofer Jonssond779a082023-01-04 17:09:47 +010093 if (length != sizeof(rpmsg->error)) {
94 dev_warn(dev,
95 "Msg: Error message of incorrect size. size=%u, expected=%zu", length,
96 sizeof(rpmsg->error));
Jonny Svärd7c24c772021-01-14 19:53:17 +010097 ret = -EBADMSG;
98 break;
99 }
100
Kristofer Jonssond779a082023-01-04 17:09:47 +0100101 rpmsg->error.msg[sizeof(rpmsg->error.msg) - 1] = '\0';
102 dev_warn(dev, "Msg: Error. type=%u, msg=\"%s\"",
103 rpmsg->error.type, rpmsg->error.msg);
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100104
105 rproc_report_crash(rproc_get_by_child(dev), RPROC_FATAL_ERROR);
Jonny Svärd7c24c772021-01-14 19:53:17 +0100106 break;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200107 case ETHOSU_CORE_MSG_PING:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100108 dev_info(dev, "Msg: Ping");
Jonny Svärd7c24c772021-01-14 19:53:17 +0100109 ret = ethosu_mailbox_pong(&edev->mailbox);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200110 break;
111 case ETHOSU_CORE_MSG_PONG:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100112 dev_info(dev, "Msg: Pong");
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200113 break;
114 case ETHOSU_CORE_MSG_INFERENCE_RSP:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100115 if (length != sizeof(rpmsg->inf_rsp)) {
116 dev_warn(dev,
117 "Msg: Inference response of incorrect size. size=%u, expected=%zu", length,
118 sizeof(rpmsg->inf_rsp));
Jonny Svärd7c24c772021-01-14 19:53:17 +0100119 ret = -EBADMSG;
120 break;
121 }
122
Kristofer Jonssond779a082023-01-04 17:09:47 +0100123 dev_info(dev,
124 "Msg: Inference response. ofm_count=%u, status=%u",
125 rpmsg->inf_rsp.ofm_count, rpmsg->inf_rsp.status);
Kristofer Jonsson442fefb2022-03-17 17:15:52 +0100126
Kristofer Jonssonec477042023-01-20 13:38:13 +0100127 ethosu_inference_rsp(&edev->mailbox, rpmsg->header.msg_id,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100128 &rpmsg->inf_rsp);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200129 break;
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100130 case ETHOSU_CORE_MSG_CANCEL_INFERENCE_RSP:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100131 if (length != sizeof(rpmsg->cancel_rsp)) {
132 dev_warn(dev,
133 "Msg: Cancel Inference response of incorrect size. size=%u, expected=%zu", length,
134 sizeof(rpmsg->cancel_rsp));
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100135 ret = -EBADMSG;
136 break;
137 }
138
Kristofer Jonssond779a082023-01-04 17:09:47 +0100139 dev_info(dev,
140 "Msg: Cancel Inference response. status=%u",
141 rpmsg->cancel_rsp.status);
Kristofer Jonssonec477042023-01-20 13:38:13 +0100142 ethosu_cancel_inference_rsp(&edev->mailbox,
143 rpmsg->header.msg_id,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100144 &rpmsg->cancel_rsp);
Davide Grohmann7e8f5082022-03-23 12:48:45 +0100145 break;
Jonny Svärd7c24c772021-01-14 19:53:17 +0100146 case ETHOSU_CORE_MSG_VERSION_RSP:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100147 if (length != sizeof(rpmsg->version_rsp)) {
148 dev_warn(dev,
Mikael Olsson7c843dc2023-08-03 12:41:48 +0200149 "Msg: Protocol version response of incorrect size. size=%u, expected=%zu", length,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100150 sizeof(rpmsg->version_rsp));
Jonny Svärd7c24c772021-01-14 19:53:17 +0100151 ret = -EBADMSG;
152 break;
153 }
154
Mikael Olsson7c843dc2023-08-03 12:41:48 +0200155 dev_dbg(dev, "Msg: Protocol version response %u.%u.%u",
156 rpmsg->version_rsp.major, rpmsg->version_rsp.minor,
157 rpmsg->version_rsp.patch);
Jonny Svärd7c24c772021-01-14 19:53:17 +0100158
Mikael Olsson7c843dc2023-08-03 12:41:48 +0200159 ethosu_version_rsp(&edev->mailbox, rpmsg->header.msg_id,
160 &rpmsg->version_rsp);
Jonny Svärd7c24c772021-01-14 19:53:17 +0100161 break;
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200162 case ETHOSU_CORE_MSG_CAPABILITIES_RSP:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100163 if (length != sizeof(rpmsg->cap_rsp)) {
164 dev_warn(dev,
165 "Msg: Capabilities response of incorrect size. size=%u, expected=%zu", length,
166 sizeof(rpmsg->cap_rsp));
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200167 ret = -EBADMSG;
168 break;
169 }
Jonny Svärd7c24c772021-01-14 19:53:17 +0100170
Kristofer Jonssond779a082023-01-04 17:09:47 +0100171 dev_info(dev,
172 "Msg: Capabilities response vs%hhu v%hhu.%hhu p%hhu av%hhu.%hhu.%hhu dv%hhu.%hhu.%hhu mcc%hhu csv%hhu cd%hhu",
173 rpmsg->cap_rsp.version_status,
174 rpmsg->cap_rsp.version_major,
175 rpmsg->cap_rsp.version_minor,
176 rpmsg->cap_rsp.product_major,
177 rpmsg->cap_rsp.arch_major_rev,
178 rpmsg->cap_rsp.arch_minor_rev,
179 rpmsg->cap_rsp.arch_patch_rev,
180 rpmsg->cap_rsp.driver_major_rev,
181 rpmsg->cap_rsp.driver_minor_rev,
182 rpmsg->cap_rsp.driver_patch_rev,
183 rpmsg->cap_rsp.macs_per_cc,
184 rpmsg->cap_rsp.cmd_stream_version,
185 rpmsg->cap_rsp.custom_dma);
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200186
Kristofer Jonssonec477042023-01-20 13:38:13 +0100187 ethosu_capability_rsp(&edev->mailbox, rpmsg->header.msg_id,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100188 &rpmsg->cap_rsp);
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200189 break;
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100190 case ETHOSU_CORE_MSG_NETWORK_INFO_RSP:
Kristofer Jonssond779a082023-01-04 17:09:47 +0100191 if (length != sizeof(rpmsg->net_info_rsp)) {
192 dev_warn(dev,
193 "Msg: Network info response of incorrect size. size=%u, expected=%zu", length,
194 sizeof(rpmsg->net_info_rsp));
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100195 ret = -EBADMSG;
196 break;
197 }
198
Kristofer Jonssond779a082023-01-04 17:09:47 +0100199 dev_info(dev,
200 "Msg: Network info response. status=%u",
201 rpmsg->net_info_rsp.status);
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100202
Kristofer Jonssonec477042023-01-20 13:38:13 +0100203 ethosu_network_info_rsp(&edev->mailbox,
204 rpmsg->header.msg_id,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100205 &rpmsg->net_info_rsp);
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100206
207 break;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200208 default:
Jonny Svärd7c24c772021-01-14 19:53:17 +0100209 /* This should not happen due to version checks */
Kristofer Jonssond779a082023-01-04 17:09:47 +0100210 dev_warn(dev, "Msg: Protocol error. type=%u",
211 rpmsg->header.type);
Jonny Svärd7c24c772021-01-14 19:53:17 +0100212 ret = -EPROTO;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200213 break;
214 }
215
Mikael Olsson5fcc28c2023-05-16 16:53:09 +0200216 device_unlock(dev);
217
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218 return ret;
219}
220
221static int ethosu_open(struct inode *inode,
222 struct file *file)
223{
Kristofer Jonssonec477042023-01-20 13:38:13 +0100224 struct cdev *cdev = inode->i_cdev;
225 struct ethosu_device *edev = container_of(cdev, struct ethosu_device,
226 cdev);
227 struct rpmsg_device *rpdev = edev->rpdev;
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100228 struct device *dev = &edev->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200229
Kristofer Jonssonec477042023-01-20 13:38:13 +0100230 dev_info(dev, "Device open. file=0x%pK", file);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200231
Kristofer Jonssonec477042023-01-20 13:38:13 +0100232 file->private_data = rpdev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200233
234 return nonseekable_open(inode, file);
235}
236
237static long ethosu_ioctl(struct file *file,
238 unsigned int cmd,
239 unsigned long arg)
240{
Kristofer Jonssonec477042023-01-20 13:38:13 +0100241 struct rpmsg_device *rpdev = file->private_data;
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100242 struct ethosu_device *edev = dev_get_drvdata(&rpdev->dev);
243 struct device *dev = &edev->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200244 void __user *udata = (void __user *)arg;
245 int ret = -EINVAL;
246
Kristofer Jonssonec477042023-01-20 13:38:13 +0100247 ret = device_lock_interruptible(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200248 if (ret)
249 return ret;
250
Kristofer Jonssonec477042023-01-20 13:38:13 +0100251 dev_info(dev, "Device ioctl. file=0x%pK, cmd=0x%x, arg=0x%lx",
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200252 file, cmd, arg);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200253
254 switch (cmd) {
Davide Grohmann32660f92022-04-27 16:49:07 +0200255 case ETHOSU_IOCTL_CAPABILITIES_REQ: {
Mikael Olsson252ed6a2023-05-29 18:07:55 +0200256 dev_info(dev, "Device ioctl: Capabilities request");
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200257
Mikael Olsson252ed6a2023-05-29 18:07:55 +0200258 ret = copy_to_user(udata, &edev->capabilities,
259 sizeof(edev->capabilities)) ? -EFAULT : 0;
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200260 break;
Davide Grohmann32660f92022-04-27 16:49:07 +0200261 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200262 case ETHOSU_IOCTL_PING: {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100263 dev_info(dev, "Device ioctl: Send ping");
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200264 ret = ethosu_mailbox_ping(&edev->mailbox);
265 break;
266 }
267 case ETHOSU_IOCTL_BUFFER_CREATE: {
268 struct ethosu_uapi_buffer_create uapi;
269
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200270 if (copy_from_user(&uapi, udata, sizeof(uapi)))
271 break;
272
Kristofer Jonssonec477042023-01-20 13:38:13 +0100273 dev_info(dev,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100274 "Device ioctl: Buffer create. capacity=%u",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200275 uapi.capacity);
276
Kristofer Jonssonec477042023-01-20 13:38:13 +0100277 ret = ethosu_buffer_create(dev, uapi.capacity);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200278 break;
279 }
280 case ETHOSU_IOCTL_NETWORK_CREATE: {
281 struct ethosu_uapi_network_create uapi;
282
283 if (copy_from_user(&uapi, udata, sizeof(uapi)))
284 break;
285
Kristofer Jonssonec477042023-01-20 13:38:13 +0100286 dev_info(dev,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100287 "Device ioctl: Network create. type=%u, fd/index=%u",
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200288 uapi.type, uapi.fd);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200289
Kristofer Jonssonec477042023-01-20 13:38:13 +0100290 ret = ethosu_network_create(dev, &edev->mailbox, &uapi);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200291 break;
292 }
293 default: {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100294 dev_err(dev, "Invalid ioctl. cmd=%u, arg=%lu",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200295 cmd, arg);
296 break;
297 }
298 }
299
Kristofer Jonssonec477042023-01-20 13:38:13 +0100300 device_unlock(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200301
302 return ret;
303}
304
Kristofer Jonssond779a082023-01-04 17:09:47 +0100305static struct rpmsg_endpoint *ethosu_create_ept(struct rpmsg_device *rpdev)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200306{
Kristofer Jonssond779a082023-01-04 17:09:47 +0100307 struct device *dev = &rpdev->dev;
308 struct rpmsg_channel_info info;
309 struct rpmsg_endpoint *ept;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200310
Kristofer Jonssond779a082023-01-04 17:09:47 +0100311 /* Create rpmsg endpoint */
312 strncpy(info.name, rpdev->id.name, sizeof(info.name));
313 info.src = 0;
314 info.dst = rpdev->dst;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200315
Kristofer Jonssond779a082023-01-04 17:09:47 +0100316 dev_info(dev, "Creating rpmsg endpoint. name=%s, src=%u, dst=%u",
317 info.name, info.src, info.dst);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200318
Kristofer Jonssonec477042023-01-20 13:38:13 +0100319 ept = rpmsg_create_ept(rpdev, ethosu_handle_rpmsg, NULL, info);
Kristofer Jonssond779a082023-01-04 17:09:47 +0100320 if (!ept) {
321 dev_err(&rpdev->dev, "Failed to create endpoint");
322
323 return ERR_PTR(-EINVAL);
324 }
325
326 return ept;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200327}
328
Kristofer Jonssonec477042023-01-20 13:38:13 +0100329static const struct file_operations fops = {
330 .owner = THIS_MODULE,
331 .open = &ethosu_open,
332 .unlocked_ioctl = &ethosu_ioctl,
333#ifdef CONFIG_COMPAT
334 .compat_ioctl = &ethosu_ioctl,
335#endif
336};
337
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100338static void ethosu_dev_release(struct device *dev)
339{
340 struct ethosu_device *edev = dev_get_drvdata(dev);
341
342 dev_info(dev, "%s", __FUNCTION__);
343
344 clear_bit(MINOR(edev->cdev.dev), minors);
345
346 ethosu_mailbox_deinit(&edev->mailbox);
347 device_destroy(edev->class, edev->cdev.dev);
348 kfree(edev);
349}
350
351static int ethosu_device_register(struct device *dev,
352 struct device *parent,
353 void *drvdata,
354 dev_t devt)
355{
356 struct rproc *rproc = rproc_get_by_child(parent);
357 int ret;
358
359 dev->parent = parent;
360 dev->release = ethosu_dev_release;
361 dev_set_drvdata(dev, drvdata);
362
363 ret = dev_set_name(dev, "ethosu%d", MINOR(devt));
364 if (ret) {
365 dev_err(parent, "Failed to set device name. ret=%d", ret);
366
367 return ret;
368 }
369
370 /* Inherit DMA settings for rproc device */
371 ret = of_reserved_mem_device_init_by_idx(dev,
372 rproc->dev.parent->of_node, 0);
373 if (ret) {
374 dev_err(parent, "Failed to initialize reserved memory. ret=%d",
375 ret);
376
377 return ret;
378 }
379
Mikael Olsson099d90c2023-05-02 10:39:22 +0200380 /* Set mask for coherent DMA addressing */
381 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(DMA_ADDR_BITS));
382 if (ret) {
383 dev_err(parent, "Failed to set coherent DMA mask. ret=%d", ret);
384
385 return ret;
386 }
387
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100388 ret = device_register(dev);
389 if (ret) {
390 dev_err(parent, "Failed to register device. ret=%d", ret);
391
392 return ret;
393 }
394
395 return 0;
396}
397
Kristofer Jonssonec477042023-01-20 13:38:13 +0100398int ethosu_dev_init(struct rpmsg_device *rpdev,
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200399 struct class *class,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100400 dev_t devt)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200401{
Kristofer Jonssonec477042023-01-20 13:38:13 +0100402 struct device *dev = &rpdev->dev;
403 struct ethosu_device *edev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200404 struct device *sysdev;
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100405 int minor;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200406 int ret;
407
Kristofer Jonssonec477042023-01-20 13:38:13 +0100408 dev_info(dev, "%s", __FUNCTION__);
409
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100410 /* Reserve minor number for device node */
411 minor = find_first_zero_bit(minors, MINOR_COUNT);
412 if (minor >= MINOR_COUNT) {
413 dev_err(dev, "No more minor numbers.");
414
415 return -ENOMEM;
416 }
417
418 devt = MKDEV(MAJOR(devt), minor);
419
Kristofer Jonssonec477042023-01-20 13:38:13 +0100420 /* Allocate and create Ethos-U device */
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100421 edev = kzalloc(sizeof(*edev), GFP_KERNEL);
Kristofer Jonssonec477042023-01-20 13:38:13 +0100422 if (!edev)
423 return -ENOMEM;
424
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100425 dev_set_drvdata(&rpdev->dev, edev);
Kristofer Jonssonec477042023-01-20 13:38:13 +0100426
Kristofer Jonssond779a082023-01-04 17:09:47 +0100427 edev->rpdev = rpdev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200428 edev->class = class;
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100429
430 /* Create device object */
431 ret = ethosu_device_register(&edev->dev, &rpdev->dev, edev,
432 devt);
Mikael Olsson229e1252023-06-22 14:34:55 +0200433 if (ret) {
434 kfree(edev);
435
436 return ret;
437 }
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100438
439 /* Continue with new device */
440 dev = &edev->dev;
Kristofer Jonsson442fefb2022-03-17 17:15:52 +0100441
Kristofer Jonssonec477042023-01-20 13:38:13 +0100442 /* Create RPMsg endpoint */
Kristofer Jonssond779a082023-01-04 17:09:47 +0100443 edev->ept = ethosu_create_ept(rpdev);
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100444 if (IS_ERR(edev->ept)) {
445 ret = PTR_ERR(edev->ept);
446 goto device_unregister;
447 }
Kristofer Jonssond779a082023-01-04 17:09:47 +0100448
Kristofer Jonssonec477042023-01-20 13:38:13 +0100449 ret = ethosu_mailbox_init(&edev->mailbox, dev, edev->ept);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200450 if (ret)
Mikael Olsson08c42f52023-06-22 15:13:35 +0200451 goto free_rpmsg_ept;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200452
Mikael Olsson7c843dc2023-08-03 12:41:48 +0200453 device_lock(dev);
454 ret = ethosu_version_check_request(dev, &edev->mailbox);
455 device_unlock(dev);
456 if (ret) {
457 dev_err(dev, "Protocol version check failed: %d", ret);
458 goto deinit_mailbox;
459 }
Mikael Olsson252ed6a2023-05-29 18:07:55 +0200460
461 device_lock(dev);
462 ret = ethosu_capabilities_request(dev, &edev->mailbox,
463 &edev->capabilities);
464 device_unlock(dev);
465 if (ret) {
466 dev_err(dev, "Failed to get device capabilities: %d", ret);
467 goto deinit_mailbox;
468 }
469
Kristofer Jonssonec477042023-01-20 13:38:13 +0100470 /* Create device node */
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200471 cdev_init(&edev->cdev, &fops);
472 edev->cdev.owner = THIS_MODULE;
473
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100474 cdev_set_parent(&edev->cdev, &dev->kobj);
475
476 ret = cdev_add(&edev->cdev, devt, 1);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200477 if (ret) {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100478 dev_err(dev, "Failed to add character device.");
Kristofer Jonsson4aec3762021-10-13 17:09:27 +0200479 goto deinit_mailbox;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200480 }
481
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100482 sysdev = device_create(edev->class, NULL, devt, rpdev,
483 "ethosu%d", MINOR(devt));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200484 if (IS_ERR(sysdev)) {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100485 dev_err(dev, "Failed to create device.");
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200486 ret = PTR_ERR(sysdev);
487 goto del_cdev;
488 }
489
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100490 set_bit(minor, minors);
491
Kristofer Jonssonec477042023-01-20 13:38:13 +0100492 dev_info(dev,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100493 "Created Arm Ethos-U device. name=%s, major=%d, minor=%d",
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100494 dev_name(sysdev), MAJOR(devt), MINOR(devt));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200495
496 return 0;
497
498del_cdev:
499 cdev_del(&edev->cdev);
500
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200501deinit_mailbox:
502 ethosu_mailbox_deinit(&edev->mailbox);
503
Mikael Olsson08c42f52023-06-22 15:13:35 +0200504free_rpmsg_ept:
505 rpmsg_destroy_ept(edev->ept);
506
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100507device_unregister:
508 device_unregister(dev);
509
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200510 return ret;
511}
512
Kristofer Jonssonec477042023-01-20 13:38:13 +0100513void ethosu_dev_deinit(struct rpmsg_device *rpdev)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200514{
Kristofer Jonssonec477042023-01-20 13:38:13 +0100515 struct device *dev = &rpdev->dev;
516 struct ethosu_device *edev = dev_get_drvdata(dev);
517
518 dev_info(dev, "%s", __FUNCTION__);
Kristofer Jonssond779a082023-01-04 17:09:47 +0100519
Mikael Olsson529cfad2023-06-14 17:14:14 +0200520 device_lock(&edev->dev);
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100521 ethosu_mailbox_fail(&edev->mailbox);
Mikael Olsson529cfad2023-06-14 17:14:14 +0200522 device_unlock(&edev->dev);
523
Kristofer Jonssond779a082023-01-04 17:09:47 +0100524 rpmsg_destroy_ept(edev->ept);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200525 cdev_del(&edev->cdev);
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100526 device_unregister(&edev->dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200527}