1
/**************************************************************************
2
* Copyright (c) Intel Corp. 2007.
3
* Copyright (c) Tungsten Graphics Inc., Cedar Park TX. USA.
6
* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
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:
17
* The above copyright notice and this permission notice (including the
18
* next paragraph) shall be included in all copies or substantial portions
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.
29
**************************************************************************/
31
* psb_ioctl.c - Poulsbo device-specific IOCTL interface.
45
#include "psb_driver.h"
46
#include "psb_ioctl.h"
48
#define PSB_2D_RELOC_BUFFER_SIZE (4096*16)
49
#define PSB_2D_RELOC_OFFS (4096*4)
51
typedef struct _drmBONode
55
struct drm_bo_op_arg bo_arg;
61
psbAddValidateItem(drmBOList * list, drmBO * buf, uint64_t flags,
62
uint64_t mask, int *itemLoc, struct _drmBONode **pNode);
66
psbTimeDiff(struct timeval *now, struct timeval *then)
70
val = now->tv_sec - then->tv_sec;
81
drmAdjustListNodes(drmBOList * list)
87
while (list->numCurrent < list->numTarget) {
88
node = (drmBONode *) malloc(sizeof(*node));
94
DRMLISTADD(&node->head, &list->free);
97
while (list->numCurrent > list->numTarget) {
102
node = DRMLISTENTRY(drmBONode, l, head);
110
drmBOCreateList(int numTarget, drmBOList * list)
112
DRMINITLISTHEAD(&list->list);
113
DRMINITLISTHEAD(&list->free);
114
list->numTarget = numTarget;
115
list->numCurrent = 0;
117
return drmAdjustListNodes(list);
121
drmBOResetList(drmBOList * list)
126
ret = drmAdjustListNodes(list);
131
while (l != &list->list) {
133
DRMLISTADD(l, &list->free);
137
return drmAdjustListNodes(list);
141
drmBOFreeList(drmBOList * list)
147
while (l != &list->list) {
149
node = DRMLISTENTRY(drmBONode, l, head);
157
while (l != &list->free) {
159
node = DRMLISTENTRY(drmBONode, l, head);
167
psbDRMCopyReply(const struct drm_bo_info_rep *rep, drmBO * buf)
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;
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).
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)
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;
206
struct timeval then, now;
207
Bool have_then = FALSE;
211
for (l = list->list.next; l != &list->list; l = l->next) {
212
node = DRMLISTENTRY(drmBONode, l, head);
221
*prevNext = (unsigned long)arg;
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;
231
memset(&ca, 0, sizeof(ca));
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;
242
ca.reloc_handle = relocBufHandle;
243
ca.reloc_offset = relocBufOffset;
244
ca.num_relocs = numRelocs;
246
ca.fence_flags = fence_flags;
249
if (gettimeofday(&then, NULL))
250
FatalError("Gettimeofday error.\n");
253
* X server Signals will clobber the kernel time out mechanism.
254
* we need a user-space timeout as well.
258
ret = drmCommandWriteRead(fd, DRM_PSB_CMDBUF, &ca, sizeof(ca));
259
if (ret == -EAGAIN) {
261
if (gettimeofday(&then, NULL))
262
FatalError("Gettimeofday error.\n");
265
if (gettimeofday(&now, NULL))
266
FatalError("Gettimeofday error.\n");
268
} while (ret == -EAGAIN && psbTimeDiff(&now, &then) < PSB_TIMEOUT_USEC);
273
for (l = list->list.next; l != &list->list; l = l->next) {
274
node = DRMLISTENTRY(drmBONode, l, head);
276
rep = &arg->d.rep.bo_info;
281
if (arg->d.rep.ret) {
282
return arg->d.rep.ret;
286
psbDRMCopyReply(rep, buf);
293
psbInit2DBuffer(int fd, Psb2DBufferPtr buf)
297
struct _drmBONode *node;
298
struct drm_bo_info_req *req;
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);
306
ret = drmBOMap(fd, &buf->buffer, DRM_BO_FLAG_WRITE, 0, &addr);
307
buf->startCmd = addr;
308
drmBOUnmap(fd, &buf->buffer);
310
ret = drmBOCreateList(10, &buf->bufferList);
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);
323
ret = psbAddValidateItem(&buf->bufferList, &buf->buffer, 0, 0,
324
&buf->myValidateIndex, &node);
328
req = &node->bo_arg.d.req.bo_req;
329
req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
330
req->presumed_offset = 0; /* Local memory */
336
psbTakedown2DBuffer(int fd, Psb2DBufferPtr buf)
338
drmBOFreeList(&buf->bufferList);
339
(void)drmBOUnreference(fd, &buf->buffer);
343
psbAddListItem(drmBOList * list, drmBO * item, uint64_t arg0, uint64_t arg1)
349
if (l == &list->free) {
350
node = (drmBONode *) malloc(sizeof(*node));
357
node = DRMLISTENTRY(drmBONode, l, head);
359
memset(&node->bo_arg, 0, sizeof(node->bo_arg));
363
DRMLISTADDTAIL(&node->head, &list->list);
369
* Should really go into libdrm. Slightly different semantics than
370
* the libdrm counterpart.
374
psbAddValidateItem(drmBOList * list, drmBO * buf, uint64_t flags,
375
uint64_t mask, int *itemLoc, struct _drmBONode **pNode)
377
drmBONode *node, *cur;
383
for (l = list->list.next; l != &list->list; l = l->next) {
384
node = DRMLISTENTRY(drmBONode, l, head);
385
if (node->buf == buf) {
392
cur = psbAddListItem(list, buf, flags, mask);
399
uint64_t memMask = (cur->arg1 | mask) & DRM_BO_MASK_MEM;
400
uint64_t memFlags = cur->arg0 & flags & memMask;
402
if (!memFlags && ((mask & DRM_BO_MASK_MEM) == DRM_BO_MASK_MEM))
405
if (mask & cur->arg1 & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags))
409
cur->arg0 = memFlags | ((cur->arg0 | flags) &
410
cur->arg1 & ~DRM_BO_MASK_MEM);
418
psbRelocOffset2D(Psb2DBufferPtr buf, unsigned delta, drmBO * buffer,
419
uint64_t flags, uint64_t mask)
421
struct drm_psb_reloc *reloc = buf->curReloc;
422
struct _drmBONode *node;
425
struct drm_bo_info_req *req;
427
ret = psbAddValidateItem(&buf->bufferList, buffer, flags, mask, &itemLoc,
430
FatalError("Add validate failed %s\n", strerror(-ret));
433
req = &node->bo_arg.d.req.bo_req;
435
if (!(req->hint & DRM_BO_HINT_PRESUMED_OFFSET)) {
436
req->presumed_offset = buffer->offset;
437
req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
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;
446
reloc->pre_add = delta;
447
reloc->dst_buffer = buf->myValidateIndex;
456
psbFlush2D(Psb2DBufferPtr buf, unsigned fence_flags, unsigned *fence_handle)
458
struct _drmBONode *node;
459
struct drm_bo_info_req *req;
462
if (buf->curCmd == buf->startCmd)
465
ret = psbDRMCmdBuf(buf->fd, &buf->bufferList, buf->buffer.handle,
466
0, buf->curCmd - buf->startCmd,
468
buf->buffer.handle, PSB_2D_RELOC_OFFS,
469
buf->curReloc - buf->startReloc, buf->clipRects, 0,
470
PSB_ENGINE_2D, fence_flags, fence_handle);
473
ErrorF("Command submission ioctl failed: \"%s\".\n", strerror(-ret));
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);
482
ErrorF("Failed adding command buffer to validate list:"
483
" \"%s\".\n", strerror(-ret));
487
req = &node->bo_arg.d.req.bo_req;
488
req->hint = DRM_BO_HINT_PRESUMED_OFFSET;
489
req->presumed_offset = 0; /* Local memory */
496
psbSetStateCallback(Psb2DBufferPtr buf, PsbVolatileStateFunc *func,
499
buf->emitVolatileState = func;
500
buf->volatileStateArg = arg;