blob: 5cdea2caf018060a9200fb6b44ab559c99453adc [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
2 * (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
3 *
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"
28#include "ethosu_core_interface.h"
29#include "ethosu_inference.h"
30#include "ethosu_network.h"
31#include "uapi/ethosu.h"
32
33#include <linux/delay.h>
34#include <linux/dma-mapping.h>
35#include <linux/errno.h>
36#include <linux/fs.h>
37#include <linux/interrupt.h>
38#include <linux/io.h>
39#include <linux/of_reserved_mem.h>
40#include <linux/uaccess.h>
41
42/****************************************************************************
43 * Defines
44 ****************************************************************************/
45
46#define MINOR_VERSION 0 /* Minor version starts at 0 */
47#define MINOR_COUNT 1 /* Allocate 1 minor version */
48#define DMA_ADDR_BITS 32 /* Number of address bits */
49
50/****************************************************************************
51 * Types
52 ****************************************************************************/
53
54/****************************************************************************
55 * Functions
56 ****************************************************************************/
57
58static int ethosu_handle_msg(struct ethosu_device *edev)
59{
60 struct ethosu_core_msg header;
61
62 union {
63 struct ethosu_core_inference_rsp inf;
64 } data;
65 int ret;
66
67 /* Read message */
68 ret = ethosu_mailbox_read(&edev->mailbox, &header, &data, sizeof(data));
69 if (ret)
70 return ret;
71
72 switch (header.type) {
73 case ETHOSU_CORE_MSG_PING:
74 dev_info(edev->dev, "Msg: Ping\n");
75 ret = ethosu_mailbox_ping(&edev->mailbox);
76 break;
77 case ETHOSU_CORE_MSG_PONG:
78 dev_info(edev->dev, "Msg: Pong\n");
79 break;
80 case ETHOSU_CORE_MSG_INFERENCE_RSP:
81 dev_info(edev->dev,
82 "Msg: Inference response. user_arg=0x%llx, ofm_size=%u, status=%u\n",
83 data.inf.user_arg, data.inf.ofm_size,
84 data.inf.status);
85 ethosu_inference_rsp(edev, &data.inf);
86 break;
87 default:
88 dev_warn(edev->dev,
89 "Msg: Unsupported msg type. type=%u, length=%u",
90 header.type, header.length);
91 break;
92 }
93
94 return ret;
95}
96
97static int ethosu_open(struct inode *inode,
98 struct file *file)
99{
100 struct ethosu_device *edev =
101 container_of(inode->i_cdev, struct ethosu_device, cdev);
102
103 file->private_data = edev;
104
105 dev_info(edev->dev, "Opening device node.\n");
106
107 return nonseekable_open(inode, file);
108}
109
110static long ethosu_ioctl(struct file *file,
111 unsigned int cmd,
112 unsigned long arg)
113{
114 struct ethosu_device *edev = file->private_data;
115 void __user *udata = (void __user *)arg;
116 int ret = -EINVAL;
117
118 ret = mutex_lock_interruptible(&edev->mutex);
119 if (ret)
120 return ret;
121
122 dev_info(edev->dev, "Ioctl. cmd=%u, arg=%lu\n", cmd, arg);
123
124 switch (cmd) {
125 case ETHOSU_IOCTL_PING: {
126 dev_info(edev->dev, "Ioctl: Send ping\n");
127 ret = ethosu_mailbox_ping(&edev->mailbox);
128 break;
129 }
130 case ETHOSU_IOCTL_BUFFER_CREATE: {
131 struct ethosu_uapi_buffer_create uapi;
132
133 dev_info(edev->dev, "Ioctl: Buffer create\n");
134
135 if (copy_from_user(&uapi, udata, sizeof(uapi)))
136 break;
137
138 dev_info(edev->dev, "Ioctl: Buffer. capacity=%u\n",
139 uapi.capacity);
140
141 ret = ethosu_buffer_create(edev, uapi.capacity);
142 break;
143 }
144 case ETHOSU_IOCTL_NETWORK_CREATE: {
145 struct ethosu_uapi_network_create uapi;
146
147 if (copy_from_user(&uapi, udata, sizeof(uapi)))
148 break;
149
150 dev_info(edev->dev, "Ioctl: Network. fd=%u\n", uapi.fd);
151
152 ret = ethosu_network_create(edev, &uapi);
153 break;
154 }
155 default: {
156 dev_err(edev->dev, "Invalid ioctl. cmd=%u, arg=%lu",
157 cmd, arg);
158 break;
159 }
160 }
161
162 mutex_unlock(&edev->mutex);
163
164 return ret;
165}
166
167static void ethosu_mbox_rx(void *user_arg)
168{
169 struct ethosu_device *edev = user_arg;
170 int ret;
171
172 mutex_lock(&edev->mutex);
173
174 do {
175 ret = ethosu_handle_msg(edev);
176 } while (ret == 0);
177
178 mutex_unlock(&edev->mutex);
179}
180
181int ethosu_dev_init(struct ethosu_device *edev,
182 struct device *dev,
183 struct class *class,
184 struct resource *in_queue,
185 struct resource *out_queue)
186{
187 static const struct file_operations fops = {
188 .owner = THIS_MODULE,
189 .open = &ethosu_open,
190 .unlocked_ioctl = &ethosu_ioctl,
191#ifdef CONFIG_COMPAT
192 .compat_ioctl = &ethosu_ioctl,
193#endif
194 };
195 struct device *sysdev;
196 int ret;
197
198 edev->dev = dev;
199 edev->class = class;
200 mutex_init(&edev->mutex);
201 INIT_LIST_HEAD(&edev->inference_list);
202
203 ret = of_reserved_mem_device_init(edev->dev);
204 if (ret)
205 return ret;
206
207 dma_set_mask_and_coherent(edev->dev, DMA_BIT_MASK(DMA_ADDR_BITS));
208
209 ret = ethosu_mailbox_init(&edev->mailbox, dev, in_queue, out_queue,
210 ethosu_mbox_rx, edev);
211 if (ret)
212 goto release_reserved_mem;
213
214 ret = alloc_chrdev_region(&edev->devt, MINOR_VERSION, MINOR_COUNT,
215 "ethosu");
216 if (ret) {
217 dev_err(edev->dev, "Failed to allocate chrdev region.\n");
218 goto deinit_mailbox;
219 }
220
221 cdev_init(&edev->cdev, &fops);
222 edev->cdev.owner = THIS_MODULE;
223
224 ret = cdev_add(&edev->cdev, edev->devt, MINOR_COUNT);
225 if (ret) {
226 dev_err(edev->dev, "Failed to add character device.\n");
227 goto region_unregister;
228 }
229
230 sysdev = device_create(edev->class, NULL, edev->devt, edev,
231 "ethosu%d", MAJOR(edev->devt));
232 if (IS_ERR(sysdev)) {
233 dev_err(edev->dev, "Failed to create device.\n");
234 ret = PTR_ERR(sysdev);
235 goto del_cdev;
236 }
237
238 dev_info(edev->dev,
239 "Created Arm Ethos-U device. name=%s, major=%d, minor=%d\n",
240 dev_name(sysdev), MAJOR(edev->devt), MINOR(edev->devt));
241
242 return 0;
243
244del_cdev:
245 cdev_del(&edev->cdev);
246
247region_unregister:
248 unregister_chrdev_region(edev->devt, 1);
249
250deinit_mailbox:
251 ethosu_mailbox_deinit(&edev->mailbox);
252
253release_reserved_mem:
254 of_reserved_mem_device_release(edev->dev);
255
256 return ret;
257}
258
259void ethosu_dev_deinit(struct ethosu_device *edev)
260{
261 ethosu_mailbox_deinit(&edev->mailbox);
262 device_destroy(edev->class, edev->cdev.dev);
263 cdev_del(&edev->cdev);
264 unregister_chrdev_region(edev->devt, MINOR_COUNT);
265 of_reserved_mem_device_release(edev->dev);
266
267 dev_info(edev->dev, "%s\n", __FUNCTION__);
268}