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 "iep_iommu_ops.h"
33 struct iep_ion_buffer {
34 struct list_head list;
35 struct ion_handle *handle;
39 struct iep_iommu_ion_info {
40 struct ion_client *ion_client;
44 static struct iep_ion_buffer *
45 iep_ion_get_buffer_no_lock(struct iep_iommu_session_info *session_info,
48 struct iep_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 iep_ion_clear_session(struct iep_iommu_session_info *session_info)
65 static int iep_ion_attach(struct iep_iommu_info *iommu_info)
67 struct iep_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 iep_ion_detach(struct iep_iommu_info *iommu_info)
88 struct iep_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 iep_ion_destroy(struct iep_iommu_info *iommu_info)
105 struct iep_iommu_ion_info *ion_info = iommu_info->private;
107 iep_ion_detach(iommu_info);
109 iommu_info->private = NULL;
115 iep_ion_free(struct iep_iommu_session_info *session_info, int idx)
117 struct iep_ion_buffer *ion_buffer;
119 mutex_lock(&session_info->list_mutex);
120 ion_buffer = iep_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 iep_ion_unmap_iommu(struct iep_iommu_session_info *session_info, int idx)
139 struct iep_ion_buffer *ion_buffer;
140 struct iep_iommu_info *iommu_info = session_info->iommu_info;
141 struct iep_iommu_ion_info *ion_info = iommu_info->private;
143 mutex_lock(&session_info->list_mutex);
144 ion_buffer = iep_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 iep_ion_map_iommu(struct iep_iommu_session_info *session_info, int idx,
160 unsigned long *iova, unsigned long *size)
162 struct iep_ion_buffer *ion_buffer;
163 struct device *dev = session_info->dev;
164 struct iep_iommu_info *iommu_info = session_info->iommu_info;
165 struct iep_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 = iep_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 iep_ion_import(struct iep_iommu_session_info *session_info, int fd)
194 struct iep_ion_buffer *ion_buffer = NULL;
195 struct iep_iommu_info *iommu_info = session_info->iommu_info;
196 struct iep_iommu_ion_info *ion_info = iommu_info->private;
198 ion_buffer = kzalloc(sizeof(*ion_buffer), GFP_KERNEL);
202 ion_buffer->handle = ion_import_dma_buf(ion_info->ion_client, fd);
204 INIT_LIST_HEAD(&ion_buffer->list);
205 mutex_lock(&session_info->list_mutex);
206 ion_buffer->index = session_info->max_idx;
207 list_add_tail(&ion_buffer->list, &session_info->buffer_list);
208 session_info->max_idx++;
209 if ((session_info->max_idx & 0xfffffff) == 0)
210 session_info->max_idx = 0;
211 mutex_unlock(&session_info->list_mutex);
213 return ion_buffer->index;
216 static int iep_ion_create(struct iep_iommu_info *iommu_info)
218 struct iep_iommu_ion_info *ion_info;
220 iommu_info->private = kmalloc(sizeof(*ion_info), GFP_KERNEL);
222 ion_info = iommu_info->private;
226 ion_info->ion_client = rockchip_ion_client_create("vpu");
227 ion_info->attached = false;
229 iep_ion_attach(iommu_info);
231 return IS_ERR(ion_info->ion_client) ? -1 : 0;
234 static struct iep_iommu_ops ion_ops = {
235 .create = iep_ion_create,
236 .destroy = iep_ion_destroy,
237 .import = iep_ion_import,
238 .free = iep_ion_free,
240 .map_iommu = iep_ion_map_iommu,
241 .unmap_iommu = iep_ion_unmap_iommu,
243 .attach = iep_ion_attach,
244 .detach = iep_ion_detach,
245 .clear = iep_ion_clear_session,
249 * we do not manage the ref number ourselves,
250 * since ion will help us to do that. what we
251 * need to do is just map/unmap and import/free
254 void iep_iommu_ion_set_ops(struct iep_iommu_info *iommu_info)
258 iommu_info->ops = &ion_ops;