blob: fb4a8b4c931e50df21a21ce827c897160ff84c01 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Kristofer Jonssond779a082023-01-04 17:09:47 +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_buffer.h"
26
27#include "ethosu_device.h"
28#include "uapi/ethosu.h"
29
30#include <linux/anon_inodes.h>
31#include <linux/dma-mapping.h>
32#include <linux/of_address.h>
33#include <linux/file.h>
34#include <linux/fs.h>
Kristofer Jonssond779a082023-01-04 17:09:47 +010035#include <linux/remoteproc.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020036#include <linux/uaccess.h>
37
38/****************************************************************************
39 * Variables
40 ****************************************************************************/
41
42static int ethosu_buffer_release(struct inode *inode,
43 struct file *file);
44
45static int ethosu_buffer_mmap(struct file *file,
46 struct vm_area_struct *vma);
47
48static long ethosu_buffer_ioctl(struct file *file,
49 unsigned int cmd,
50 unsigned long arg);
51
52static const struct file_operations ethosu_buffer_fops = {
53 .release = &ethosu_buffer_release,
54 .mmap = &ethosu_buffer_mmap,
55 .unlocked_ioctl = &ethosu_buffer_ioctl,
56#ifdef CONFIG_COMPAT
57 .compat_ioctl = &ethosu_buffer_ioctl,
58#endif
59};
60
61/****************************************************************************
62 * Functions
63 ****************************************************************************/
64
Kristofer Jonsson116a6352020-08-20 17:25:23 +020065static bool ethosu_buffer_verify(struct file *file)
66{
67 return file->f_op == &ethosu_buffer_fops;
68}
69
70static void ethosu_buffer_destroy(struct kref *kref)
71{
72 struct ethosu_buffer *buf =
73 container_of(kref, struct ethosu_buffer, kref);
Kristofer Jonssonec477042023-01-20 13:38:13 +010074 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020075
Kristofer Jonsson074ef902023-01-23 13:05:36 +010076 dev_info(dev, "Buffer destroy. buf=0x%pK", buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020077
Kristofer Jonsson074ef902023-01-23 13:05:36 +010078 dma_free_coherent(dev, buf->capacity, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +010079 buf->dma_addr);
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +020080
Kristofer Jonssonec477042023-01-20 13:38:13 +010081 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020082}
83
84static int ethosu_buffer_release(struct inode *inode,
85 struct file *file)
86{
87 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +010088 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020089
Kristofer Jonssonec477042023-01-20 13:38:13 +010090 dev_info(dev, "Buffer release. file=0x%pK, buf=0x%pK\n",
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +020091 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020092
93 ethosu_buffer_put(buf);
94
95 return 0;
96}
97
98static int ethosu_buffer_mmap(struct file *file,
99 struct vm_area_struct *vma)
100{
101 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +0100102 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200103 int ret;
104
Kristofer Jonssonec477042023-01-20 13:38:13 +0100105 dev_info(dev, "Buffer mmap. file=0x%pK, buf=0x%pK\n",
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200106 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200107
Kristofer Jonssonec477042023-01-20 13:38:13 +0100108 ret = dma_mmap_coherent(dev, vma, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100109 buf->dma_addr, buf->capacity);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200110
111 return ret;
112}
113
114static long ethosu_buffer_ioctl(struct file *file,
115 unsigned int cmd,
116 unsigned long arg)
117{
118 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +0100119 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200120 void __user *udata = (void __user *)arg;
121 int ret = -EINVAL;
122
Kristofer Jonssonec477042023-01-20 13:38:13 +0100123 ret = device_lock_interruptible(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200124 if (ret)
125 return ret;
126
Kristofer Jonssonec477042023-01-20 13:38:13 +0100127 dev_info(dev,
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200128 "Buffer ioctl. file=0x%pK, buf=0x%pK, cmd=0x%x, arg=%lu\n",
129 file, buf, cmd, arg);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200130
131 switch (cmd) {
132 case ETHOSU_IOCTL_BUFFER_SET: {
133 struct ethosu_uapi_buffer uapi;
134
135 if (copy_from_user(&uapi, udata, sizeof(uapi)))
136 break;
137
Kristofer Jonssonec477042023-01-20 13:38:13 +0100138 dev_info(dev,
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200139 "Buffer ioctl: Buffer set. size=%u, offset=%u\n",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200140 uapi.size, uapi.offset);
141
142 ret = ethosu_buffer_resize(buf, uapi.size, uapi.offset);
143 break;
144 }
145 case ETHOSU_IOCTL_BUFFER_GET: {
146 struct ethosu_uapi_buffer uapi;
147
148 uapi.size = buf->size;
149 uapi.offset = buf->offset;
150
Kristofer Jonssonec477042023-01-20 13:38:13 +0100151 dev_info(dev,
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200152 "Buffer ioctl: Buffer get. size=%u, offset=%u\n",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200153 uapi.size, uapi.offset);
154
155 if (copy_to_user(udata, &uapi, sizeof(uapi)))
156 break;
157
158 ret = 0;
159 break;
160 }
161 default: {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100162 dev_err(dev, "Invalid ioctl. cmd=%u, arg=%lu",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 cmd, arg);
164 break;
165 }
166 }
167
Kristofer Jonssonec477042023-01-20 13:38:13 +0100168 device_unlock(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200169
170 return ret;
171}
172
Kristofer Jonssonec477042023-01-20 13:38:13 +0100173int ethosu_buffer_create(struct device *dev,
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200174 size_t capacity)
175{
176 struct ethosu_buffer *buf;
177 int ret = -ENOMEM;
178
Per Åstrandf50f25e2022-05-18 09:12:15 +0200179 if (!capacity)
180 return -EINVAL;
181
Kristofer Jonssonec477042023-01-20 13:38:13 +0100182 buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200183 if (!buf)
184 return -ENOMEM;
185
Kristofer Jonssond779a082023-01-04 17:09:47 +0100186 buf->dev = dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200187 buf->capacity = capacity;
188 buf->offset = 0;
189 buf->size = 0;
190 kref_init(&buf->kref);
191
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100192 buf->cpu_addr = dma_alloc_coherent(dev, capacity,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100193 &buf->dma_addr, GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200194 if (!buf->cpu_addr)
195 goto free_buf;
196
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200197 ret = anon_inode_getfd("ethosu-buffer", &ethosu_buffer_fops, buf,
198 O_RDWR | O_CLOEXEC);
199 if (ret < 0)
200 goto free_dma;
201
202 buf->file = fget(ret);
203 fput(buf->file);
204
Kristofer Jonssonec477042023-01-20 13:38:13 +0100205 dev_info(dev,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100206 "Buffer create. file=0x%pK, fd=%d, buf=0x%pK, capacity=%zu, cpu_addr=0x%pK, dma_addr=0x%llx, phys_addr=0x%llx\n",
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +0200207 buf->file, ret, buf, capacity, buf->cpu_addr, buf->dma_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100208 virt_to_phys(buf->cpu_addr));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200209
210 return ret;
211
212free_dma:
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100213 dma_free_coherent(dev, buf->capacity, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100214 buf->dma_addr);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200215
216free_buf:
Kristofer Jonssonec477042023-01-20 13:38:13 +0100217 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218
219 return ret;
220}
221
222struct ethosu_buffer *ethosu_buffer_get_from_fd(int fd)
223{
224 struct ethosu_buffer *buf;
225 struct file *file;
226
227 file = fget(fd);
228 if (!file)
229 return ERR_PTR(-EINVAL);
230
231 if (!ethosu_buffer_verify(file)) {
232 fput(file);
233
234 return ERR_PTR(-EINVAL);
235 }
236
237 buf = file->private_data;
238 ethosu_buffer_get(buf);
239 fput(file);
240
241 return buf;
242}
243
244void ethosu_buffer_get(struct ethosu_buffer *buf)
245{
246 kref_get(&buf->kref);
247}
248
249void ethosu_buffer_put(struct ethosu_buffer *buf)
250{
251 kref_put(&buf->kref, ethosu_buffer_destroy);
252}
253
254int ethosu_buffer_resize(struct ethosu_buffer *buf,
255 size_t size,
256 size_t offset)
257{
258 if ((size + offset) > buf->capacity)
259 return -EINVAL;
260
261 buf->size = size;
262 buf->offset = offset;
263
264 return 0;
265}