blob: bf7d74592a7601f74bdbde1beacc21a33141fa3c [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.
Kristofer Jonsson116a6352020-08-20 17:25:23 +020018 */
19
20/****************************************************************************
21 * Includes
22 ****************************************************************************/
23
24#include "ethosu_buffer.h"
25
26#include "ethosu_device.h"
27#include "uapi/ethosu.h"
28
29#include <linux/anon_inodes.h>
30#include <linux/dma-mapping.h>
31#include <linux/of_address.h>
32#include <linux/file.h>
33#include <linux/fs.h>
Kristofer Jonssond779a082023-01-04 17:09:47 +010034#include <linux/remoteproc.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020035#include <linux/uaccess.h>
36
37/****************************************************************************
38 * Variables
39 ****************************************************************************/
40
41static int ethosu_buffer_release(struct inode *inode,
42 struct file *file);
43
44static int ethosu_buffer_mmap(struct file *file,
45 struct vm_area_struct *vma);
46
Mikael Olsson07545152023-10-17 13:05:38 +020047static loff_t ethosu_buffer_llseek(struct file *file,
48 loff_t offset,
49 int whence);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020050
51static const struct file_operations ethosu_buffer_fops = {
Mikael Olsson07545152023-10-17 13:05:38 +020052 .release = &ethosu_buffer_release,
53 .mmap = &ethosu_buffer_mmap,
54 .llseek = &ethosu_buffer_llseek,
Kristofer Jonsson116a6352020-08-20 17:25:23 +020055};
56
57/****************************************************************************
58 * Functions
59 ****************************************************************************/
60
Kristofer Jonsson116a6352020-08-20 17:25:23 +020061static bool ethosu_buffer_verify(struct file *file)
62{
63 return file->f_op == &ethosu_buffer_fops;
64}
65
66static void ethosu_buffer_destroy(struct kref *kref)
67{
68 struct ethosu_buffer *buf =
69 container_of(kref, struct ethosu_buffer, kref);
Kristofer Jonssonec477042023-01-20 13:38:13 +010070 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020071
Ledion Dajaedd25502023-10-17 09:15:32 +020072 dev_dbg(dev, "Buffer destroy. buf=0x%pK", buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020073
Mikael Olsson07545152023-10-17 13:05:38 +020074 memset(buf->cpu_addr, 0, buf->size);
75 dma_free_coherent(dev, buf->size, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +010076 buf->dma_addr);
Kristofer Jonsson53fd03d2022-06-21 16:58:45 +020077
Mikael Olsson1182f382023-08-10 13:25:44 +020078 memset(buf, 0, sizeof(*buf));
Kristofer Jonssonec477042023-01-20 13:38:13 +010079 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020080}
81
82static int ethosu_buffer_release(struct inode *inode,
83 struct file *file)
84{
85 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +010086 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +020087
Ledion Dajaedd25502023-10-17 09:15:32 +020088 dev_dbg(dev, "Buffer release. file=0x%pK, buf=0x%pK\n",
89 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +020090
91 ethosu_buffer_put(buf);
92
93 return 0;
94}
95
96static int ethosu_buffer_mmap(struct file *file,
97 struct vm_area_struct *vma)
98{
99 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonssonec477042023-01-20 13:38:13 +0100100 struct device *dev = buf->dev;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200101 int ret;
102
Ledion Dajaedd25502023-10-17 09:15:32 +0200103 dev_dbg(dev, "Buffer mmap. file=0x%pK, buf=0x%pK\n",
104 file, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200105
Kristofer Jonssonec477042023-01-20 13:38:13 +0100106 ret = dma_mmap_coherent(dev, vma, buf->cpu_addr,
Mikael Olsson07545152023-10-17 13:05:38 +0200107 buf->dma_addr, buf->size);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200108
109 return ret;
110}
111
Mikael Olsson07545152023-10-17 13:05:38 +0200112static loff_t ethosu_buffer_llseek(struct file *file,
113 loff_t offset,
114 int whence)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200115{
116 struct ethosu_buffer *buf = file->private_data;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200117
Mikael Olsson07545152023-10-17 13:05:38 +0200118 if (offset != 0)
119 return -EINVAL;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200120
Mikael Olsson07545152023-10-17 13:05:38 +0200121 /*
122 * SEEK_END and SEEK_SET is supported with a zero offset to allow buffer
123 * size discovery using seek functions e.g.
124 * size = lseek(buf_fd, 0, SEEK_END);
125 * lseek(buf_fd, 0, SEEK_SET);
126 */
127 switch (whence) {
128 case SEEK_END:
129 return buf->size;
130 case SEEK_SET:
131 return 0;
132 default:
133 return -EINVAL;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200134 }
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200135}
136
Kristofer Jonssonec477042023-01-20 13:38:13 +0100137int ethosu_buffer_create(struct device *dev,
Mikael Olsson07545152023-10-17 13:05:38 +0200138 size_t size)
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200139{
140 struct ethosu_buffer *buf;
141 int ret = -ENOMEM;
142
Mikael Olsson07545152023-10-17 13:05:38 +0200143 if (!size)
Per Åstrandf50f25e2022-05-18 09:12:15 +0200144 return -EINVAL;
145
Kristofer Jonssonec477042023-01-20 13:38:13 +0100146 buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200147 if (!buf)
148 return -ENOMEM;
149
Kristofer Jonssond779a082023-01-04 17:09:47 +0100150 buf->dev = dev;
Mikael Olsson07545152023-10-17 13:05:38 +0200151 buf->size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200152 kref_init(&buf->kref);
153
Mikael Olsson07545152023-10-17 13:05:38 +0200154 buf->cpu_addr = dma_alloc_coherent(dev, size, &buf->dma_addr,
155 GFP_KERNEL);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200156 if (!buf->cpu_addr)
157 goto free_buf;
158
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200159 ret = anon_inode_getfd("ethosu-buffer", &ethosu_buffer_fops, buf,
160 O_RDWR | O_CLOEXEC);
161 if (ret < 0)
162 goto free_dma;
163
164 buf->file = fget(ret);
Mikael Olsson07545152023-10-17 13:05:38 +0200165 buf->file->f_mode |= FMODE_LSEEK;
166
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200167 fput(buf->file);
168
Ledion Dajaedd25502023-10-17 09:15:32 +0200169 dev_dbg(dev,
Mikael Olsson07545152023-10-17 13:05:38 +0200170 "Buffer create. file=0x%pK, fd=%d, buf=0x%pK, size=%zu, cpu_addr=0x%pK, dma_addr=0x%llx, phys_addr=0x%llx\n",
171 buf->file, ret, buf, size, buf->cpu_addr, buf->dma_addr,
Ledion Dajaedd25502023-10-17 09:15:32 +0200172 virt_to_phys(buf->cpu_addr));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200173
174 return ret;
175
176free_dma:
Mikael Olsson07545152023-10-17 13:05:38 +0200177 dma_free_coherent(dev, buf->size, buf->cpu_addr,
Kristofer Jonssond779a082023-01-04 17:09:47 +0100178 buf->dma_addr);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200179
180free_buf:
Mikael Olsson1182f382023-08-10 13:25:44 +0200181 memset(buf, 0, sizeof(*buf));
Kristofer Jonssonec477042023-01-20 13:38:13 +0100182 devm_kfree(dev, buf);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200183
184 return ret;
185}
186
187struct ethosu_buffer *ethosu_buffer_get_from_fd(int fd)
188{
189 struct ethosu_buffer *buf;
190 struct file *file;
191
192 file = fget(fd);
193 if (!file)
194 return ERR_PTR(-EINVAL);
195
196 if (!ethosu_buffer_verify(file)) {
197 fput(file);
198
199 return ERR_PTR(-EINVAL);
200 }
201
202 buf = file->private_data;
203 ethosu_buffer_get(buf);
204 fput(file);
205
206 return buf;
207}
208
209void ethosu_buffer_get(struct ethosu_buffer *buf)
210{
211 kref_get(&buf->kref);
212}
213
214void ethosu_buffer_put(struct ethosu_buffer *buf)
215{
216 kref_put(&buf->kref, ethosu_buffer_destroy);
217}