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