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
28struct _WsbmBufferPool * mainPool = NULL;
29
30struct PsbWsbmValidateNode
31{
32    struct  _ValidateNode base;
33    struct psb_validate_arg arg;
34};
35
36static inline uint32_t align_to(uint32_t arg, uint32_t align)
37{
38    return ((arg + (align - 1)) & (~(align - 1)));
39}
40
41static 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
68static 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
78static 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
88static struct _WsbmVNodeFuncs vNodeFuncs = {
89    .alloc  = pvrAlloc,
90    .free   = pvrFree,
91    .clear  = pvrClear,
92};
93
94void psbWsbmTakedown()
95{
96    CTRACE();
97
98    if (mainPool) {
99        wsbmPoolTakeDown(mainPool);
100        mainPool = NULL;
101    }
102
103    if (wsbmIsInitialized()) {
104        wsbmTakedown();
105    }
106}
107
108int 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
153out:
154    psbWsbmTakedown();
155    return ret;
156}
157
158int 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
196int 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
233int 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
264int 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
289int 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
309int 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
325int 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
344void * 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
367uint32_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
385uint32_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
395uint32_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