blob: 58d5c770ee89d88886863f61288bff5a492bb7a0 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Ledion Dajaedd25502023-10-17 09:15:32 +02002 * SPDX-FileCopyrightText: Copyright 2020,2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
3 * SPDX-License-Identifier: GPL-2.0-only
Kristofer Jonsson116a6352020-08-20 17:25:23 +02004 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, you can access it online at
17 * http://www.gnu.org/licenses/gpl-2.0.html.
Kristofer Jonsson116a6352020-08-20 17:25:23 +020018 */
19
20/****************************************************************************
21 * Includes
22 ****************************************************************************/
23
24#include "ethosu_network.h"
25
Kristofer Jonsson116a6352020-08-20 17:25:23 +020026#include "ethosu_device.h"
Mikael Olssonc081e592023-10-30 11:10:56 +010027#include "ethosu_dma_mem.h"
Kristofer Jonsson116a6352020-08-20 17:25:23 +020028#include "ethosu_inference.h"
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +010029#include "ethosu_network_info.h"
Kristofer Jonsson116a6352020-08-20 17:25:23 +020030#include "uapi/ethosu.h"
31
32#include <linux/anon_inodes.h>
33#include <linux/file.h>
34#include <linux/fs.h>
35#include <linux/uaccess.h>
36
37/****************************************************************************
38 * Variables
39 ****************************************************************************/
40
41static int ethosu_network_release(struct inode *inode,
42 struct file *file);
43
44static long ethosu_network_ioctl(struct file *file,
45 unsigned int cmd,
46 unsigned long arg);
47
48static const struct file_operations ethosu_network_fops = {
49 .release = &ethosu_network_release,
50 .unlocked_ioctl = &ethosu_network_ioctl,
51#ifdef CONFIG_COMPAT
52 .compat_ioctl = &ethosu_network_ioctl,
53#endif
54};
55
56/****************************************************************************
57 * Functions
58 ****************************************************************************/
59
60static bool ethosu_network_verify(struct file *file)
61{
62 return file->f_op == &ethosu_network_fops;
63}
64
65static void ethosu_network_destroy(struct kref *kref)
66{
67 struct ethosu_network *net =
68 container_of(kref, struct ethosu_network, kref);
Kristofer Jonssonec477042023-01-20 13:38:13 +010069 struct device *dev = net->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020070
Ledion Dajaedd25502023-10-17 09:15:32 +020071 dev_dbg(dev, "Network destroy. net=0x%pK\n", net);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020072
Mikael Olssonc081e592023-10-30 11:10:56 +010073 if (net->dma_mem != NULL)
74 ethosu_dma_mem_free(&net->dma_mem);
Kristofer Jonsson35de9e62022-03-08 13:25:45 +010075
Mikael Olsson1182f382023-08-10 13:25:44 +020076 memset(net, 0, sizeof(*net));
Kristofer Jonssonec477042023-01-20 13:38:13 +010077 devm_kfree(dev, net);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020078}
79
80static int ethosu_network_release(struct inode *inode,
81 struct file *file)
82{
83 struct ethosu_network *net = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +010084 struct device *dev = net->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020085
Ledion Dajaedd25502023-10-17 09:15:32 +020086 dev_dbg(dev, "Network release. file=0x%pK, net=0x%pK\n",
87 file, net);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020088
89 ethosu_network_put(net);
90
91 return 0;
92}
93
94static long ethosu_network_ioctl(struct file *file,
95 unsigned int cmd,
96 unsigned long arg)
97{
98 struct ethosu_network *net = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +010099 struct device *dev = net->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200100 void __user *udata = (void __user *)arg;
Mikael Olsson891156d2023-08-24 13:20:31 +0200101 int ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200102
Kristofer Jonssonec477042023-01-20 13:38:13 +0100103 ret = device_lock_interruptible(net->dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200104 if (ret)
105 return ret;
106
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200107 switch (cmd) {
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100108 case ETHOSU_IOCTL_NETWORK_INFO: {
Mikael Olssonec902232023-08-24 13:28:19 +0200109 struct ethosu_uapi_network_info uapi = { 0 };
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100110
Ledion Dajaedd25502023-10-17 09:15:32 +0200111 dev_dbg(dev, "Network ioctl: Network info. net=0x%pK\n", net);
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100112
Mikael Olsson52c563d2023-08-24 13:28:35 +0200113 ret = ethosu_network_info_request(dev, net->mailbox, net,
114 &uapi);
Kristofer Jonsson3c6a2602022-03-10 11:17:29 +0100115 if (ret)
116 break;
117
118 ret = copy_to_user(udata, &uapi, sizeof(uapi)) ? -EFAULT : 0;
119 break;
120 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200121 case ETHOSU_IOCTL_INFERENCE_CREATE: {
122 struct ethosu_uapi_inference_create uapi;
123
Mikael Olsson891156d2023-08-24 13:20:31 +0200124 if (copy_from_user(&uapi, udata, sizeof(uapi))) {
125 ret = -EFAULT;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200126 break;
Mikael Olsson891156d2023-08-24 13:20:31 +0200127 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200128
Ledion Dajaedd25502023-10-17 09:15:32 +0200129 dev_dbg(dev,
130 "Network ioctl: Inference. ifm_fd=%u, ofm_fd=%u\n",
131 uapi.ifm_fd[0], uapi.ofm_fd[0]);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200132
Kristofer Jonssonec477042023-01-20 13:38:13 +0100133 ret = ethosu_inference_create(dev, net->mailbox, net, &uapi);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200134 break;
135 }
136 default: {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100137 dev_err(dev, "Invalid ioctl. cmd=%u, arg=%lu",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200138 cmd, arg);
Mikael Olsson891156d2023-08-24 13:20:31 +0200139 ret = -ENOIOCTLCMD;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200140 break;
141 }
142 }
143
Kristofer Jonssonec477042023-01-20 13:38:13 +0100144 device_unlock(net->dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200145
146 return ret;
147}
148
Kristofer Jonssonec477042023-01-20 13:38:13 +0100149int ethosu_network_create(struct device *dev,
150 struct ethosu_mailbox *mailbox,
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200151 struct ethosu_uapi_network_create *uapi)
152{
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200153 struct ethosu_network *net;
Mikael Olssonc081e592023-10-30 11:10:56 +0100154 const void __user *data;
155 int ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200156
Kristofer Jonssonec477042023-01-20 13:38:13 +0100157 net = devm_kzalloc(dev, sizeof(*net), GFP_KERNEL);
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100158 if (!net)
159 return -ENOMEM;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200160
Kristofer Jonssonec477042023-01-20 13:38:13 +0100161 net->dev = dev;
162 net->mailbox = mailbox;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 kref_init(&net->kref);
164
Mikael Olsson45d47992023-10-12 15:32:56 +0200165 switch (uapi->type) {
Mikael Olssonc081e592023-10-30 11:10:56 +0100166 case ETHOSU_UAPI_NETWORK_USER_BUFFER:
167 if (!uapi->network.data_ptr) {
168 dev_err(dev, "Invalid network data ptr\n");
169 ret = -EINVAL;
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100170 goto free_net;
171 }
Mikael Olsson45d47992023-10-12 15:32:56 +0200172
Mikael Olssonc081e592023-10-30 11:10:56 +0100173 if (!uapi->network.size) {
174 dev_err(dev, "Invalid network data size\n");
175 ret = -EINVAL;
176 goto free_net;
177 }
178
179 net->dma_mem = ethosu_dma_mem_alloc(dev, uapi->network.size);
180 if (IS_ERR(net->dma_mem)) {
181 ret = PTR_ERR(net->dma_mem);
182 goto free_net;
183 }
184
185 data = u64_to_user_ptr(uapi->network.data_ptr);
186 ret = copy_from_user(net->dma_mem->cpu_addr, data,
187 uapi->network.size);
188 if (ret)
189 goto free_dma_mem;
190
Mikael Olsson45d47992023-10-12 15:32:56 +0200191 break;
192 case ETHOSU_UAPI_NETWORK_INDEX:
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100193 net->index = uapi->index;
Mikael Olsson45d47992023-10-12 15:32:56 +0200194 break;
195 default:
196 ret = -EINVAL;
197 goto free_net;
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100198 }
199
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200200 ret = anon_inode_getfd("ethosu-network", &ethosu_network_fops, net,
201 O_RDWR | O_CLOEXEC);
202 if (ret < 0)
Mikael Olssonc081e592023-10-30 11:10:56 +0100203 goto free_dma_mem;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200204
205 net->file = fget(ret);
206 fput(net->file);
207
Ledion Dajaedd25502023-10-17 09:15:32 +0200208 dev_dbg(dev,
209 "Network create. file=0x%pK, fd=%d, net=0x%pK, buf=0x%pK, index=%u",
Mikael Olssonc081e592023-10-30 11:10:56 +0100210 net->file, ret, net, net->dma_mem, net->index);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200211
212 return ret;
213
Mikael Olssonc081e592023-10-30 11:10:56 +0100214free_dma_mem:
215 if (net->dma_mem != NULL)
216 ethosu_dma_mem_free(&net->dma_mem);
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100217
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218free_net:
Mikael Olsson1182f382023-08-10 13:25:44 +0200219 memset(net, 0, sizeof(*net));
Kristofer Jonssonec477042023-01-20 13:38:13 +0100220 devm_kfree(dev, net);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200221
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200222 return ret;
223}
224
225struct ethosu_network *ethosu_network_get_from_fd(int fd)
226{
227 struct ethosu_network *net;
228 struct file *file;
229
230 file = fget(fd);
231 if (!file)
232 return ERR_PTR(-EINVAL);
233
234 if (!ethosu_network_verify(file)) {
235 fput(file);
236
237 return ERR_PTR(-EINVAL);
238 }
239
240 net = file->private_data;
241 ethosu_network_get(net);
242 fput(file);
243
244 return net;
245}
246
247void ethosu_network_get(struct ethosu_network *net)
248{
249 kref_get(&net->kref);
250}
251
Kristofer Jonsson442fefb2022-03-17 17:15:52 +0100252int ethosu_network_put(struct ethosu_network *net)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200253{
Kristofer Jonsson442fefb2022-03-17 17:15:52 +0100254 return kref_put(&net->kref, ethosu_network_destroy);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200255}