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 <string.h>
18 #include <wsbm_pool.h>
19 #include <wsbm_driver.h>
20 #include <wsbm_manager.h>
21 #include <wsbm_util.h>
22 #include <drm/ttm/ttm_placement.h>
23 #include <linux/psb_drm.h>
24 #include <xf86drm.h>
25 #include <HwcTrace.h>
26 
27 struct _WsbmBufferPool * mainPool = NULL;
28 
29 struct PsbWsbmValidateNode
30 {
31     struct  _ValidateNode base;
32     struct psb_validate_arg arg;
33 };
34 
align_to(uint32_t arg,uint32_t align)35 static inline uint32_t align_to(uint32_t arg, uint32_t align)
36 {
37     return ((arg + (align - 1)) & (~(align - 1)));
38 }
39 
pvrAlloc(struct _WsbmVNodeFuncs * func,int typeId)40 static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func,
41                                        int typeId)
42 {
43     CTRACE();
44     if(typeId == 0) {
45         struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode));
46         if(!vNode) {
47             ETRACE("failed to allocate memory");
48             return NULL;
49         }
50 
51         vNode->base.func = func;
52         vNode->base.type_id = 0;
53         return &vNode->base;
54     } else {
55         struct _ValidateNode * node = malloc(sizeof(*node));
56         if(!node) {
57             ETRACE("failed to allocate node");
58             return NULL;
59         }
60 
61         node->func = func;
62         node->type_id = 1;
63         return node;
64     }
65 }
66 
pvrFree(struct _ValidateNode * node)67 static void pvrFree(struct _ValidateNode * node)
68 {
69     CTRACE();
70     if(node->type_id == 0) {
71         free(containerOf(node, struct PsbWsbmValidateNode, base));
72     } else {
73         free(node);
74     }
75 }
76 
pvrClear(struct _ValidateNode * node)77 static void pvrClear(struct _ValidateNode * node)
78 {
79     CTRACE();
80     if(node->type_id == 0) {
81         struct PsbWsbmValidateNode * vNode =
82             containerOf(node, struct PsbWsbmValidateNode, base);
83         memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req));
84     }
85 }
86 
87 static struct _WsbmVNodeFuncs vNodeFuncs = {
88     .alloc  = pvrAlloc,
89     .free   = pvrFree,
90     .clear  = pvrClear,
91 };
92 
psbWsbmTakedown()93 void psbWsbmTakedown()
94 {
95     CTRACE();
96 
97     if (mainPool) {
98         wsbmPoolTakeDown(mainPool);
99         mainPool = NULL;
100     }
101 
102     if (wsbmIsInitialized()) {
103         wsbmTakedown();
104     }
105 }
106 
psbWsbmInitialize(int drmFD)107 int psbWsbmInitialize(int drmFD)
108 {
109     union drm_psb_extension_arg arg;
110     const char drmExt[] = "psb_ttm_placement_alphadrop";
111     int ret = 0;
112 
113     CTRACE();
114 
115     if (drmFD <= 0) {
116         ETRACE("invalid drm fd %d", drmFD);
117         return drmFD;
118     }
119 
120     /*init wsbm*/
121     ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs);
122     if (ret) {
123         ETRACE("failed to initialize Wsbm, error code %d", ret);
124         return ret;
125     }
126 
127     VTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION);
128 
129     /*get devOffset via drm IOCTL*/
130     strncpy(arg.extension, drmExt, sizeof(drmExt));
131 
132     ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg));
133     if(ret || !arg.rep.exists) {
134         ETRACE("failed to get device offset, error code %d", ret);
135         goto out;
136     }
137 
138     VTRACE("ioctl offset %#x", arg.rep.driver_ioctl_offset);
139 
140     mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset);
141     if(!mainPool) {
142         ETRACE("failed to initialize TTM Pool");
143         ret = -EINVAL;
144         goto out;
145     }
146 
147     VTRACE("Wsbm initialization succeeded. mainPool %p", mainPool);
148 
149     return 0;
150 
151 out:
152     psbWsbmTakedown();
153     return ret;
154 }
155 
psbWsbmAllocateFromUB(uint32_t size,uint32_t align,void ** buf,void * user_pt)156 int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt)
157 {
158     struct _WsbmBufferObject * wsbmBuf = NULL;
159     int ret = 0;
160     int offset = 0;
161 
162     ATRACE("size %d", align_to(size, 4096));
163 
164     if(!buf || !user_pt) {
165         ETRACE("invalid parameter");
166         return -EINVAL;
167     }
168 
169     VTRACE("mainPool %p", mainPool);
170 
171     ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
172                         DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED |
173                         WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED);
174     if(ret) {
175         ETRACE("wsbmGenBuffers failed with error code %d", ret);
176         return ret;
177     }
178 
179     ret = wsbmBODataUB(wsbmBuf,
180                        align_to(size, 4096), NULL, NULL, 0,
181                        user_pt, -1);
182 
183     if(ret) {
184         ETRACE("wsbmBOData failed with error code %d", ret);
185         /*FIXME: should I unreference this buffer here?*/
186         return ret;
187     }
188 
189     *buf = wsbmBuf;
190 
191     VTRACE("ttm UB buffer allocated. %p", *buf);
192     return 0;
193 }
194 
psbWsbmAllocateTTMBuffer(uint32_t size,uint32_t align,void ** buf)195 int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf)
196 {
197     struct _WsbmBufferObject * wsbmBuf = NULL;
198     int ret = 0;
199     int offset = 0;
200 
201     ATRACE("size %d", align_to(size, 4096));
202 
203     if(!buf) {
204         ETRACE("invalid parameter");
205         return -EINVAL;
206     }
207 
208     VTRACE("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         ETRACE("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         ETRACE("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     VTRACE("ttm buffer allocated. %p", *buf);
230     return 0;
231 }
232 
psbWsbmWrapTTMBuffer(uint64_t handle,void ** buf)233 int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf)
234 {
235     int ret = 0;
236     struct _WsbmBufferObject *wsbmBuf;
237 
238     if (!buf) {
239         ETRACE("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         ETRACE("wsbmGenBuffers failed with error code %d", ret);
249         return ret;
250     }
251 
252     ret = wsbmBOSetReferenced(wsbmBuf, handle);
253     if (ret) {
254         ETRACE("wsbmBOSetReferenced failed with error code %d", ret);
255         return ret;
256     }
257 
258     *buf = (void *)wsbmBuf;
259 
260     VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
261     return 0;
262 }
263 
psbWsbmWrapTTMBuffer2(uint64_t handle,void ** buf)264 int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf)
265 {
266     int ret = 0;
267     struct _WsbmBufferObject *wsbmBuf;
268 
269     if (!buf) {
270         ETRACE("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         ETRACE("wsbmGenBuffers failed with error code %d", ret);
279         return ret;
280     }
281 
282     *buf = (void *)wsbmBuf;
283 
284     VTRACE("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         ETRACE("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         ETRACE("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         ETRACE("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         ETRACE("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     XTRACE();
340 
341     return 0;
342 }
343 
psbWsbmGetCPUAddress(void * buf)344 void * psbWsbmGetCPUAddress(void * buf)
345 {
346     if(!buf) {
347         ETRACE("invalid ttm buffer");
348         return NULL;
349     }
350 
351     VTRACE("buffer object %p", buf);
352 
353     void * address = wsbmBOMap((struct _WsbmBufferObject *)buf,
354                                 WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
355     if(!address) {
356         ETRACE("failed to map buffer object");
357         return NULL;
358     }
359 
360     VTRACE("mapped successfully. %p, size %ld",
361         address, wsbmBOSize((struct _WsbmBufferObject *)buf));
362 
363     return address;
364 }
365 
psbWsbmGetGttOffset(void * buf)366 uint32_t psbWsbmGetGttOffset(void * buf)
367 {
368     if(!buf) {
369         ETRACE("invalid ttm buffer");
370         return 0;
371     }
372 
373     VTRACE("buffer object %p", buf);
374 
375     uint32_t offset =
376         wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000;
377 
378     VTRACE("offset %#x", offset >> 12);
379 
380     return offset >> 12;
381 }
382 
psbWsbmGetKBufHandle(void * buf)383 uint32_t psbWsbmGetKBufHandle(void *buf)
384 {
385     if (!buf) {
386         ETRACE("invalid ttm buffer");
387         return 0;
388     }
389 
390     return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf)));
391 }
392 
psbWsbmWaitIdle(void * buf)393 uint32_t psbWsbmWaitIdle(void *buf)
394 {
395     if (!buf) {
396         ETRACE("invalid ttm buffer");
397         return -EINVAL;
398     }
399 
400     wsbmBOWaitIdle(buf, 0);
401     return 0;
402 }
403