video: rockchip: vcodec: fix fd import error
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / vcodec / vcodec_iommu_ops.c
1 /**
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
5  *
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.
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  */
16
17 #include <linux/slab.h>
18
19 #include "vcodec_iommu_ops.h"
20
21 static
22 struct vcodec_iommu_session_info *vcodec_iommu_get_session_info
23         (struct vcodec_iommu_info *iommu_info, struct vpu_session *session)
24 {
25         struct vcodec_iommu_session_info *session_info = NULL, *n;
26
27         list_for_each_entry_safe(session_info, n, &iommu_info->session_list,
28                                  head) {
29                 if (session_info->session == session)
30                         return session_info;
31         }
32
33         return NULL;
34 }
35
36 int vcodec_iommu_create(struct vcodec_iommu_info *iommu_info)
37 {
38         if (!iommu_info || !iommu_info->ops->create)
39                 return -EINVAL;
40
41         return iommu_info->ops->create(iommu_info);
42 }
43
44 int vcodec_iommu_import(struct vcodec_iommu_info *iommu_info,
45                         struct vpu_session *session, int fd)
46 {
47         struct vcodec_iommu_session_info *session_info = NULL;
48
49         if (!iommu_info || !iommu_info->ops->import || !session)
50                 return -EINVAL;
51
52         session_info = vcodec_iommu_get_session_info(iommu_info, session);
53         if (!session_info) {
54                 session_info = kzalloc(sizeof(*session_info), GFP_KERNEL);
55                 if (!session_info)
56                         return -ENOMEM;
57
58                 INIT_LIST_HEAD(&session_info->head);
59                 INIT_LIST_HEAD(&session_info->buffer_list);
60                 mutex_init(&session_info->list_mutex);
61                 session_info->max_idx = 0;
62                 session_info->session = session;
63                 session_info->mmu_dev = iommu_info->mmu_dev;
64                 session_info->dev = iommu_info->dev;
65                 session_info->iommu_info = iommu_info;
66                 mutex_lock(&iommu_info->list_mutex);
67                 list_add_tail(&session_info->head, &iommu_info->session_list);
68                 mutex_unlock(&iommu_info->list_mutex);
69         }
70
71         session_info->debug_level = iommu_info->debug_level;
72
73         return iommu_info->ops->import(session_info, fd);
74 }
75
76 int vcodec_iommu_free(struct vcodec_iommu_info *iommu_info,
77                       struct vpu_session *session, int idx)
78 {
79         struct vcodec_iommu_session_info *session_info = NULL;
80
81         session_info = vcodec_iommu_get_session_info(iommu_info, session);
82
83         if (!iommu_info || !iommu_info->ops->free || !session_info)
84                 return -EINVAL;
85
86         return iommu_info->ops->free(session_info, idx);
87 }
88
89 int vcodec_iommu_free_fd(struct vcodec_iommu_info *iommu_info,
90                          struct vpu_session *session, int fd)
91 {
92         struct vcodec_iommu_session_info *session_info = NULL;
93
94         session_info = vcodec_iommu_get_session_info(iommu_info, session);
95
96         if (!iommu_info || !iommu_info->ops->free_fd || !session_info)
97                 return -EINVAL;
98
99         return iommu_info->ops->free_fd(session_info, fd);
100 }
101
102 void *vcodec_iommu_map_kernel(struct vcodec_iommu_info *iommu_info,
103                                  struct vpu_session *session, int idx)
104 {
105         struct vcodec_iommu_session_info *session_info = NULL;
106
107         session_info = vcodec_iommu_get_session_info(iommu_info, session);
108
109         if (!iommu_info || !iommu_info->ops->map_kernel || !session_info)
110                 return NULL;
111
112         return iommu_info->ops->map_kernel(session_info, idx);
113 }
114
115 int vcodec_iommu_unmap_kernel(struct vcodec_iommu_info *iommu_info,
116                               struct vpu_session *session, int idx)
117 {
118         struct vcodec_iommu_session_info *session_info = NULL;
119
120         session_info = vcodec_iommu_get_session_info(iommu_info, session);
121
122         if (!iommu_info || !iommu_info->ops->unmap_kernel || !session_info)
123                 return -EINVAL;
124
125         return iommu_info->ops->unmap_kernel(session_info, idx);
126 }
127
128 int vcodec_iommu_map_iommu(struct vcodec_iommu_info *iommu_info,
129                            struct vpu_session *session,
130                            int idx, unsigned long *iova,
131                            unsigned long *size)
132 {
133         struct vcodec_iommu_session_info *session_info = NULL;
134
135         session_info = vcodec_iommu_get_session_info(iommu_info, session);
136
137         if (!iommu_info || !iommu_info->ops->map_iommu || !session_info)
138                 return -EINVAL;
139
140         return iommu_info->ops->map_iommu(session_info, idx, iova, size);
141 }
142
143 int vcodec_iommu_unmap_iommu(struct vcodec_iommu_info *iommu_info,
144                              struct vpu_session *session, int idx)
145 {
146         struct vcodec_iommu_session_info *session_info = NULL;
147
148         session_info = vcodec_iommu_get_session_info(iommu_info, session);
149
150         if (!iommu_info || !iommu_info->ops->unmap_iommu || !session_info)
151                 return -EINVAL;
152
153         return iommu_info->ops->unmap_iommu(session_info, idx);
154 }
155
156 int vcodec_iommu_destroy(struct vcodec_iommu_info *iommu_info)
157 {
158         if (!iommu_info || !iommu_info->ops->destroy)
159                 return -EINVAL;
160
161         return iommu_info->ops->destroy(iommu_info);
162 }
163
164 void vcodec_iommu_dump(struct vcodec_iommu_info *iommu_info,
165                        struct vpu_session *session)
166 {
167         struct vcodec_iommu_session_info *session_info = NULL;
168
169         session_info = vcodec_iommu_get_session_info(iommu_info, session);
170
171         if (!iommu_info || !iommu_info->ops->dump || !session_info)
172                 return;
173
174         iommu_info->ops->dump(session_info);
175 }
176
177 void vcodec_iommu_clear(struct vcodec_iommu_info *iommu_info,
178                         struct vpu_session *session)
179 {
180         struct vcodec_iommu_session_info *session_info = NULL;
181
182         session_info = vcodec_iommu_get_session_info(iommu_info, session);
183
184         if (!iommu_info || !iommu_info->ops->clear || !session_info)
185                 return;
186
187         iommu_info->ops->clear(session_info);
188
189         mutex_lock(&iommu_info->list_mutex);
190         list_del_init(&session_info->head);
191         kfree(session_info);
192         mutex_unlock(&iommu_info->list_mutex);
193 }
194
195 int vcodec_iommu_attach(struct vcodec_iommu_info *iommu_info)
196 {
197         if (!iommu_info || !iommu_info->ops->attach)
198                 return 0;
199
200         return iommu_info->ops->attach(iommu_info);
201 }
202
203 void vcodec_iommu_detach(struct vcodec_iommu_info *iommu_info)
204 {
205         if (!iommu_info || !iommu_info->ops->detach)
206                 return;
207
208         return iommu_info->ops->detach(iommu_info);
209 }
210
211 struct vcodec_iommu_info *
212 vcodec_iommu_info_create(struct device *dev,
213                          struct device *mmu_dev,
214                          int alloc_type)
215 {
216         struct vcodec_iommu_info *iommu_info = NULL;
217
218         iommu_info = kzalloc(sizeof(*iommu_info), GFP_KERNEL);
219         if (!iommu_info)
220                 return NULL;
221
222         iommu_info->dev = dev;
223         INIT_LIST_HEAD(&iommu_info->session_list);
224         mutex_init(&iommu_info->list_mutex);
225         mutex_init(&iommu_info->iommu_mutex);
226         switch (alloc_type) {
227 #ifdef CONFIG_DRM
228         case ALLOCATOR_USE_DRM:
229                 vcodec_iommu_drm_set_ops(iommu_info);
230                 break;
231 #endif
232 #ifdef CONFIG_ION
233         case ALLOCATOR_USE_ION:
234                 vcodec_iommu_ion_set_ops(iommu_info);
235                 break;
236 #endif
237         default:
238                 iommu_info->ops = NULL;
239                 break;
240         }
241
242         iommu_info->mmu_dev = mmu_dev;
243
244         vcodec_iommu_create(iommu_info);
245
246         return iommu_info;
247 }
248
249 int vcodec_iommu_info_destroy(struct vcodec_iommu_info *iommu_info)
250 {
251         vcodec_iommu_destroy(iommu_info);
252         kfree(iommu_info);
253
254         return 0;
255 }