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