blob: 07c8033e6e3484be25bfe682c6f430a837c4b4b1 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Ledion Dajaedd25502023-10-17 09:15:32 +02002 * SPDX-FileCopyrightText: Copyright 2020-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.
18 *
Kristofer Jonsson116a6352020-08-20 17:25:23 +020019 */
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
Ledion Dajaedd25502023-10-17 09:15:32 +020076 dev_dbg(dev, "Buffer destroy. buf=0x%pK", buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020077
Mikael Olsson1182f382023-08-10 13:25:44 +020078 memset(buf->cpu_addr, 0, buf->capacity);
Kristofer Jonsson074ef902023-01-23 13:05:36 +010079 dma_free_coherent(dev, buf->capacity, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +010080 buf->dma_addr);
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +020081
Mikael Olsson1182f382023-08-10 13:25:44 +020082 memset(buf, 0, sizeof(*buf));
Kristofer Jonssonec477042023-01-20 13:38:13 +010083 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020084}
85
86static int ethosu_buffer_release(struct inode *inode,
87 struct file *file)
88{
89 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +010090 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020091
Ledion Dajaedd25502023-10-17 09:15:32 +020092 dev_dbg(dev, "Buffer release. file=0x%pK, buf=0x%pK\n",
93 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020094
95 ethosu_buffer_put(buf);
96
97 return 0;
98}
99
100static int ethosu_buffer_mmap(struct file *file,
101 struct vm_area_struct *vma)
102{
103 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +0100104 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200105 int ret;
106
Ledion Dajaedd25502023-10-17 09:15:32 +0200107 dev_dbg(dev, "Buffer mmap. file=0x%pK, buf=0x%pK\n",
108 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200109
Kristofer Jonssonec477042023-01-20 13:38:13 +0100110 ret = dma_mmap_coherent(dev, vma, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100111 buf->dma_addr, buf->capacity);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200112
113 return ret;
114}
115
116static long ethosu_buffer_ioctl(struct file *file,
117 unsigned int cmd,
118 unsigned long arg)
119{
120 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +0100121 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200122 void __user *udata = (void __user *)arg;
Mikael Olsson891156d2023-08-24 13:20:31 +0200123 int ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200124
Kristofer Jonssonec477042023-01-20 13:38:13 +0100125 ret = device_lock_interruptible(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200126 if (ret)
127 return ret;
128
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200129 switch (cmd) {
130 case ETHOSU_IOCTL_BUFFER_SET: {
131 struct ethosu_uapi_buffer uapi;
132
Mikael Olsson891156d2023-08-24 13:20:31 +0200133 if (copy_from_user(&uapi, udata, sizeof(uapi))) {
134 ret = -EFAULT;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200135 break;
Mikael Olsson891156d2023-08-24 13:20:31 +0200136 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200137
Ledion Dajaedd25502023-10-17 09:15:32 +0200138 dev_dbg(dev,
139 "Buffer ioctl: Buffer set. size=%u, offset=%u\n",
140 uapi.size, uapi.offset);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200141
142 ret = ethosu_buffer_resize(buf, uapi.size, uapi.offset);
143 break;
144 }
145 case ETHOSU_IOCTL_BUFFER_GET: {
Mikael Olssonec902232023-08-24 13:28:19 +0200146 struct ethosu_uapi_buffer uapi = { 0 };
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200147
148 uapi.size = buf->size;
149 uapi.offset = buf->offset;
150
Ledion Dajaedd25502023-10-17 09:15:32 +0200151 dev_dbg(dev,
152 "Buffer ioctl: Buffer get. size=%u, offset=%u\n",
153 uapi.size, uapi.offset);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200154
Mikael Olsson891156d2023-08-24 13:20:31 +0200155 if (copy_to_user(udata, &uapi, sizeof(uapi))) {
156 ret = -EFAULT;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200157 break;
Mikael Olsson891156d2023-08-24 13:20:31 +0200158 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200159
160 ret = 0;
161 break;
162 }
163 default: {
Kristofer Jonssonec477042023-01-20 13:38:13 +0100164 dev_err(dev, "Invalid ioctl. cmd=%u, arg=%lu",
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200165 cmd, arg);
Mikael Olsson891156d2023-08-24 13:20:31 +0200166 ret = -ENOIOCTLCMD;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200167 break;
168 }
169 }
170
Kristofer Jonssonec477042023-01-20 13:38:13 +0100171 device_unlock(dev);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200172
173 return ret;
174}
175
Kristofer Jonssonec477042023-01-20 13:38:13 +0100176int ethosu_buffer_create(struct device *dev,
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200177 size_t capacity)
178{
179 struct ethosu_buffer *buf;
180 int ret = -ENOMEM;
181
Per Åstrandf50f25e2022-05-18 09:12:15 +0200182 if (!capacity)
183 return -EINVAL;
184
Kristofer Jonssonec477042023-01-20 13:38:13 +0100185 buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200186 if (!buf)
187 return -ENOMEM;
188
Kristofer Jonssond779a082023-01-04 17:09:47 +0100189 buf->dev = dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200190 buf->capacity = capacity;
191 buf->offset = 0;
192 buf->size = 0;
193 kref_init(&buf->kref);
194
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100195 buf->cpu_addr = dma_alloc_coherent(dev, capacity,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100196 &buf->dma_addr, GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200197 if (!buf->cpu_addr)
198 goto free_buf;
199
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200200 ret = anon_inode_getfd("ethosu-buffer", &ethosu_buffer_fops, buf,
201 O_RDWR | O_CLOEXEC);
202 if (ret < 0)
203 goto free_dma;
204
205 buf->file = fget(ret);
206 fput(buf->file);
207
Ledion Dajaedd25502023-10-17 09:15:32 +0200208 dev_dbg(dev,
209 "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",
210 buf->file, ret, buf, capacity, buf->cpu_addr, buf->dma_addr,
211 virt_to_phys(buf->cpu_addr));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200212
213 return ret;
214
215free_dma:
Kristofer Jonsson074ef902023-01-23 13:05:36 +0100216 dma_free_coherent(dev, buf->capacity, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100217 buf->dma_addr);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218
219free_buf:
Mikael Olsson1182f382023-08-10 13:25:44 +0200220 memset(buf, 0, sizeof(*buf));
Kristofer Jonssonec477042023-01-20 13:38:13 +0100221 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200222
223 return ret;
224}
225
226struct ethosu_buffer *ethosu_buffer_get_from_fd(int fd)
227{
228 struct ethosu_buffer *buf;
229 struct file *file;
230
231 file = fget(fd);
232 if (!file)
233 return ERR_PTR(-EINVAL);
234
235 if (!ethosu_buffer_verify(file)) {
236 fput(file);
237
238 return ERR_PTR(-EINVAL);
239 }
240
241 buf = file->private_data;
242 ethosu_buffer_get(buf);
243 fput(file);
244
245 return buf;
246}
247
248void ethosu_buffer_get(struct ethosu_buffer *buf)
249{
250 kref_get(&buf->kref);
251}
252
253void ethosu_buffer_put(struct ethosu_buffer *buf)
254{
255 kref_put(&buf->kref, ethosu_buffer_destroy);
256}
257
258int ethosu_buffer_resize(struct ethosu_buffer *buf,
259 size_t size,
260 size_t offset)
261{
262 if ((size + offset) > buf->capacity)
263 return -EINVAL;
264
265 buf->size = size;
266 buf->offset = offset;
267
268 return 0;
269}