xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/iep/iep_iommu_ops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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