1 /*
2 // Copyright (c) 2014 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <malloc.h>
18 #include <string.h>
19 #include <wsbm_pool.h>
20 #include <wsbm_driver.h>
21 #include <wsbm_manager.h>
22 #include <wsbm_util.h>
23 #include <drm/ttm/ttm_placement.h>
24 #include <linux/psb_drm.h>
25 #include <xf86drm.h>
26 #include <common/utils/HwcTrace.h>
27
28 struct _WsbmBufferPool * mainPool = NULL;
29
30 struct PsbWsbmValidateNode
31 {
32 struct _ValidateNode base;
33 struct psb_validate_arg arg;
34 };
35
align_to(uint32_t arg,uint32_t align)36 static inline uint32_t align_to(uint32_t arg, uint32_t align)
37 {
38 return ((arg + (align - 1)) & (~(align - 1)));
39 }
40
pvrAlloc(struct _WsbmVNodeFuncs * func,int typeId)41 static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func,
42 int typeId)
43 {
44 CTRACE();
45 if(typeId == 0) {
46 struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode));
47 if(!vNode) {
48 ELOGTRACE("failed to allocate memory");
49 return NULL;
50 }
51
52 vNode->base.func = func;
53 vNode->base.type_id = 0;
54 return &vNode->base;
55 } else {
56 struct _ValidateNode * node = malloc(sizeof(*node));
57 if(!node) {
58 ELOGTRACE("failed to allocate node");
59 return NULL;
60 }
61
62 node->func = func;
63 node->type_id = 1;
64 return node;
65 }
66 }
67
pvrFree(struct _ValidateNode * node)68 static void pvrFree(struct _ValidateNode * node)
69 {
70 CTRACE();
71 if(node->type_id == 0) {
72 free(containerOf(node, struct PsbWsbmValidateNode, base));
73 } else {
74 free(node);
75 }
76 }
77
pvrClear(struct _ValidateNode * node)78 static void pvrClear(struct _ValidateNode * node)
79 {
80 CTRACE();
81 if(node->type_id == 0) {
82 struct PsbWsbmValidateNode * vNode =
83 containerOf(node, struct PsbWsbmValidateNode, base);
84 memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req));
85 }
86 }
87
88 static struct _WsbmVNodeFuncs vNodeFuncs = {
89 .alloc = pvrAlloc,
90 .free = pvrFree,
91 .clear = pvrClear,
92 };
93
psbWsbmTakedown()94 void psbWsbmTakedown()
95 {
96 CTRACE();
97
98 if (mainPool) {
99 wsbmPoolTakeDown(mainPool);
100 mainPool = NULL;
101 }
102
103 if (wsbmIsInitialized()) {
104 wsbmTakedown();
105 }
106 }
107
psbWsbmInitialize(int drmFD)108 int psbWsbmInitialize(int drmFD)
109 {
110 union drm_psb_extension_arg arg;
111 const char drmExt[] = "psb_ttm_placement_alphadrop";
112 int ret = 0;
113
114 CTRACE();
115
116 if (drmFD <= 0) {
117 ELOGTRACE("invalid drm fd %d", drmFD);
118 return drmFD;
119 }
120
121 /*init wsbm*/
122 ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs);
123 if (ret) {
124 ELOGTRACE("failed to initialize Wsbm, error code %d", ret);
125 return ret;
126 }
127
128 VLOGTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION);
129
130 /*get devOffset via drm IOCTL*/
131 strncpy(arg.extension, drmExt, sizeof(drmExt));
132
133 ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg));
134 if(ret || !arg.rep.exists) {
135 ELOGTRACE("failed to get device offset, error code %d", ret);
136 goto out;
137 }
138
139 unsigned int ioctl_offset = arg.rep.driver_ioctl_offset;
140 ILOGTRACE("ioctl offset %#x", ioctl_offset);
141
142 mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset);
143 if(!mainPool) {
144 ELOGTRACE("failed to initialize TTM Pool");
145 ret = -EINVAL;
146 goto out;
147 }
148
149 VLOGTRACE("Wsbm initialization succeeded. mainPool %p", mainPool);
150
151 return 0;
152
153 out:
154 psbWsbmTakedown();
155 return ret;
156 }
157
psbWsbmAllocateFromUB(uint32_t size,uint32_t align,void ** buf,void * user_pt)158 int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt)
159 {
160 struct _WsbmBufferObject * wsbmBuf = NULL;
161 int ret = 0;
162
163 ALOGTRACE("size %d", align_to(size, 4096));
164
165 if(!buf || !user_pt) {
166 ELOGTRACE("invalid parameter");
167 return -EINVAL;
168 }
169
170 VLOGTRACE("mainPool %p", mainPool);
171
172 ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
173 DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED |
174 WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED);
175 if(ret) {
176 ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
177 return ret;
178 }
179
180 ret = wsbmBODataUB(wsbmBuf,
181 align_to(size, 4096), NULL, NULL, 0,
182 user_pt, -1);
183
184 if(ret) {
185 ELOGTRACE("wsbmBOData failed with error code %d", ret);
186 /*FIXME: should I unreference this buffer here?*/
187 return ret;
188 }
189
190 *buf = wsbmBuf;
191
192 VLOGTRACE("ttm UB buffer allocated. %p", *buf);
193 return 0;
194 }
195
psbWsbmAllocateTTMBuffer(uint32_t size,uint32_t align,void ** buf)196 int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf)
197 {
198 struct _WsbmBufferObject * wsbmBuf = NULL;
199 int ret = 0;
200
201 ALOGTRACE("size %d", align_to(size, 4096));
202
203 if(!buf) {
204 ELOGTRACE("invalid parameter");
205 return -EINVAL;
206 }
207
208 VLOGTRACE("mainPool %p", mainPool);
209
210 ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
211 (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
212 WSBM_PL_FLAG_SHARED | WSBM_PL_FLAG_NO_EVICT));
213 if(ret) {
214 ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
215 return ret;
216 }
217
218 ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0);
219 if(ret) {
220 ELOGTRACE("wsbmBOData failed with error code %d", ret);
221 /*FIXME: should I unreference this buffer here?*/
222 return ret;
223 }
224
225 /* wsbmBOReference(wsbmBuf); */ /* no need to add reference */
226
227 *buf = wsbmBuf;
228
229 VLOGTRACE("ttm buffer allocated. %p", *buf);
230 return 0;
231 }
232
psbWsbmWrapTTMBuffer(uint32_t handle,void ** buf)233 int psbWsbmWrapTTMBuffer(uint32_t handle, void **buf)
234 {
235 int ret = 0;
236 struct _WsbmBufferObject *wsbmBuf;
237
238 if (!buf) {
239 ELOGTRACE("invalid parameter");
240 return -EINVAL;
241 }
242
243 ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 0,
244 (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
245 /*WSBM_PL_FLAG_NO_EVICT |*/ WSBM_PL_FLAG_SHARED));
246
247 if (ret) {
248 ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
249 return ret;
250 }
251
252 ret = wsbmBOSetReferenced(wsbmBuf, handle);
253 if (ret) {
254 ELOGTRACE("wsbmBOSetReferenced failed with error code %d", ret);
255 return ret;
256 }
257
258 *buf = (void *)wsbmBuf;
259
260 VLOGTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
261 return 0;
262 }
263
psbWsbmWrapTTMBuffer2(uint32_t handle,void ** buf)264 int psbWsbmWrapTTMBuffer2(uint32_t handle, void **buf)
265 {
266 int ret = 0;
267 struct _WsbmBufferObject *wsbmBuf;
268
269 if (!buf) {
270 ELOGTRACE("invalid parameter");
271 return -EINVAL;
272 }
273
274 ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 4096,
275 (WSBM_PL_FLAG_SHARED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_UNCACHED));
276
277 if (ret) {
278 ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
279 return ret;
280 }
281
282 *buf = (void *)wsbmBuf;
283
284 VLOGTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
285 return 0;
286 }
287
288
psbWsbmCreateFromUB(void * buf,uint32_t size,void * vaddr)289 int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr)
290 {
291 int ret = 0;
292 struct _WsbmBufferObject *wsbmBuf;
293
294 if (!buf || !vaddr) {
295 ELOGTRACE("invalid parameter");
296 return -EINVAL;
297 }
298
299 wsbmBuf = (struct _WsbmBufferObject *)buf;
300 ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr, -1);
301 if (ret) {
302 ELOGTRACE("wsbmBODataUB failed with error code %d", ret);
303 return ret;
304 }
305
306 return 0;
307 }
308
psbWsbmUnReference(void * buf)309 int psbWsbmUnReference(void *buf)
310 {
311 struct _WsbmBufferObject *wsbmBuf;
312
313 if (!buf) {
314 ELOGTRACE("invalid parameter");
315 return -EINVAL;
316 }
317
318 wsbmBuf = (struct _WsbmBufferObject *)buf;
319
320 wsbmBOUnreference(&wsbmBuf);
321
322 return 0;
323 }
324
psbWsbmDestroyTTMBuffer(void * buf)325 int psbWsbmDestroyTTMBuffer(void * buf)
326 {
327 CTRACE();
328
329 if(!buf) {
330 ELOGTRACE("invalid ttm buffer");
331 return -EINVAL;
332 }
333
334 /*FIXME: should I unmap this buffer object first?*/
335 wsbmBOUnmap((struct _WsbmBufferObject *)buf);
336
337 wsbmBOUnreference((struct _WsbmBufferObject **)&buf);
338
339 XLOGTRACE();
340
341 return 0;
342 }
343
psbWsbmGetCPUAddress(void * buf)344 void * psbWsbmGetCPUAddress(void * buf)
345 {
346 if(!buf) {
347 ELOGTRACE("invalid ttm buffer");
348 return NULL;
349 }
350
351 VLOGTRACE("buffer object %p", buf);
352
353 void * address = wsbmBOMap((struct _WsbmBufferObject *)buf,
354 WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
355 if(!address) {
356 ELOGTRACE("failed to map buffer object");
357 return NULL;
358 }
359
360 unsigned long buf_size = wsbmBOSize((struct _WsbmBufferObject *)buf);
361 VLOGTRACE("mapped successfully. %p, size %ld",
362 address, buf_size);
363
364 return address;
365 }
366
psbWsbmGetGttOffset(void * buf)367 uint32_t psbWsbmGetGttOffset(void * buf)
368 {
369 if(!buf) {
370 ELOGTRACE("invalid ttm buffer");
371 return 0;
372 }
373
374 VLOGTRACE("buffer object %p", buf);
375
376 uint32_t offset =
377 wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000;
378
379 uint32_t offset_tmp = offset >> 12;
380 VLOGTRACE("offset %#x", offset_tmp);
381
382 return offset >> 12;
383 }
384
psbWsbmGetKBufHandle(void * buf)385 uint32_t psbWsbmGetKBufHandle(void *buf)
386 {
387 if (!buf) {
388 ELOGTRACE("invalid ttm buffer");
389 return 0;
390 }
391
392 return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf)));
393 }
394
psbWsbmWaitIdle(void * buf)395 uint32_t psbWsbmWaitIdle(void *buf)
396 {
397 if (!buf) {
398 ELOGTRACE("invalid ttm buffer");
399 return -EINVAL;
400 }
401
402 wsbmBOWaitIdle(buf, 0);
403 return 0;
404 }
405