~gma500/emgd/trunk

« back to all changes in this revision

Viewing changes to xserver-xorg-video-psb/xserver-xorg-video-psb-0.32.1/src/psb_ioctl.c

  • Committer: José Bernardo Bandos
  • Date: 2010-08-28 16:04:10 UTC
  • Revision ID: jbs@jbs-laptop-20100828160410-nw5zohdn37oupdv2
First step to add emgd drivers from meego

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**************************************************************************
2
 
 * Copyright (c) Intel Corp. 2007.
3
 
 * Copyright (c) Tungsten Graphics Inc., Cedar Park TX. USA.
4
 
 * All Rights Reserved.
5
 
 *
6
 
 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
7
 
 * develop this driver.
8
 
 *
9
 
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 
 * copy of this software and associated documentation files (the
11
 
 * "Software"), to deal in the Software without restriction, including
12
 
 * without limitation the rights to use, copy, modify, merge, publish,
13
 
 * distribute, sub license, and/or sell copies of the Software, and to
14
 
 * permit persons to whom the Software is furnished to do so, subject to
15
 
 * the following conditions:
16
 
 *
17
 
 * The above copyright notice and this permission notice (including the
18
 
 * next paragraph) shall be included in all copies or substantial portions
19
 
 * of the Software.
20
 
 *
21
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
24
 
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
25
 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26
 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
27
 
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
28
 
 *
29
 
 **************************************************************************/
30
 
/*
31
 
 * psb_ioctl.c - Poulsbo device-specific IOCTL interface.
32
 
 */
33
 
 
34
 
#ifdef HAVE_CONFIG_H
35
 
#include "config.h"
36
 
#endif
37
 
 
38
 
#include <stdint.h>
39
 
#include <xf86drm.h>
40
 
#include <psb_drm.h>
41
 
#include <errno.h>
42
 
#include <stdio.h>
43
 
#include <string.h>
44
 
#include <sys/time.h>
45
 
#include "psb_driver.h"
46
 
#include "psb_ioctl.h"
47
 
 
48
 
#define PSB_2D_RELOC_BUFFER_SIZE (4096*16)
49
 
#define PSB_2D_RELOC_OFFS (4096*4)
50
 
 
51
 
typedef struct _drmBONode
52
 
{
53
 
    drmMMListHead head;
54
 
    drmBO *buf;
55
 
    struct drm_bo_op_arg bo_arg;
56
 
    uint64_t arg0;
57
 
    uint64_t arg1;
58
 
} drmBONode;
59
 
 
60
 
static int
61
 
psbAddValidateItem(drmBOList * list, drmBO * buf, uint64_t flags,
62
 
                   uint64_t mask, int *itemLoc, struct _drmBONode **pNode);
63
 
 
64
 
 
65
 
static unsigned
66
 
psbTimeDiff(struct timeval *now, struct timeval *then)
67
 
{
68
 
    long long val;
69
 
 
70
 
    val = now->tv_sec - then->tv_sec;
71
 
    val *= 1000000LL;
72
 
    val += now->tv_usec;
73
 
    val -= then->tv_usec;
74
 
    if (val < 1LL)
75
 
        val = 1LL;
76
 
 
77
 
    return (unsigned)val;
78
 
}
79
 
 
80
 
static int
81
 
drmAdjustListNodes(drmBOList * list)
82
 
{
83
 
    drmBONode *node;
84
 
    drmMMListHead *l;
85
 
    int ret = 0;
86
 
 
87
 
    while (list->numCurrent < list->numTarget) {
88
 
        node = (drmBONode *) malloc(sizeof(*node));
89
 
        if (!node) {
90
 
            ret = -ENOMEM;
91
 
            break;
92
 
        }
93
 
        list->numCurrent++;
94
 
        DRMLISTADD(&node->head, &list->free);
95
 
    }
96
 
 
97
 
    while (list->numCurrent > list->numTarget) {
98
 
        l = list->free.next;
99
 
        if (l == &list->free)
100
 
            break;
101
 
        DRMLISTDEL(l);
102
 
        node = DRMLISTENTRY(drmBONode, l, head);
103
 
        free(node);
104
 
        list->numCurrent--;
105
 
    }
106
 
    return ret;
107
 
}
108
 
 
109
 
static int
110
 
drmBOCreateList(int numTarget, drmBOList * list)
111
 
{
112
 
    DRMINITLISTHEAD(&list->list);
113
 
    DRMINITLISTHEAD(&list->free);
114
 
    list->numTarget = numTarget;
115
 
    list->numCurrent = 0;
116
 
    list->numOnList = 0;
117
 
    return drmAdjustListNodes(list);
118
 
}
119
 
 
120
 
static int
121
 
drmBOResetList(drmBOList * list)
122
 
{
123
 
    drmMMListHead *l;
124
 
    int ret;
125
 
 
126
 
    ret = drmAdjustListNodes(list);
127
 
    if (ret)
128
 
        return ret;
129
 
 
130
 
    l = list->list.next;
131
 
    while (l != &list->list) {
132
 
        DRMLISTDEL(l);
133
 
        DRMLISTADD(l, &list->free);
134
 
        list->numOnList--;
135
 
        l = list->list.next;
136
 
    }
137
 
    return drmAdjustListNodes(list);
138
 
}
139
 
 
140
 
static void
141
 
drmBOFreeList(drmBOList * list)
142
 
{
143
 
    drmBONode *node;
144
 
    drmMMListHead *l;
145
 
 
146
 
    l = list->list.next;
147
 
    while (l != &list->list) {
148
 
        DRMLISTDEL(l);
149
 
        node = DRMLISTENTRY(drmBONode, l, head);
150
 
        free(node);
151
 
        l = list->list.next;
152
 
        list->numCurrent--;
153
 
        list->numOnList--;
154
 
    }
155
 
 
156
 
    l = list->free.next;
157
 
    while (l != &list->free) {
158
 
        DRMLISTDEL(l);
159
 
        node = DRMLISTENTRY(drmBONode, l, head);
160
 
        free(node);
161
 
        l = list->free.next;
162
 
        list->numCurrent--;
163
 
    }
164
 
}
165
 
 
166
 
static void
167
 
psbDRMCopyReply(const struct drm_bo_info_rep *rep, drmBO * buf)
168
 
{
169
 
    buf->handle = rep->handle;
170
 
    buf->flags = rep->flags;
171
 
    buf->size = rep->size;
172
 
    buf->offset = rep->offset;
173
 
    buf->mapHandle = rep->arg_handle;
174
 
    buf->mask = rep->mask;
175
 
    buf->start = rep->buffer_start;
176
 
    buf->fenceFlags = rep->fence_flags;
177
 
    buf->replyFlags = rep->rep_flags;
178
 
    buf->pageAlignment = rep->page_alignment;
179
 
}
180
 
 
181
 
/*
182
 
 * This is the user-space do-it-all interface to the drm cmdbuf ioctl.
183
 
 * It allows different buffers as command- and reloc buffer. A list of
184
 
 * cliprects to apply and whether to copy the clipRect content to all
185
 
 * scanout buffers (damage = 1).
186
 
 */
187
 
 
188
 
int
189
 
psbDRMCmdBuf(int fd, drmBOList * list, unsigned cmdBufHandle,
190
 
             unsigned cmdBufOffset, unsigned cmdBufSize,
191
 
             unsigned taBufHandle, unsigned taBufOffset, unsigned taBufSize,
192
 
             unsigned relocBufHandle, unsigned relocBufOffset,
193
 
             unsigned numRelocs, drm_clip_rect_t * clipRects, int damage,
194
 
             unsigned engine, unsigned fence_flags, unsigned *fence_handle)
195
 
{
196
 
 
197
 
    drmBONode *node;
198
 
    drmMMListHead *l;
199
 
    drm_psb_cmdbuf_arg_t ca;
200
 
    struct drm_bo_op_arg *arg, *first;
201
 
    struct drm_bo_op_req *req;
202
 
    struct drm_bo_info_rep *rep;
203
 
    uint64_t *prevNext = NULL;
204
 
    drmBO *buf;
205
 
    int ret;
206
 
    struct timeval then, now;
207
 
    Bool have_then = FALSE;
208
 
 
209
 
    first = NULL;
210
 
 
211
 
    for (l = list->list.next; l != &list->list; l = l->next) {
212
 
        node = DRMLISTENTRY(drmBONode, l, head);
213
 
 
214
 
        arg = &node->bo_arg;
215
 
        req = &arg->d.req;
216
 
 
217
 
        if (!first)
218
 
            first = arg;
219
 
 
220
 
        if (prevNext)
221
 
            *prevNext = (unsigned long)arg;
222
 
 
223
 
        prevNext = &arg->next;
224
 
        req->bo_req.handle = node->buf->handle;
225
 
        req->op = drm_bo_validate;
226
 
        req->bo_req.flags = node->arg0;
227
 
        req->bo_req.mask = node->arg1;
228
 
        req->bo_req.hint |= 0;
229
 
    }
230
 
 
231
 
    memset(&ca, 0, sizeof(ca));
232
 
 
233
 
    ca.buffer_list = (uint64_t) ((unsigned long)first);
234
 
    ca.clip_rects = (uint64_t) ((unsigned long)clipRects);
235
 
    ca.ta_handle = taBufHandle;
236
 
    ca.ta_offset = taBufOffset;
237
 
    ca.ta_size = taBufSize;
238
 
    ca.cmdbuf_handle = cmdBufHandle;
239
 
    ca.cmdbuf_offset = cmdBufOffset;
240
 
    ca.cmdbuf_size = cmdBufSize;
241
 
    ca.oom_size = 0;
242
 
    ca.reloc_handle = relocBufHandle;
243
 
    ca.reloc_offset = relocBufOffset;
244
 
    ca.num_relocs = numRelocs;
245
 
    ca.engine = engine;
246
 
    ca.fence_flags = fence_flags;
247
 
    ca.damage = damage;
248
 
 
249
 
    if (gettimeofday(&then, NULL))
250
 
        FatalError("Gettimeofday error.\n");
251
 
 
252
 
    /*
253
 
     * X server Signals will clobber the kernel time out mechanism.
254
 
     * we need a user-space timeout as well.
255
 
     */
256
 
 
257
 
    do {
258
 
        ret = drmCommandWriteRead(fd, DRM_PSB_CMDBUF, &ca, sizeof(ca));
259
 
        if (ret == -EAGAIN) {
260
 
            if (!have_then) {
261
 
                if (gettimeofday(&then, NULL))
262
 
                    FatalError("Gettimeofday error.\n");
263
 
                have_then = TRUE;
264
 
            }
265
 
            if (gettimeofday(&now, NULL))
266
 
                FatalError("Gettimeofday error.\n");
267
 
        }
268
 
    } while (ret == -EAGAIN && psbTimeDiff(&now, &then) < PSB_TIMEOUT_USEC);
269
 
 
270
 
    if (ret)
271
 
        return ret;
272
 
 
273
 
    for (l = list->list.next; l != &list->list; l = l->next) {
274
 
        node = DRMLISTENTRY(drmBONode, l, head);
275
 
        arg = &node->bo_arg;
276
 
        rep = &arg->d.rep.bo_info;
277
 
 
278
 
        if (!arg->handled) {
279
 
            return -EFAULT;
280
 
        }
281
 
        if (arg->d.rep.ret) {
282
 
            return arg->d.rep.ret;
283
 
        }
284
 
 
285
 
        buf = node->buf;
286
 
        psbDRMCopyReply(rep, buf);
287
 
    }
288
 
 
289
 
    return 0;
290
 
}
291
 
 
292
 
Bool
293
 
psbInit2DBuffer(int fd, Psb2DBufferPtr buf)
294
 
{
295
 
    int ret;
296
 
    void *addr;
297
 
    struct _drmBONode *node;
298
 
    struct drm_bo_info_req *req;
299
 
 
300
 
    ret = drmBOCreate(fd, PSB_2D_RELOC_BUFFER_SIZE, 0, NULL,
301
 
                      DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_EXE |
302
 
                      DRM_BO_FLAG_READ, DRM_BO_HINT_DONT_FENCE, &buf->buffer);
303
 
    if (ret)
304
 
        return FALSE;
305
 
 
306
 
    ret = drmBOMap(fd, &buf->buffer, DRM_BO_FLAG_WRITE, 0, &addr);
307
 
    buf->startCmd = addr;
308
 
    drmBOUnmap(fd, &buf->buffer);
309
 
 
310
 
    ret = drmBOCreateList(10, &buf->bufferList);
311
 
 
312
 
    if (ret)
313
 
        return FALSE;
314
 
 
315
 
    buf->fd = fd;
316
 
    buf->curCmd = buf->startCmd;
317
 
    buf->startReloc = (struct drm_psb_reloc *)
318
 
        ((unsigned long)buf->startCmd + PSB_2D_RELOC_OFFS);
319
 
    buf->curReloc = buf->startReloc;
320
 
    buf->maxRelocs = (PSB_2D_RELOC_BUFFER_SIZE - PSB_2D_RELOC_OFFS) /
321
 
        sizeof(struct drm_psb_reloc);
322
 
 
323
 
    ret = psbAddValidateItem(&buf->bufferList, &buf->buffer, 0, 0,
324
 
                             &buf->myValidateIndex, &node);
325
 
    if (ret)
326
 
        return FALSE;
327
 
 
328
 
    req = &node->bo_arg.d.req.bo_req;
329
 
    req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
330
 
    req->presumed_offset = 0; /* Local memory */
331
 
 
332
 
    return TRUE;
333
 
}
334
 
 
335
 
void
336
 
psbTakedown2DBuffer(int fd, Psb2DBufferPtr buf)
337
 
{
338
 
    drmBOFreeList(&buf->bufferList);
339
 
    (void)drmBOUnreference(fd, &buf->buffer);
340
 
}
341
 
 
342
 
static drmBONode *
343
 
psbAddListItem(drmBOList * list, drmBO * item, uint64_t arg0, uint64_t arg1)
344
 
{
345
 
    drmBONode *node;
346
 
    drmMMListHead *l;
347
 
 
348
 
    l = list->free.next;
349
 
    if (l == &list->free) {
350
 
        node = (drmBONode *) malloc(sizeof(*node));
351
 
        if (!node) {
352
 
            return NULL;
353
 
        }
354
 
        list->numCurrent++;
355
 
    } else {
356
 
        DRMLISTDEL(l);
357
 
        node = DRMLISTENTRY(drmBONode, l, head);
358
 
    }
359
 
    memset(&node->bo_arg, 0, sizeof(node->bo_arg));
360
 
    node->buf = item;
361
 
    node->arg0 = arg0;
362
 
    node->arg1 = arg1;
363
 
    DRMLISTADDTAIL(&node->head, &list->list);
364
 
    list->numOnList++;
365
 
    return node;
366
 
}
367
 
 
368
 
/*
369
 
 * Should really go into libdrm. Slightly different semantics than
370
 
 * the libdrm counterpart.
371
 
 */
372
 
 
373
 
static int
374
 
psbAddValidateItem(drmBOList * list, drmBO * buf, uint64_t flags,
375
 
                   uint64_t mask, int *itemLoc, struct _drmBONode **pNode)
376
 
{
377
 
    drmBONode *node, *cur;
378
 
    drmMMListHead *l;
379
 
    int count = 0;
380
 
 
381
 
    cur = NULL;
382
 
 
383
 
    for (l = list->list.next; l != &list->list; l = l->next) {
384
 
        node = DRMLISTENTRY(drmBONode, l, head);
385
 
        if (node->buf == buf) {
386
 
            cur = node;
387
 
            break;
388
 
        }
389
 
        count++;
390
 
    }
391
 
    if (!cur) {
392
 
        cur = psbAddListItem(list, buf, flags, mask);
393
 
        if (!cur)
394
 
            return -ENOMEM;
395
 
 
396
 
        cur->arg0 = flags;
397
 
        cur->arg1 = mask;
398
 
    } else {
399
 
        uint64_t memMask = (cur->arg1 | mask) & DRM_BO_MASK_MEM;
400
 
        uint64_t memFlags = cur->arg0 & flags & memMask;
401
 
 
402
 
        if (!memFlags && ((mask & DRM_BO_MASK_MEM) == DRM_BO_MASK_MEM))
403
 
            return -EINVAL;
404
 
 
405
 
        if (mask & cur->arg1 & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags))
406
 
            return -EINVAL;
407
 
 
408
 
        cur->arg1 |= mask;
409
 
        cur->arg0 = memFlags | ((cur->arg0 | flags) &
410
 
                                cur->arg1 & ~DRM_BO_MASK_MEM);
411
 
    }
412
 
    *itemLoc = count;
413
 
    *pNode = cur;
414
 
    return 0;
415
 
}
416
 
 
417
 
int
418
 
psbRelocOffset2D(Psb2DBufferPtr buf, unsigned delta, drmBO * buffer,
419
 
                 uint64_t flags, uint64_t mask)
420
 
{
421
 
    struct drm_psb_reloc *reloc = buf->curReloc;
422
 
    struct _drmBONode *node;
423
 
    int ret;
424
 
    int itemLoc;
425
 
    struct drm_bo_info_req *req;
426
 
 
427
 
    ret = psbAddValidateItem(&buf->bufferList, buffer, flags, mask, &itemLoc,
428
 
                             &node);
429
 
    if (ret) {
430
 
        FatalError("Add validate failed %s\n", strerror(-ret));
431
 
    }
432
 
 
433
 
    req = &node->bo_arg.d.req.bo_req;
434
 
 
435
 
    if (!(req->hint &  DRM_BO_HINT_PRESUMED_OFFSET)) {
436
 
        req->presumed_offset = buffer->offset;
437
 
        req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
438
 
    }
439
 
 
440
 
    *buf->curCmd = (req->presumed_offset + delta) & 0x0FFFFFFF;
441
 
    reloc->reloc_op = PSB_RELOC_OP_2D_OFFSET;
442
 
    reloc->where = (buf->curCmd - buf->startCmd);
443
 
    reloc->buffer = itemLoc;
444
 
    reloc->mask = 0x0FFFFFFF;
445
 
    reloc->shift = 0;
446
 
    reloc->pre_add = delta;
447
 
    reloc->dst_buffer = buf->myValidateIndex;
448
 
 
449
 
    buf->curCmd++;
450
 
    buf->curReloc++;
451
 
 
452
 
    return 0;
453
 
}
454
 
 
455
 
int
456
 
psbFlush2D(Psb2DBufferPtr buf, unsigned fence_flags, unsigned *fence_handle)
457
 
{
458
 
    struct _drmBONode *node;
459
 
    struct drm_bo_info_req *req;
460
 
    int ret;
461
 
 
462
 
    if (buf->curCmd == buf->startCmd)
463
 
        return 0;
464
 
 
465
 
    ret = psbDRMCmdBuf(buf->fd, &buf->bufferList, buf->buffer.handle,
466
 
                       0, buf->curCmd - buf->startCmd,
467
 
                       0, 0, 0,
468
 
                       buf->buffer.handle, PSB_2D_RELOC_OFFS,
469
 
                       buf->curReloc - buf->startReloc, buf->clipRects, 0,
470
 
                       PSB_ENGINE_2D, fence_flags, fence_handle);
471
 
 
472
 
    if (ret) {
473
 
        ErrorF("Command submission ioctl failed: \"%s\".\n", strerror(-ret));
474
 
    }
475
 
 
476
 
    drmBOResetList(&buf->bufferList);
477
 
    buf->curCmd = buf->startCmd;
478
 
    buf->curReloc = buf->startReloc;
479
 
    ret = psbAddValidateItem(&buf->bufferList, &buf->buffer, 0, 0,
480
 
                             &buf->myValidateIndex, &node);
481
 
    if (ret) {
482
 
        ErrorF("Failed adding command buffer to validate list:"
483
 
               " \"%s\".\n", strerror(-ret));
484
 
        goto out;
485
 
    }
486
 
 
487
 
    req = &node->bo_arg.d.req.bo_req;
488
 
    req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
489
 
    req->presumed_offset = 0; /* Local memory */
490
 
 
491
 
  out:
492
 
    return ret;
493
 
}
494
 
 
495
 
void
496
 
psbSetStateCallback(Psb2DBufferPtr buf, PsbVolatileStateFunc *func,
497
 
                    void *arg)
498
 
{
499
 
    buf->emitVolatileState = func;
500
 
    buf->volatileStateArg = arg;
501
 
}