xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/iep/iep_iommu_drm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  * author: Jung Zhao jung.zhao@rock-chips.com
4*4882a593Smuzhiyun  *         Randy Li, randy.li@rock-chips.com
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This software is licensed under the terms of the GNU General Public
7*4882a593Smuzhiyun  * License version 2, as published by the Free Software Foundation, and
8*4882a593Smuzhiyun  * may be copied, distributed, and modified under those terms.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
11*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*4882a593Smuzhiyun  * GNU General Public License for more details.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun #include <drm/drm_device.h>
17*4882a593Smuzhiyun #include <linux/dma-iommu.h>
18*4882a593Smuzhiyun #include <linux/dma-buf.h>
19*4882a593Smuzhiyun #include <linux/dma-mapping.h>
20*4882a593Smuzhiyun #include <linux/iommu.h>
21*4882a593Smuzhiyun #include <linux/kref.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "iep_iommu_ops.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct iep_drm_buffer {
27*4882a593Smuzhiyun 	struct list_head list;
28*4882a593Smuzhiyun 	struct dma_buf *dma_buf;
29*4882a593Smuzhiyun 	union {
30*4882a593Smuzhiyun 		unsigned long iova;
31*4882a593Smuzhiyun 		unsigned long phys;
32*4882a593Smuzhiyun 	};
33*4882a593Smuzhiyun 	unsigned long size;
34*4882a593Smuzhiyun 	int index;
35*4882a593Smuzhiyun 	struct dma_buf_attachment *attach;
36*4882a593Smuzhiyun 	struct sg_table *sgt;
37*4882a593Smuzhiyun 	struct page **pages;
38*4882a593Smuzhiyun 	struct kref ref;
39*4882a593Smuzhiyun 	struct iep_iommu_session_info *session_info;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct iep_iommu_drm_info {
43*4882a593Smuzhiyun 	struct iommu_domain *domain;
44*4882a593Smuzhiyun 	bool attached;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static struct iep_drm_buffer *
iep_drm_get_buffer_no_lock(struct iep_iommu_session_info * session_info,int idx)48*4882a593Smuzhiyun iep_drm_get_buffer_no_lock(struct iep_iommu_session_info *session_info,
49*4882a593Smuzhiyun 			   int idx)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL, *n;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
54*4882a593Smuzhiyun 				 list) {
55*4882a593Smuzhiyun 		if (drm_buffer->index == idx)
56*4882a593Smuzhiyun 			return drm_buffer;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return NULL;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static struct iep_drm_buffer *
iep_drm_get_buffer_fd_no_lock(struct iep_iommu_session_info * session_info,int fd)63*4882a593Smuzhiyun iep_drm_get_buffer_fd_no_lock(struct iep_iommu_session_info *session_info,
64*4882a593Smuzhiyun 			      int fd)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL, *n;
67*4882a593Smuzhiyun 	struct dma_buf *dma_buf = NULL;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	dma_buf = dma_buf_get(fd);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
72*4882a593Smuzhiyun 				 list) {
73*4882a593Smuzhiyun 		if (drm_buffer->dma_buf == dma_buf) {
74*4882a593Smuzhiyun 			dma_buf_put(dma_buf);
75*4882a593Smuzhiyun 			return drm_buffer;
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	dma_buf_put(dma_buf);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return NULL;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
iep_drm_detach(struct iep_iommu_info * iommu_info)84*4882a593Smuzhiyun static void iep_drm_detach(struct iep_iommu_info *iommu_info)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
87*4882a593Smuzhiyun 	struct device *dev = iommu_info->dev;
88*4882a593Smuzhiyun 	struct iommu_domain *domain = drm_info->domain;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	mutex_lock(&iommu_info->iommu_mutex);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (!drm_info->attached) {
93*4882a593Smuzhiyun 		mutex_unlock(&iommu_info->iommu_mutex);
94*4882a593Smuzhiyun 		return;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	iommu_detach_device(domain, dev);
98*4882a593Smuzhiyun 	drm_info->attached = false;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	mutex_unlock(&iommu_info->iommu_mutex);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
iep_drm_attach_unlock(struct iep_iommu_info * iommu_info)103*4882a593Smuzhiyun static int iep_drm_attach_unlock(struct iep_iommu_info *iommu_info)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
106*4882a593Smuzhiyun 	struct device *dev = iommu_info->dev;
107*4882a593Smuzhiyun 	struct iommu_domain *domain = drm_info->domain;
108*4882a593Smuzhiyun 	int ret = 0;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
111*4882a593Smuzhiyun 	if (ret)
112*4882a593Smuzhiyun 		return ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
115*4882a593Smuzhiyun 	ret = iommu_attach_device(domain, dev);
116*4882a593Smuzhiyun 	if (ret) {
117*4882a593Smuzhiyun 		dev_err(dev, "Failed to attach iommu device\n");
118*4882a593Smuzhiyun 		return ret;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return ret;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
iep_drm_attach(struct iep_iommu_info * iommu_info)124*4882a593Smuzhiyun static int iep_drm_attach(struct iep_iommu_info *iommu_info)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
127*4882a593Smuzhiyun 	int ret;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	mutex_lock(&iommu_info->iommu_mutex);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (drm_info->attached) {
132*4882a593Smuzhiyun 		mutex_unlock(&iommu_info->iommu_mutex);
133*4882a593Smuzhiyun 		return 0;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	ret = iep_drm_attach_unlock(iommu_info);
137*4882a593Smuzhiyun 	if (ret) {
138*4882a593Smuzhiyun 		mutex_unlock(&iommu_info->iommu_mutex);
139*4882a593Smuzhiyun 		return ret;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	drm_info->attached = true;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	mutex_unlock(&iommu_info->iommu_mutex);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	return ret;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
iep_drm_clear_map(struct kref * ref)149*4882a593Smuzhiyun static void iep_drm_clear_map(struct kref *ref)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer =
152*4882a593Smuzhiyun 		container_of(ref, struct iep_drm_buffer, ref);
153*4882a593Smuzhiyun 	struct iep_iommu_session_info *session_info =
154*4882a593Smuzhiyun 		drm_buffer->session_info;
155*4882a593Smuzhiyun 	struct iep_iommu_info *iommu_info = session_info->iommu_info;
156*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
157*4882a593Smuzhiyun 	struct device *dev = session_info->dev;
158*4882a593Smuzhiyun 	struct iommu_domain *domain = drm_info->domain;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	mutex_lock(&iommu_info->iommu_mutex);
161*4882a593Smuzhiyun 	drm_info = session_info->iommu_info->private;
162*4882a593Smuzhiyun 	if (!drm_info->attached) {
163*4882a593Smuzhiyun 		if (iep_drm_attach_unlock(session_info->iommu_info))
164*4882a593Smuzhiyun 			dev_err(dev, "can't clea map, attach iommu failed.\n");
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	if (drm_buffer->attach) {
168*4882a593Smuzhiyun 		dma_buf_unmap_attachment(drm_buffer->attach, drm_buffer->sgt,
169*4882a593Smuzhiyun 					 DMA_BIDIRECTIONAL);
170*4882a593Smuzhiyun 		dma_buf_detach(drm_buffer->dma_buf, drm_buffer->attach);
171*4882a593Smuzhiyun 		dma_buf_put(drm_buffer->dma_buf);
172*4882a593Smuzhiyun 		drm_buffer->attach = NULL;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (!drm_info->attached)
176*4882a593Smuzhiyun 		iommu_detach_device(domain, dev);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	mutex_unlock(&iommu_info->iommu_mutex);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
vcdoec_drm_dump_info(struct iep_iommu_session_info * session_info)181*4882a593Smuzhiyun static void vcdoec_drm_dump_info(struct iep_iommu_session_info *session_info)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL, *n;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_OPS_DUMP,
186*4882a593Smuzhiyun 			"still there are below buffers stored in list\n");
187*4882a593Smuzhiyun 	list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
188*4882a593Smuzhiyun 				 list) {
189*4882a593Smuzhiyun 		vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_OPS_DUMP,
190*4882a593Smuzhiyun 				"index %d drm_buffer dma_buf %p\n",
191*4882a593Smuzhiyun 				drm_buffer->index,
192*4882a593Smuzhiyun 				drm_buffer->dma_buf);
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
iep_drm_free(struct iep_iommu_session_info * session_info,int idx)196*4882a593Smuzhiyun static int iep_drm_free(struct iep_iommu_session_info *session_info,
197*4882a593Smuzhiyun 			int idx)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct device *dev = session_info->dev;
200*4882a593Smuzhiyun 	/* please double-check all maps have been release */
201*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
204*4882a593Smuzhiyun 	drm_buffer = iep_drm_get_buffer_no_lock(session_info, idx);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	if (!drm_buffer) {
207*4882a593Smuzhiyun 		dev_err(dev, "can not find %d buffer in list\n", idx);
208*4882a593Smuzhiyun 		mutex_unlock(&session_info->list_mutex);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 		return -EINVAL;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (kref_read(&drm_buffer->ref) == 0) {
214*4882a593Smuzhiyun 		dma_buf_put(drm_buffer->dma_buf);
215*4882a593Smuzhiyun 		list_del_init(&drm_buffer->list);
216*4882a593Smuzhiyun 		kfree(drm_buffer);
217*4882a593Smuzhiyun 		session_info->buffer_nums--;
218*4882a593Smuzhiyun 		vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
219*4882a593Smuzhiyun 			"buffer nums %d\n", session_info->buffer_nums);
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static int
iep_drm_unmap_iommu(struct iep_iommu_session_info * session_info,int idx)227*4882a593Smuzhiyun iep_drm_unmap_iommu(struct iep_iommu_session_info *session_info,
228*4882a593Smuzhiyun 		    int idx)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct device *dev = session_info->dev;
231*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
234*4882a593Smuzhiyun 	drm_buffer = iep_drm_get_buffer_no_lock(session_info, idx);
235*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (!drm_buffer) {
238*4882a593Smuzhiyun 		dev_err(dev, "can not find %d buffer in list\n", idx);
239*4882a593Smuzhiyun 		return -EINVAL;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	kref_put(&drm_buffer->ref, iep_drm_clear_map);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
iep_drm_map_iommu(struct iep_iommu_session_info * session_info,int idx,unsigned long * iova,unsigned long * size)247*4882a593Smuzhiyun static int iep_drm_map_iommu(struct iep_iommu_session_info *session_info,
248*4882a593Smuzhiyun 			     int idx,
249*4882a593Smuzhiyun 			     unsigned long *iova,
250*4882a593Smuzhiyun 			     unsigned long *size)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct device *dev = session_info->dev;
253*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
256*4882a593Smuzhiyun 	drm_buffer = iep_drm_get_buffer_no_lock(session_info, idx);
257*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (!drm_buffer) {
260*4882a593Smuzhiyun 		dev_err(dev, "can not find %d buffer in list\n", idx);
261*4882a593Smuzhiyun 		return -EINVAL;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	kref_get(&drm_buffer->ref);
265*4882a593Smuzhiyun 	if (iova)
266*4882a593Smuzhiyun 		*iova = drm_buffer->iova;
267*4882a593Smuzhiyun 	if (size)
268*4882a593Smuzhiyun 		*size = drm_buffer->size;
269*4882a593Smuzhiyun 	return 0;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun static int
iep_drm_free_fd(struct iep_iommu_session_info * session_info,int fd)273*4882a593Smuzhiyun iep_drm_free_fd(struct iep_iommu_session_info *session_info, int fd)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	/* please double-check all maps have been release */
276*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
279*4882a593Smuzhiyun 	drm_buffer = iep_drm_get_buffer_fd_no_lock(session_info, fd);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (!drm_buffer) {
282*4882a593Smuzhiyun 		vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
283*4882a593Smuzhiyun 				"can not find %d buffer in list\n", fd);
284*4882a593Smuzhiyun 		mutex_unlock(&session_info->list_mutex);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		return -EINVAL;
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	iep_drm_unmap_iommu(session_info, drm_buffer->index);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
293*4882a593Smuzhiyun 	if (kref_read(&drm_buffer->ref) == 0) {
294*4882a593Smuzhiyun 		dma_buf_put(drm_buffer->dma_buf);
295*4882a593Smuzhiyun 		list_del_init(&drm_buffer->list);
296*4882a593Smuzhiyun 		kfree(drm_buffer);
297*4882a593Smuzhiyun 		session_info->buffer_nums--;
298*4882a593Smuzhiyun 		vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
299*4882a593Smuzhiyun 				"buffer nums %d\n", session_info->buffer_nums);
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return 0;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static void
iep_drm_clear_session(struct iep_iommu_session_info * session_info)307*4882a593Smuzhiyun iep_drm_clear_session(struct iep_iommu_session_info *session_info)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL, *n;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	list_for_each_entry_safe(drm_buffer, n, &session_info->buffer_list,
312*4882a593Smuzhiyun 				 list) {
313*4882a593Smuzhiyun 		kref_put(&drm_buffer->ref, iep_drm_clear_map);
314*4882a593Smuzhiyun 		iep_drm_free(session_info, drm_buffer->index);
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
iep_drm_import(struct iep_iommu_session_info * session_info,int fd)318*4882a593Smuzhiyun static int iep_drm_import(struct iep_iommu_session_info *session_info,
319*4882a593Smuzhiyun 			  int fd)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct iep_drm_buffer *drm_buffer = NULL, *n;
322*4882a593Smuzhiyun 	struct iep_iommu_info *iommu_info = session_info->iommu_info;
323*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
324*4882a593Smuzhiyun 	struct iommu_domain *domain = drm_info->domain;
325*4882a593Smuzhiyun 	struct device *dev = session_info->dev;
326*4882a593Smuzhiyun 	struct dma_buf_attachment *attach;
327*4882a593Smuzhiyun 	struct sg_table *sgt;
328*4882a593Smuzhiyun 	struct dma_buf *dma_buf;
329*4882a593Smuzhiyun 	int ret = 0;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	dma_buf = dma_buf_get(fd);
332*4882a593Smuzhiyun 	if (IS_ERR(dma_buf)) {
333*4882a593Smuzhiyun 		ret = PTR_ERR(dma_buf);
334*4882a593Smuzhiyun 		return ret;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	list_for_each_entry_safe(drm_buffer, n,
338*4882a593Smuzhiyun 				 &session_info->buffer_list, list) {
339*4882a593Smuzhiyun 		if (drm_buffer->dma_buf == dma_buf) {
340*4882a593Smuzhiyun 			dma_buf_put(dma_buf);
341*4882a593Smuzhiyun 			return drm_buffer->index;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	drm_buffer = kzalloc(sizeof(*drm_buffer), GFP_KERNEL);
346*4882a593Smuzhiyun 	if (!drm_buffer) {
347*4882a593Smuzhiyun 		ret = -ENOMEM;
348*4882a593Smuzhiyun 		return ret;
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	drm_buffer->dma_buf = dma_buf;
352*4882a593Smuzhiyun 	drm_buffer->session_info = session_info;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	kref_init(&drm_buffer->ref);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	mutex_lock(&iommu_info->iommu_mutex);
357*4882a593Smuzhiyun 	drm_info = session_info->iommu_info->private;
358*4882a593Smuzhiyun 	if (!drm_info->attached) {
359*4882a593Smuzhiyun 		ret = iep_drm_attach_unlock(session_info->iommu_info);
360*4882a593Smuzhiyun 		if (ret)
361*4882a593Smuzhiyun 			goto fail_out;
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	attach = dma_buf_attach(drm_buffer->dma_buf, dev);
365*4882a593Smuzhiyun 	if (IS_ERR(attach)) {
366*4882a593Smuzhiyun 		ret = PTR_ERR(attach);
367*4882a593Smuzhiyun 		goto fail_out;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	get_dma_buf(drm_buffer->dma_buf);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
373*4882a593Smuzhiyun 	if (IS_ERR(sgt)) {
374*4882a593Smuzhiyun 		ret = PTR_ERR(sgt);
375*4882a593Smuzhiyun 		goto fail_detach;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	drm_buffer->iova = sg_dma_address(sgt->sgl);
379*4882a593Smuzhiyun 	drm_buffer->size = drm_buffer->dma_buf->size;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	drm_buffer->attach = attach;
382*4882a593Smuzhiyun 	drm_buffer->sgt = sgt;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (!drm_info->attached)
385*4882a593Smuzhiyun 		iommu_detach_device(domain, dev);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	mutex_unlock(&iommu_info->iommu_mutex);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	INIT_LIST_HEAD(&drm_buffer->list);
390*4882a593Smuzhiyun 	mutex_lock(&session_info->list_mutex);
391*4882a593Smuzhiyun 	session_info->buffer_nums++;
392*4882a593Smuzhiyun 	vpu_iommu_debug(session_info->debug_level, DEBUG_IOMMU_NORMAL,
393*4882a593Smuzhiyun 			"buffer nums %d\n", session_info->buffer_nums);
394*4882a593Smuzhiyun 	drm_buffer->index = session_info->max_idx;
395*4882a593Smuzhiyun 	list_add_tail(&drm_buffer->list, &session_info->buffer_list);
396*4882a593Smuzhiyun 	session_info->max_idx++;
397*4882a593Smuzhiyun 	if ((session_info->max_idx & 0xfffffff) == 0)
398*4882a593Smuzhiyun 		session_info->max_idx = 0;
399*4882a593Smuzhiyun 	mutex_unlock(&session_info->list_mutex);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return drm_buffer->index;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun fail_detach:
404*4882a593Smuzhiyun 	dev_err(dev, "dmabuf map attach failed\n");
405*4882a593Smuzhiyun 	dma_buf_detach(drm_buffer->dma_buf, attach);
406*4882a593Smuzhiyun 	dma_buf_put(drm_buffer->dma_buf);
407*4882a593Smuzhiyun fail_out:
408*4882a593Smuzhiyun 	kfree(drm_buffer);
409*4882a593Smuzhiyun 	mutex_unlock(&iommu_info->iommu_mutex);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	return ret;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
iep_drm_create(struct iep_iommu_info * iommu_info)414*4882a593Smuzhiyun static int iep_drm_create(struct iep_iommu_info *iommu_info)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	iommu_info->private = kzalloc(sizeof(*drm_info),
419*4882a593Smuzhiyun 				      GFP_KERNEL);
420*4882a593Smuzhiyun 	drm_info = iommu_info->private;
421*4882a593Smuzhiyun 	if (!drm_info)
422*4882a593Smuzhiyun 		return -ENOMEM;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	drm_info->domain = iommu_get_domain_for_dev(iommu_info->dev);
425*4882a593Smuzhiyun 	drm_info->attached = false;
426*4882a593Smuzhiyun 	if (!drm_info->domain) {
427*4882a593Smuzhiyun 		kfree(iommu_info->private);
428*4882a593Smuzhiyun 		return -ENOMEM;
429*4882a593Smuzhiyun 	}
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
iep_drm_destroy(struct iep_iommu_info * iommu_info)434*4882a593Smuzhiyun static int iep_drm_destroy(struct iep_iommu_info *iommu_info)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	struct iep_iommu_drm_info *drm_info = iommu_info->private;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	iep_drm_detach(iommu_info);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	kfree(drm_info);
441*4882a593Smuzhiyun 	iommu_info->private = NULL;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun static struct iep_iommu_ops drm_ops = {
447*4882a593Smuzhiyun 	.create = iep_drm_create,
448*4882a593Smuzhiyun 	.import = iep_drm_import,
449*4882a593Smuzhiyun 	.free = iep_drm_free,
450*4882a593Smuzhiyun 	.free_fd = iep_drm_free_fd,
451*4882a593Smuzhiyun 	.map_iommu = iep_drm_map_iommu,
452*4882a593Smuzhiyun 	.unmap_iommu = iep_drm_unmap_iommu,
453*4882a593Smuzhiyun 	.destroy = iep_drm_destroy,
454*4882a593Smuzhiyun 	.dump = vcdoec_drm_dump_info,
455*4882a593Smuzhiyun 	.attach = iep_drm_attach,
456*4882a593Smuzhiyun 	.detach = iep_drm_detach,
457*4882a593Smuzhiyun 	.clear = iep_drm_clear_session,
458*4882a593Smuzhiyun };
459*4882a593Smuzhiyun 
iep_iommu_drm_set_ops(struct iep_iommu_info * iommu_info)460*4882a593Smuzhiyun void iep_iommu_drm_set_ops(struct iep_iommu_info *iommu_info)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	if (!iommu_info)
463*4882a593Smuzhiyun 		return;
464*4882a593Smuzhiyun 	iommu_info->ops = &drm_ops;
465*4882a593Smuzhiyun }
466