blob: 57ccb623d3cafd3ed58fe94bfbb05ab64ee7a37c [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_network.h"
26
27#include "ethosu_buffer.h"
28#include "ethosu_device.h"
29#include "ethosu_inference.h"
30#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);
69
70 dev_info(net->edev->dev, "Network destroy. handle=0x%pK\n", net);
71
Kristofer Jonsson35de9e62022-03-08 13:25:45 +010072 if (net->buf != NULL)
73 ethosu_buffer_put(net->buf);
74
Kristofer Jonsson116a6352020-08-20 17:25:23 +020075 devm_kfree(net->edev->dev, net);
76}
77
78static int ethosu_network_release(struct inode *inode,
79 struct file *file)
80{
81 struct ethosu_network *net = file->private_data;
82
83 dev_info(net->edev->dev, "Network release. handle=0x%pK\n", net);
84
85 ethosu_network_put(net);
86
87 return 0;
88}
89
90static long ethosu_network_ioctl(struct file *file,
91 unsigned int cmd,
92 unsigned long arg)
93{
94 struct ethosu_network *net = file->private_data;
95 void __user *udata = (void __user *)arg;
96 int ret = -EINVAL;
97
98 ret = mutex_lock_interruptible(&net->edev->mutex);
99 if (ret)
100 return ret;
101
102 dev_info(net->edev->dev, "Ioctl: cmd=%u, arg=%lu\n", cmd, arg);
103
104 switch (cmd) {
105 case ETHOSU_IOCTL_INFERENCE_CREATE: {
106 struct ethosu_uapi_inference_create uapi;
107
108 if (copy_from_user(&uapi, udata, sizeof(uapi)))
109 break;
110
111 dev_info(net->edev->dev,
112 "Ioctl: Inference. ifm_fd=%u, ofm_fd=%u\n",
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200113 uapi.ifm_fd[0], uapi.ofm_fd[0]);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200114
115 ret = ethosu_inference_create(net->edev, net, &uapi);
116 break;
117 }
118 default: {
119 dev_err(net->edev->dev, "Invalid ioctl. cmd=%u, arg=%lu",
120 cmd, arg);
121 break;
122 }
123 }
124
125 mutex_unlock(&net->edev->mutex);
126
127 return ret;
128}
129
130int ethosu_network_create(struct ethosu_device *edev,
131 struct ethosu_uapi_network_create *uapi)
132{
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200133 struct ethosu_network *net;
134 int ret = -ENOMEM;
135
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200136 net = devm_kzalloc(edev->dev, sizeof(*net), GFP_KERNEL);
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100137 if (!net)
138 return -ENOMEM;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200139
140 net->edev = edev;
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100141 net->buf = NULL;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200142 kref_init(&net->kref);
143
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100144 if (uapi->type == ETHOSU_UAPI_NETWORK_BUFFER) {
145 net->buf = ethosu_buffer_get_from_fd(uapi->fd);
146 if (IS_ERR(net->buf)) {
147 ret = PTR_ERR(net->buf);
148 goto free_net;
149 }
150 } else {
151 net->index = uapi->index;
152 }
153
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200154 ret = anon_inode_getfd("ethosu-network", &ethosu_network_fops, net,
155 O_RDWR | O_CLOEXEC);
156 if (ret < 0)
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100157 goto put_buf;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200158
159 net->file = fget(ret);
160 fput(net->file);
161
162 dev_info(edev->dev, "Network create. handle=0x%pK",
163 net);
164
165 return ret;
166
Kristofer Jonsson35de9e62022-03-08 13:25:45 +0100167put_buf:
168 if (net->buf != NULL)
169 ethosu_buffer_put(net->buf);
170
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200171free_net:
172 devm_kfree(edev->dev, net);
173
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200174 return ret;
175}
176
177struct ethosu_network *ethosu_network_get_from_fd(int fd)
178{
179 struct ethosu_network *net;
180 struct file *file;
181
182 file = fget(fd);
183 if (!file)
184 return ERR_PTR(-EINVAL);
185
186 if (!ethosu_network_verify(file)) {
187 fput(file);
188
189 return ERR_PTR(-EINVAL);
190 }
191
192 net = file->private_data;
193 ethosu_network_get(net);
194 fput(file);
195
196 return net;
197}
198
199void ethosu_network_get(struct ethosu_network *net)
200{
201 kref_get(&net->kref);
202}
203
204void ethosu_network_put(struct ethosu_network *net)
205{
206 kref_put(&net->kref, ethosu_network_destroy);
207}