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 "iep_iommu_ops.h"
20
21 static
iep_iommu_get_session_info(struct iep_iommu_info * iommu_info,struct iep_session * session)22 struct iep_iommu_session_info *iep_iommu_get_session_info
23 (struct iep_iommu_info *iommu_info, struct iep_session *session)
24 {
25 struct iep_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
iep_iommu_create(struct iep_iommu_info * iommu_info)36 int iep_iommu_create(struct iep_iommu_info *iommu_info)
37 {
38 if (!iommu_info || !iommu_info->ops || !iommu_info->ops->create)
39 return -EINVAL;
40
41 return iommu_info->ops->create(iommu_info);
42 }
43
iep_iommu_import(struct iep_iommu_info * iommu_info,struct iep_session * session,int fd)44 int iep_iommu_import(struct iep_iommu_info *iommu_info,
45 struct iep_session *session, int fd)
46 {
47 struct iep_iommu_session_info *session_info = NULL;
48
49 if (!iommu_info || !iommu_info->ops ||
50 !iommu_info->ops->import || !session)
51 return -EINVAL;
52
53 session_info = iep_iommu_get_session_info(iommu_info, session);
54 if (!session_info) {
55 session_info = kzalloc(sizeof(*session_info), GFP_KERNEL);
56 if (!session_info)
57 return -ENOMEM;
58
59 INIT_LIST_HEAD(&session_info->head);
60 INIT_LIST_HEAD(&session_info->buffer_list);
61 mutex_init(&session_info->list_mutex);
62 session_info->max_idx = 0;
63 session_info->session = session;
64 session_info->mmu_dev = iommu_info->mmu_dev;
65 session_info->dev = iommu_info->dev;
66 session_info->iommu_info = iommu_info;
67 session_info->buffer_nums = 0;
68 mutex_lock(&iommu_info->list_mutex);
69 list_add_tail(&session_info->head, &iommu_info->session_list);
70 mutex_unlock(&iommu_info->list_mutex);
71 }
72
73 session_info->debug_level = iommu_info->debug_level;
74
75 return iommu_info->ops->import(session_info, fd);
76 }
77
iep_iommu_free(struct iep_iommu_info * iommu_info,struct iep_session * session,int idx)78 int iep_iommu_free(struct iep_iommu_info *iommu_info,
79 struct iep_session *session, int idx)
80 {
81 struct iep_iommu_session_info *session_info = NULL;
82
83 if (!iommu_info)
84 return -EINVAL;
85
86 session_info = iep_iommu_get_session_info(iommu_info, session);
87
88 if (!iommu_info->ops || !iommu_info->ops->free || !session_info)
89 return -EINVAL;
90
91 return iommu_info->ops->free(session_info, idx);
92 }
93
iep_iommu_free_fd(struct iep_iommu_info * iommu_info,struct iep_session * session,int fd)94 int iep_iommu_free_fd(struct iep_iommu_info *iommu_info,
95 struct iep_session *session, int fd)
96 {
97 struct iep_iommu_session_info *session_info = NULL;
98
99 if (!iommu_info)
100 return -EINVAL;
101
102 session_info = iep_iommu_get_session_info(iommu_info, session);
103
104 if (!iommu_info->ops || !iommu_info->ops->free_fd || !session_info)
105 return -EINVAL;
106
107 return iommu_info->ops->free_fd(session_info, fd);
108 }
109
iep_iommu_map_iommu(struct iep_iommu_info * iommu_info,struct iep_session * session,int idx,unsigned long * iova,unsigned long * size)110 int iep_iommu_map_iommu(struct iep_iommu_info *iommu_info,
111 struct iep_session *session,
112 int idx, unsigned long *iova,
113 unsigned long *size)
114 {
115 struct iep_iommu_session_info *session_info = NULL;
116
117 if (!iommu_info)
118 return -EINVAL;
119
120 session_info = iep_iommu_get_session_info(iommu_info, session);
121
122 if (!iommu_info->ops || !iommu_info->ops->map_iommu || !session_info)
123 return -EINVAL;
124
125 return iommu_info->ops->map_iommu(session_info, idx, iova, size);
126 }
127
iep_iommu_unmap_iommu(struct iep_iommu_info * iommu_info,struct iep_session * session,int idx)128 int iep_iommu_unmap_iommu(struct iep_iommu_info *iommu_info,
129 struct iep_session *session, int idx)
130 {
131 struct iep_iommu_session_info *session_info = NULL;
132
133 if (!iommu_info)
134 return -EINVAL;
135
136 session_info = iep_iommu_get_session_info(iommu_info, session);
137
138 if (!iommu_info->ops || !iommu_info->ops->unmap_iommu || !session_info)
139 return -EINVAL;
140
141 return iommu_info->ops->unmap_iommu(session_info, idx);
142 }
143
iep_iommu_destroy(struct iep_iommu_info * iommu_info)144 int iep_iommu_destroy(struct iep_iommu_info *iommu_info)
145 {
146 if (!iommu_info || !iommu_info->ops || !iommu_info->ops->destroy)
147 return -EINVAL;
148
149 return iommu_info->ops->destroy(iommu_info);
150 }
151
iep_iommu_dump(struct iep_iommu_info * iommu_info,struct iep_session * session)152 void iep_iommu_dump(struct iep_iommu_info *iommu_info,
153 struct iep_session *session)
154 {
155 struct iep_iommu_session_info *session_info = NULL;
156
157 if (!iommu_info)
158 return;
159
160 session_info = iep_iommu_get_session_info(iommu_info, session);
161
162 if (!iommu_info->ops || !iommu_info->ops->dump || !session_info)
163 return;
164
165 iommu_info->ops->dump(session_info);
166 }
167
iep_iommu_clear(struct iep_iommu_info * iommu_info,struct iep_session * session)168 void iep_iommu_clear(struct iep_iommu_info *iommu_info,
169 struct iep_session *session)
170 {
171 struct iep_iommu_session_info *session_info = NULL;
172
173 if (!iommu_info)
174 return;
175
176 session_info = iep_iommu_get_session_info(iommu_info, session);
177
178 if (!iommu_info->ops || !iommu_info->ops->clear || !session_info)
179 return;
180
181 iommu_info->ops->clear(session_info);
182
183 mutex_lock(&iommu_info->list_mutex);
184 list_del_init(&session_info->head);
185 kfree(session_info);
186 mutex_unlock(&iommu_info->list_mutex);
187 }
188
iep_iommu_attach(struct iep_iommu_info * iommu_info)189 int iep_iommu_attach(struct iep_iommu_info *iommu_info)
190 {
191 if (!iommu_info || !iommu_info->ops || !iommu_info->ops->attach)
192 return 0;
193
194 return iommu_info->ops->attach(iommu_info);
195 }
196
iep_iommu_detach(struct iep_iommu_info * iommu_info)197 void iep_iommu_detach(struct iep_iommu_info *iommu_info)
198 {
199 if (!iommu_info || !iommu_info->ops || !iommu_info->ops->detach)
200 return;
201
202 return iommu_info->ops->detach(iommu_info);
203 }
204
205 struct iep_iommu_info *
iep_iommu_info_create(struct device * dev,struct device * mmu_dev,int alloc_type)206 iep_iommu_info_create(struct device *dev,
207 struct device *mmu_dev,
208 int alloc_type)
209 {
210 struct iep_iommu_info *iommu_info = NULL;
211
212 iommu_info = kzalloc(sizeof(*iommu_info), GFP_KERNEL);
213 if (!iommu_info)
214 return NULL;
215
216 iommu_info->dev = dev;
217 INIT_LIST_HEAD(&iommu_info->session_list);
218 mutex_init(&iommu_info->list_mutex);
219 mutex_init(&iommu_info->iommu_mutex);
220 switch (alloc_type) {
221 #ifdef CONFIG_DRM
222 case ALLOCATOR_USE_DRM:
223 iep_iommu_drm_set_ops(iommu_info);
224 break;
225 #endif
226 default:
227 iommu_info->ops = NULL;
228 break;
229 }
230
231 iommu_info->mmu_dev = mmu_dev;
232
233 iep_iommu_create(iommu_info);
234
235 return iommu_info;
236 }
237
iep_iommu_info_destroy(struct iep_iommu_info * iommu_info)238 int iep_iommu_info_destroy(struct iep_iommu_info *iommu_info)
239 {
240 iep_iommu_destroy(iommu_info);
241 kfree(iommu_info);
242
243 return 0;
244 }
245