blob: 17beef421c61c02fc18758641a87e6b5b61d73b8 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Kristofer Jonsson35de9e62022-03-08 13:25:45 +01002 * Copyright (c) 2020, 2022 Arm Limited.
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_inference.h"
26
27#include "ethosu_buffer.h"
28#include "ethosu_core_interface.h"
29#include "ethosu_device.h"
30#include "ethosu_network.h"
31#include "uapi/ethosu.h"
32
33#include <linux/anon_inodes.h>
34#include <linux/file.h>
35#include <linux/fs.h>
36#include <linux/poll.h>
37
38/****************************************************************************
39 * Variables
40 ****************************************************************************/
41
42static int ethosu_inference_release(struct inode *inode,
43 struct file *file);
44
45static unsigned int ethosu_inference_poll(struct file *file,
46 poll_table *wait);
47
48static long ethosu_inference_ioctl(struct file *file,
49 unsigned int cmd,
50 unsigned long arg);
51
52static const struct file_operations ethosu_inference_fops = {
53 .release = &ethosu_inference_release,
54 .poll = &ethosu_inference_poll,
55 .unlocked_ioctl = &ethosu_inference_ioctl,
56#ifdef CONFIG_COMPAT
57 .compat_ioctl = &ethosu_inference_ioctl,
58#endif
59};
60
61/****************************************************************************
62 * Functions
63 ****************************************************************************/
64
65static const char *status_to_string(const enum ethosu_uapi_status status)
66{
67 switch (status) {
68 case ETHOSU_UAPI_STATUS_OK: {
69 return "Ok";
70 }
71 case ETHOSU_UAPI_STATUS_ERROR: {
72 return "Error";
73 }
74 default: {
75 return "Unknown";
76 }
77 }
78}
79
80static int ethosu_inference_send(struct ethosu_inference *inf)
81{
82 int ret;
83
84 if (inf->pending)
85 return -EINVAL;
86
87 inf->status = ETHOSU_UAPI_STATUS_ERROR;
88
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020089 ret = ethosu_mailbox_inference(&inf->edev->mailbox, inf,
90 inf->ifm_count, inf->ifm,
91 inf->ofm_count, inf->ofm,
Per Åstrandf7e407a2020-10-23 21:25:05 +020092 inf->net->buf,
Kristofer Jonsson35de9e62022-03-08 13:25:45 +010093 inf->net->index,
Per Åstrandf7e407a2020-10-23 21:25:05 +020094 inf->pmu_event_config,
95 ETHOSU_PMU_EVENT_MAX,
96 inf->pmu_cycle_counter_enable);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020097 if (ret)
98 return ret;
99
100 inf->pending = true;
101
102 ethosu_inference_get(inf);
103
104 return 0;
105}
106
107static int ethosu_inference_find(struct ethosu_inference *inf,
108 struct list_head *inference_list)
109{
110 struct ethosu_inference *cur;
111
112 list_for_each_entry(cur, inference_list, list) {
113 if (cur == inf)
114 return 0;
115 }
116
117 return -EINVAL;
118}
119
120static bool ethosu_inference_verify(struct file *file)
121{
122 return file->f_op == &ethosu_inference_fops;
123}
124
125static void ethosu_inference_kref_destroy(struct kref *kref)
126{
127 struct ethosu_inference *inf =
128 container_of(kref, struct ethosu_inference, kref);
129
130 dev_info(inf->edev->dev,
131 "Inference destroy. handle=0x%pK, status=%d\n",
132 inf, inf->status);
133
134 list_del(&inf->list);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200135
136 while (inf->ifm_count-- > 0)
137 ethosu_buffer_put(inf->ifm[inf->ifm_count]);
138
139 while (inf->ofm_count-- > 0)
140 ethosu_buffer_put(inf->ofm[inf->ofm_count]);
141
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200142 ethosu_network_put(inf->net);
143 devm_kfree(inf->edev->dev, inf);
144}
145
146static int ethosu_inference_release(struct inode *inode,
147 struct file *file)
148{
149 struct ethosu_inference *inf = file->private_data;
150
151 dev_info(inf->edev->dev,
152 "Inference release. handle=0x%pK, status=%d\n",
153 inf, inf->status);
154
155 ethosu_inference_put(inf);
156
157 return 0;
158}
159
160static unsigned int ethosu_inference_poll(struct file *file,
161 poll_table *wait)
162{
163 struct ethosu_inference *inf = file->private_data;
164 int ret = 0;
165
166 poll_wait(file, &inf->waitq, wait);
167
168 if (!inf->pending)
169 ret |= POLLIN;
170
171 return ret;
172}
173
174static long ethosu_inference_ioctl(struct file *file,
175 unsigned int cmd,
176 unsigned long arg)
177{
178 struct ethosu_inference *inf = file->private_data;
Per Åstrandf7e407a2020-10-23 21:25:05 +0200179 void __user *udata = (void __user *)arg;
180 int ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200181
182 ret = mutex_lock_interruptible(&inf->edev->mutex);
183 if (ret)
184 return ret;
185
186 dev_info(inf->edev->dev, "Ioctl: cmd=%u, arg=%lu\n", cmd, arg);
187
188 switch (cmd) {
189 case ETHOSU_IOCTL_INFERENCE_STATUS: {
Per Åstrandf7e407a2020-10-23 21:25:05 +0200190 struct ethosu_uapi_result_status uapi;
191 int i;
192
193 uapi.status = inf->status;
194
195 for (i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
196 uapi.pmu_config.events[i] =
197 inf->pmu_event_config[i];
198 uapi.pmu_count.events[i] =
199 inf->pmu_event_count[i];
200 }
201
202 uapi.pmu_config.cycle_count = inf->pmu_cycle_counter_enable;
203 uapi.pmu_count.cycle_count = inf->pmu_cycle_counter_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200204
205 dev_info(inf->edev->dev,
206 "Ioctl: Inference status. status=%s (%d)\n",
Per Åstrandf7e407a2020-10-23 21:25:05 +0200207 status_to_string(uapi.status), uapi.status);
208
209 ret = copy_to_user(udata, &uapi, sizeof(uapi)) ? -EFAULT : 0;
210
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200211 break;
212 }
213 default: {
214 dev_err(inf->edev->dev, "Invalid ioctl. cmd=%u, arg=%lu",
215 cmd, arg);
216 break;
217 }
218 }
219
220 mutex_unlock(&inf->edev->mutex);
221
222 return ret;
223}
224
225int ethosu_inference_create(struct ethosu_device *edev,
226 struct ethosu_network *net,
227 struct ethosu_uapi_inference_create *uapi)
228{
229 struct ethosu_inference *inf;
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200230 uint32_t i;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200231 int fd;
232 int ret = -ENOMEM;
233
234 inf = devm_kzalloc(edev->dev, sizeof(*inf), GFP_KERNEL);
235 if (!inf)
236 return -ENOMEM;
237
238 inf->edev = edev;
239 inf->net = net;
240 inf->pending = false;
241 inf->status = ETHOSU_UAPI_STATUS_ERROR;
242 kref_init(&inf->kref);
243 init_waitqueue_head(&inf->waitq);
244
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200245 /* Get pointer to IFM buffers */
246 for (i = 0; i < uapi->ifm_count; i++) {
247 inf->ifm[i] = ethosu_buffer_get_from_fd(uapi->ifm_fd[i]);
248 if (IS_ERR(inf->ifm[i])) {
249 ret = PTR_ERR(inf->ifm[i]);
250 goto put_ifm;
251 }
252
253 inf->ifm_count++;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200254 }
255
256 /* Get pointer to OFM buffer */
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200257 for (i = 0; i < uapi->ofm_count; i++) {
258 inf->ofm[i] = ethosu_buffer_get_from_fd(uapi->ofm_fd[i]);
259 if (IS_ERR(inf->ofm[i])) {
260 ret = PTR_ERR(inf->ofm[i]);
261 goto put_ofm;
262 }
263
264 inf->ofm_count++;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200265 }
266
Per Åstrandf7e407a2020-10-23 21:25:05 +0200267 /* Configure PMU and cycle counter */
268 dev_info(inf->edev->dev,
269 "Configuring events for PMU. events=[%u, %u, %u, %u]\n",
270 uapi->pmu_config.events[0], uapi->pmu_config.events[1],
271 uapi->pmu_config.events[2], uapi->pmu_config.events[3]);
272
273 /* Configure events and reset count for all events */
274 for (i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
275 inf->pmu_event_config[i] = uapi->pmu_config.events[i];
276 inf->pmu_event_count[i] = 0;
277 }
278
279 if (uapi->pmu_config.cycle_count)
280 dev_info(inf->edev->dev, "Enabling cycle counter\n");
281
282 /* Configure cycle counter and reset any previous count */
283 inf->pmu_cycle_counter_enable = uapi->pmu_config.cycle_count;
284 inf->pmu_cycle_counter_count = 0;
285
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200286 /* Increment network reference count */
287 ethosu_network_get(net);
288
289 /* Create file descriptor */
290 ret = fd = anon_inode_getfd("ethosu-inference", &ethosu_inference_fops,
291 inf, O_RDWR | O_CLOEXEC);
292 if (ret < 0)
293 goto put_net;
294
295 /* Store pointer to file structure */
296 inf->file = fget(ret);
297 fput(inf->file);
298
299 /* Add inference to inference list */
300 list_add(&inf->list, &edev->inference_list);
301
302 /* Send inference request to Arm Ethos-U subsystem */
303 (void)ethosu_inference_send(inf);
304
305 dev_info(edev->dev, "Inference create. handle=0x%pK, fd=%d",
306 inf, fd);
307
308 return fd;
309
310put_net:
311 ethosu_network_put(inf->net);
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200312
313put_ofm:
314 while (inf->ofm_count-- > 0)
315 ethosu_buffer_put(inf->ofm[inf->ofm_count]);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200316
317put_ifm:
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200318 while (inf->ifm_count-- > 0)
319 ethosu_buffer_put(inf->ifm[inf->ifm_count]);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200320
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200321 devm_kfree(edev->dev, inf);
322
323 return ret;
324}
325
326struct ethosu_inference *ethosu_inference_get_from_fd(int fd)
327{
328 struct ethosu_inference *inf;
329 struct file *file;
330
331 file = fget(fd);
332 if (!file)
333 return ERR_PTR(-EINVAL);
334
335 if (!ethosu_inference_verify(file)) {
336 fput(file);
337
338 return ERR_PTR(-EINVAL);
339 }
340
341 inf = file->private_data;
342 ethosu_inference_get(inf);
343 fput(file);
344
345 return inf;
346}
347
348void ethosu_inference_get(struct ethosu_inference *inf)
349{
350 kref_get(&inf->kref);
351}
352
353void ethosu_inference_put(struct ethosu_inference *inf)
354{
355 kref_put(&inf->kref, &ethosu_inference_kref_destroy);
356}
357
358void ethosu_inference_rsp(struct ethosu_device *edev,
359 struct ethosu_core_inference_rsp *rsp)
360{
361 struct ethosu_inference *inf =
362 (struct ethosu_inference *)rsp->user_arg;
363 int ret;
Per Åstrandf7e407a2020-10-23 21:25:05 +0200364 int i;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200365
366 ret = ethosu_inference_find(inf, &edev->inference_list);
367 if (ret) {
368 dev_warn(edev->dev,
369 "Handle not found in inference list. handle=0x%p\n",
370 rsp);
371
372 return;
373 }
374
375 inf->pending = false;
376
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200377 if (rsp->status == ETHOSU_CORE_STATUS_OK &&
378 inf->ofm_count <= ETHOSU_CORE_BUFFER_MAX) {
379 uint32_t i;
380
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200381 inf->status = ETHOSU_UAPI_STATUS_OK;
382
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200383 for (i = 0; i < inf->ofm_count; i++) {
384 struct ethosu_buffer *ofm = inf->ofm[i];
385
386 ret = ethosu_buffer_resize(
387 ofm, ofm->size + rsp->ofm_size[i],
388 ofm->offset);
389 if (ret)
390 inf->status = ETHOSU_UAPI_STATUS_ERROR;
391 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200392 } else {
393 inf->status = ETHOSU_UAPI_STATUS_ERROR;
394 }
395
Per Åstrandf7e407a2020-10-23 21:25:05 +0200396 for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++) {
397 inf->pmu_event_config[i] = rsp->pmu_event_config[i];
398 inf->pmu_event_count[i] = rsp->pmu_event_count[i];
399 }
400
401 inf->pmu_cycle_counter_enable = rsp->pmu_cycle_counter_enable;
402 inf->pmu_cycle_counter_count = rsp->pmu_cycle_counter_count;
403
404 dev_info(edev->dev,
Jonny Svärd9d8d92c2020-12-10 11:33:19 +0100405 "PMU events. config=[%u, %u, %u, %u], count=[%u, %u, %u, %u]\n",
406 inf->pmu_event_config[0], inf->pmu_event_config[1],
407 inf->pmu_event_config[2], inf->pmu_event_config[3],
408 inf->pmu_event_count[0], inf->pmu_event_count[1],
409 inf->pmu_event_count[2], inf->pmu_event_count[3]);
Per Åstrandf7e407a2020-10-23 21:25:05 +0200410
411 dev_info(edev->dev,
412 "PMU cycle counter. enable=%u, count=%llu\n",
413 inf->pmu_cycle_counter_enable,
414 inf->pmu_cycle_counter_count);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200415 wake_up_interruptible(&inf->waitq);
416
417 ethosu_inference_put(inf);
418}