2 * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
3 * author: Jung Zhao jung.zhao@rock-chips.com
4 * Randy Li, randy.li@rock-chips.com
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
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.
17 #include <linux/rockchip_ion.h>
18 #include <linux/rockchip-iovmm.h>
19 #include <linux/slab.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/memblock.h>
22 #include <linux/module.h>
23 #include <linux/of_address.h>
24 #include <linux/of_graph.h>
25 #include <linux/component.h>
26 #include <linux/fence.h>
27 #include <linux/console.h>
28 #include <linux/kref.h>
29 #include <linux/fdtable.h>
31 #include "vcodec_iommu_ops.h"
33 struct vcodec_ion_buffer {
34 struct list_head list;
35 struct ion_handle *handle;
39 struct vcodec_iommu_ion_info {
40 struct ion_client *ion_client;
44 static struct vcodec_ion_buffer *
45 vcodec_ion_get_buffer_no_lock(struct vcodec_iommu_session_info *session_info,
48 struct vcodec_ion_buffer *ion_buffer = NULL, *n;
50 list_for_each_entry_safe(ion_buffer, n,
51 &session_info->buffer_list, list) {
52 if (ion_buffer->index == idx)
60 vcodec_ion_clear_session(struct vcodec_iommu_session_info *session_info)
65 static int vcodec_ion_attach(struct vcodec_iommu_info *iommu_info)
67 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
70 mutex_lock(&iommu_info->iommu_mutex);
72 if (ion_info->attached) {
73 mutex_unlock(&iommu_info->iommu_mutex);
77 rockchip_iovmm_activate(iommu_info->dev);
79 ion_info->attached = true;
81 mutex_unlock(&iommu_info->iommu_mutex);
86 static void vcodec_ion_detach(struct vcodec_iommu_info *iommu_info)
88 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
90 mutex_lock(&iommu_info->iommu_mutex);
92 if (!ion_info->attached) {
93 mutex_unlock(&iommu_info->iommu_mutex);
97 rockchip_iovmm_deactivate(iommu_info->dev);
98 ion_info->attached = false;
100 mutex_unlock(&iommu_info->iommu_mutex);
103 static int vcodec_ion_destroy(struct vcodec_iommu_info *iommu_info)
105 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
107 vcodec_ion_detach(iommu_info);
109 iommu_info->private = NULL;
115 vcodec_ion_free(struct vcodec_iommu_session_info *session_info, int idx)
117 struct vcodec_ion_buffer *ion_buffer;
119 mutex_lock(&session_info->list_mutex);
120 ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
123 mutex_unlock(&session_info->list_mutex);
124 pr_err("%s can not find %d buffer in list\n", __func__, idx);
129 list_del_init(&ion_buffer->list);
130 mutex_unlock(&session_info->list_mutex);
137 vcodec_ion_unmap_iommu(struct vcodec_iommu_session_info *session_info, int idx)
139 struct vcodec_ion_buffer *ion_buffer;
140 struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
141 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
143 mutex_lock(&session_info->list_mutex);
144 ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
145 mutex_unlock(&session_info->list_mutex);
148 pr_err("%s can not find %d buffer in list\n", __func__, idx);
153 ion_free(ion_info->ion_client, ion_buffer->handle);
159 vcodec_ion_map_iommu(struct vcodec_iommu_session_info *session_info, int idx,
160 unsigned long *iova, unsigned long *size)
162 struct vcodec_ion_buffer *ion_buffer;
163 struct device *dev = session_info->dev;
164 struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
165 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
168 /* Force to flush iommu table */
169 rockchip_iovmm_invalidate_tlb(session_info->dev);
171 mutex_lock(&session_info->list_mutex);
172 ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
173 mutex_unlock(&session_info->list_mutex);
176 pr_err("%s can not find %d buffer in list\n", __func__, idx);
181 if (session_info->mmu_dev)
182 ret = ion_map_iommu(dev, ion_info->ion_client,
183 ion_buffer->handle, iova, size);
185 ret = ion_phys(ion_info->ion_client, ion_buffer->handle,
186 iova, (size_t *)size);
192 vcodec_ion_unmap_kernel(struct vcodec_iommu_session_info *session_info,
195 struct vcodec_ion_buffer *ion_buffer;
197 mutex_lock(&session_info->list_mutex);
198 ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
199 mutex_unlock(&session_info->list_mutex);
202 pr_err("%s can not find %d buffer in list\n", __func__, idx);
211 vcodec_ion_map_kernel(struct vcodec_iommu_session_info *session_info, int idx)
213 struct vcodec_ion_buffer *ion_buffer;
214 struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
215 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
217 rockchip_iovmm_invalidate_tlb(session_info->dev);
219 mutex_lock(&session_info->list_mutex);
220 ion_buffer = vcodec_ion_get_buffer_no_lock(session_info, idx);
221 mutex_unlock(&session_info->list_mutex);
224 pr_err("%s can not find %d buffer in list\n", __func__, idx);
229 return ion_map_kernel(ion_info->ion_client, ion_buffer->handle);
233 vcodec_ion_import(struct vcodec_iommu_session_info *session_info, int fd)
235 struct vcodec_ion_buffer *ion_buffer = NULL;
236 struct vcodec_iommu_info *iommu_info = session_info->iommu_info;
237 struct vcodec_iommu_ion_info *ion_info = iommu_info->private;
239 ion_buffer = kzalloc(sizeof(*ion_buffer), GFP_KERNEL);
243 ion_buffer->handle = ion_import_dma_buf(ion_info->ion_client, fd);
245 INIT_LIST_HEAD(&ion_buffer->list);
246 mutex_lock(&session_info->list_mutex);
247 ion_buffer->index = session_info->max_idx;
248 list_add_tail(&ion_buffer->list, &session_info->buffer_list);
249 session_info->max_idx++;
250 if ((session_info->max_idx & 0xfffffff) == 0)
251 session_info->max_idx = 0;
252 mutex_unlock(&session_info->list_mutex);
254 return ion_buffer->index;
257 static int vcodec_ion_create(struct vcodec_iommu_info *iommu_info)
259 struct vcodec_iommu_ion_info *ion_info;
261 iommu_info->private = kmalloc(sizeof(*ion_info), GFP_KERNEL);
263 ion_info = iommu_info->private;
267 ion_info->ion_client = rockchip_ion_client_create("vpu");
268 ion_info->attached = false;
270 vcodec_ion_attach(iommu_info);
272 return IS_ERR(ion_info->ion_client) ? -1 : 0;
275 static struct vcodec_iommu_ops ion_ops = {
276 .create = vcodec_ion_create,
277 .destroy = vcodec_ion_destroy,
278 .import = vcodec_ion_import,
279 .free = vcodec_ion_free,
281 .map_kernel = vcodec_ion_map_kernel,
282 .unmap_kernel = vcodec_ion_unmap_kernel,
283 .map_iommu = vcodec_ion_map_iommu,
284 .unmap_iommu = vcodec_ion_unmap_iommu,
286 .attach = vcodec_ion_attach,
287 .detach = vcodec_ion_detach,
288 .clear = vcodec_ion_clear_session,
292 * we do not manage the ref number ourselves,
293 * since ion will help us to do that. what we
294 * need to do is just map/unmap and import/free
297 void vcodec_iommu_ion_set_ops(struct vcodec_iommu_info *iommu_info)
301 iommu_info->ops = &ion_ops;