tng_cmdbuf.c revision d8bdef29bee0d7e15685d1ae2ad74ad6b356ce89
1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 * Copyright (c) Imagination Technologies Limited, UK
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 *    Waldo Bastian <waldo.bastian@intel.com>
27 *    Zeng Li <zeng.li@intel.com>
28 *    Edward Lin <edward.lin@intel.com>
29 *
30 */
31
32#include <unistd.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <errno.h>
36#include <string.h>
37#include <wsbm/wsbm_manager.h>
38#include "psb_buffer.h"
39#include "tng_cmdbuf.h"
40#include "psb_def.h"
41#include "psb_drv_debug.h"
42#include "tng_hostcode.h"
43#include "psb_ws_driver.h"
44
45#ifdef ANDROID
46#include <linux/psb_drm.h>
47#else
48#include "psb_drm.h"
49#endif
50
51#include "tng_trace.h"
52
53/*
54 * Buffer layout:
55 *         cmd_base <= cmd_idx < CMD_END() == reloc_base
56 *         reloc_base <= reloc_idx < RELOC_END() == (reloc_size)
57 */
58
59#define RELOC_END(cmdbuf)     (cmdbuf->cmd_base + cmdbuf->size)
60#define CMD_END(cmdbuf)       (cmdbuf->reloc_base)
61#define RELOC_SIZE            (0x3000)
62#define CMD_SIZE              (0x3000)
63#define RELOC_MARGIN          (0x0800)
64#define CMD_MARGIN            (0x0400)
65#define MAX_CMD_COUNT         12
66#define MTX_SEG_SIZE          (0x0800)
67
68/*!
69 *****************************************************************************
70 *
71 * @Name           Command word format
72 *
73 * @details    Mask and shift values for command word
74 *
75 ****************************************************************************/
76
77/*
78 * clear buffer
79 */
80void tng_cmdbuf_mem_unmap(tng_cmdbuf_p cmdbuf)
81{
82    psb_buffer_unmap(&cmdbuf->frame_mem);
83    psb_buffer_unmap(&cmdbuf->jpeg_pic_params);
84    psb_buffer_unmap(&cmdbuf->jpeg_header_mem);
85    psb_buffer_unmap(&cmdbuf->jpeg_header_interface_mem);
86    return ;
87}
88
89/*
90 * clear buffer
91 */
92static void tng_cmdbuf_clear(tng_cmdbuf_p cmdbuf, int flag)
93{
94    switch (flag) {
95        default:
96        case 4:
97            psb_buffer_destroy(&cmdbuf->jpeg_header_mem);
98        case 3:
99            psb_buffer_destroy(&cmdbuf->jpeg_pic_params);
100        case 2:
101        case 1:
102            psb_buffer_destroy(&cmdbuf->frame_mem);
103            break;
104    }
105
106    if (cmdbuf->size) {
107        psb_buffer_destroy(&cmdbuf->buf);
108        cmdbuf->size = 0;
109    }
110    if (cmdbuf->buffer_refs_allocated) {
111        free(cmdbuf->buffer_refs);
112        cmdbuf->buffer_refs = NULL;
113        cmdbuf->buffer_refs_allocated = 0;
114    }
115}
116
117
118/*
119 * Create command buffer
120 */
121
122VAStatus tng_cmdbuf_create(
123    object_context_p obj_context,
124    psb_driver_data_p driver_data,
125    tng_cmdbuf_p cmdbuf)
126{
127    context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
128
129    VAStatus vaStatus = VA_STATUS_SUCCESS;
130    unsigned int size = CMD_SIZE + RELOC_SIZE;
131
132    cmdbuf->size = 0;
133    cmdbuf->cmd_base = NULL;
134    cmdbuf->cmd_idx = NULL;
135    cmdbuf->reloc_base = NULL;
136    cmdbuf->reloc_idx = NULL;
137    cmdbuf->buffer_refs_count = 0;
138    cmdbuf->buffer_refs_allocated = 10;
139    cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
140    if (NULL == cmdbuf->buffer_refs) {
141        cmdbuf->buffer_refs_allocated = 0;
142        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
143    }
144
145    if (VA_STATUS_SUCCESS == vaStatus) {
146        vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_only, &cmdbuf->buf);
147        cmdbuf->size = size;
148    }
149
150    if (VA_STATUS_SUCCESS != vaStatus) {
151        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 0 \n", __FUNCTION__);
152	tng_cmdbuf_clear(cmdbuf, 1);
153        free(cmdbuf->buffer_refs);
154        cmdbuf->buffer_refs = NULL;
155        cmdbuf->buffer_refs_allocated = 0;
156        return vaStatus;
157    }
158
159    cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE);
160    drv_debug_msg(VIDEO_DEBUG_GENERAL, "mem size %d\n", __FUNCTION__, cmdbuf->mem_size);
161    /* create buffer information buffer */
162    //DEBUG-FIXME
163    //tng__alloc_init_buffer(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem);
164
165    vaStatus = psb_buffer_create(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem);
166    if (VA_STATUS_SUCCESS != vaStatus) {
167        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create xx \n", __FUNCTION__);
168        free(cmdbuf->buffer_refs);
169        cmdbuf->buffer_refs = NULL;
170        cmdbuf->buffer_refs_allocated = 0;
171        return vaStatus;
172    }
173    /* all cmdbuf share one MTX_CURRENT_IN_PARAMS since every MB has a MTX_CURRENT_IN_PARAMS structure
174     * and filling this structure for all MB is very time-consuming
175     */
176
177    /* create JPEG quantization buffer */
178    vaStatus = psb_buffer_create(driver_data, ctx->jpeg_pic_params_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_pic_params);
179    if (VA_STATUS_SUCCESS != vaStatus) {
180        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 1 \n", __FUNCTION__);
181        tng_cmdbuf_clear(cmdbuf, 2);
182        return vaStatus;
183    }
184
185    /* create JPEG MTX setup buffer */
186    vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_mem);
187    if (VA_STATUS_SUCCESS != vaStatus) {
188        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 2 \n", __FUNCTION__);
189        tng_cmdbuf_clear(cmdbuf, 3);
190        return vaStatus;
191    }
192
193    /* create JPEG MTX setup interface buffer */
194    vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_interface_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_interface_mem);
195    if (VA_STATUS_SUCCESS != vaStatus) {
196        drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 3 \n", __FUNCTION__);
197        tng_cmdbuf_clear(cmdbuf, 4);
198        return vaStatus;
199    }
200
201    return vaStatus;
202}
203
204/*
205 * Destroy buffer
206 */
207void tng_cmdbuf_destroy(tng_cmdbuf_p cmdbuf)
208{
209    psb_buffer_destroy(&cmdbuf->frame_mem);
210    psb_buffer_destroy(&cmdbuf->jpeg_header_mem);
211    psb_buffer_destroy(&cmdbuf->jpeg_pic_params);
212    psb_buffer_destroy(&cmdbuf->jpeg_header_interface_mem);
213
214    if (cmdbuf->size) {
215        psb_buffer_destroy(&cmdbuf->buf);
216        cmdbuf->size = 0;
217    }
218    if (cmdbuf->buffer_refs_allocated) {
219        free(cmdbuf->buffer_refs);
220        cmdbuf->buffer_refs = NULL;
221        cmdbuf->buffer_refs_allocated = 0;
222    }
223    return ;
224}
225
226/*
227 * Reset buffer & map
228 *
229 * Returns 0 on success
230 */
231int tng_cmdbuf_reset(tng_cmdbuf_p cmdbuf)
232{
233    int ret;
234    cmdbuf->cmd_base = NULL;
235    cmdbuf->cmd_idx = NULL;
236    cmdbuf->reloc_base = NULL;
237    cmdbuf->reloc_idx = NULL;
238
239    cmdbuf->buffer_refs_count = 0;
240    cmdbuf->frame_mem_index = 0;
241    cmdbuf->cmd_count = 0;
242    cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE);
243
244    ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
245    if (ret) {
246        return ret;
247    }
248
249    cmdbuf->cmd_start = cmdbuf->cmd_base;
250    cmdbuf->cmd_idx = (IMG_UINT32 *) cmdbuf->cmd_base;
251
252    cmdbuf->reloc_base = cmdbuf->cmd_base + CMD_SIZE;
253    cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base;
254
255    /* Add ourselves to the buffer list */
256    tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 0 */
257    return ret;
258}
259
260/*
261 * Unmap buffer
262 *
263 * Returns 0 on success
264 */
265int tng_cmdbuf_unmap(tng_cmdbuf_p cmdbuf)
266{
267    cmdbuf->cmd_base = NULL;
268    cmdbuf->cmd_start = NULL;
269    cmdbuf->cmd_idx = NULL;
270    cmdbuf->reloc_base = NULL;
271    cmdbuf->reloc_idx = NULL;
272    cmdbuf->cmd_count = 0;
273    psb_buffer_unmap(&cmdbuf->buf);
274    return 0;
275}
276
277
278/*
279 * Reference an addtional buffer "buf" in the command stream
280 * Returns a reference index that can be used to refer to "buf" in
281 * relocation records, -1 on error
282 */
283int tng_cmdbuf_buffer_ref(tng_cmdbuf_p cmdbuf, psb_buffer_p buf)
284{
285    int item_loc = 0;
286
287    /*Reserve the same TTM BO twice will cause kernel lock up*/
288    while ((item_loc < cmdbuf->buffer_refs_count)
289           && (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf))
290               != wsbmKBufHandle(wsbmKBuf(buf->drm_buf))))
291        //while( (item_loc < cmdbuf->buffer_refs_count) && (cmdbuf->buffer_refs[item_loc] != buf) )
292    {
293        item_loc++;
294    }
295    if (item_loc == cmdbuf->buffer_refs_count) {
296        /* Add new entry */
297        if (item_loc >= cmdbuf->buffer_refs_allocated) {
298            /* Allocate more entries */
299            int new_size = cmdbuf->buffer_refs_allocated + 10;
300            psb_buffer_p *new_array;
301            new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size);
302            if (NULL == new_array) {
303                return -1; /* Allocation failure */
304            }
305            memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
306            free(cmdbuf->buffer_refs);
307            cmdbuf->buffer_refs_allocated = new_size;
308            cmdbuf->buffer_refs = new_array;
309        }
310        cmdbuf->buffer_refs[item_loc] = buf;
311        cmdbuf->buffer_refs_count++;
312        buf->status = psb_bs_queued;
313    }
314    return item_loc;
315}
316
317/* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address
318 * "addr_in_cmdbuf"
319 * The relocation is based on the device virtual address of "ref_buffer"
320 * "buf_offset" is be added to the device virtual address, and the sum is then
321 * right shifted with "align_shift".
322 * "mask" determines which bits of the target DWORD will be updated with the so
323 * constructed address. The remaining bits will be filled with bits from "background".
324 */
325void tng_cmdbuf_add_relocation(tng_cmdbuf_p cmdbuf,
326                               IMG_UINT32 *addr_in_dst_buffer,/*addr of dst_buffer for the DWORD*/
327                               psb_buffer_p ref_buffer,
328                               IMG_UINT32 buf_offset,
329                               IMG_UINT32 mask,
330                               IMG_UINT32 background,
331                               IMG_UINT32 align_shift,
332                               IMG_UINT32 dst_buffer,
333                               IMG_UINT32 *start_of_dst_buffer) /*Index of the list refered by cmdbuf->buffer_refs */
334{
335    struct drm_psb_reloc *reloc = cmdbuf->reloc_idx;
336    uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf);
337
338    reloc->where = addr_in_dst_buffer - start_of_dst_buffer; /* Offset in DWORDs */
339
340    reloc->buffer = tng_cmdbuf_buffer_ref(cmdbuf, ref_buffer);
341    ASSERT(reloc->buffer != -1);
342
343    reloc->reloc_op = PSB_RELOC_OP_OFFSET;
344#ifndef VA_EMULATOR
345    if (presumed_offset) {
346        IMG_UINT32 new_val =  presumed_offset + buf_offset;
347
348        new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT));
349        new_val = (background & ~mask) | (new_val & mask);
350        *addr_in_dst_buffer = new_val;
351    } else {
352        *addr_in_dst_buffer = PSB_RELOC_MAGIC;
353    }
354#else
355    /* indicate subscript of relocation buffer */
356    *addr_in_dst_buffer = reloc - (struct drm_psb_reloc *)cmdbuf->reloc_base;
357#endif
358    reloc->mask = mask;
359    reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT;
360    reloc->pre_add = buf_offset;
361    reloc->background = background;
362    reloc->dst_buffer = dst_buffer;
363    cmdbuf->reloc_idx++;
364
365    ASSERT(((void *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf));
366}
367
368/* Prepare one command package */
369void tng_cmdbuf_insert_command(
370    object_context_p obj_context,
371    IMG_UINT32 stream_id,
372    IMG_UINT32 cmd_id,
373    IMG_UINT32 cmd_data,
374    psb_buffer_p data_addr,
375    IMG_UINT32 offset)
376{
377    IMG_UINT32 cmd_word;
378    context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
379    context_ENC_cmdbuf *ps_cmd = &(ctx->ctx_cmdbuf[stream_id]);
380    context_ENC_mem *ps_mem = &(ctx->ctx_mem[stream_id]);
381    tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf;
382    psb_driver_data_p driver_data = ctx->obj_context->driver_data;
383    int interrupt_flags;
384
385    //CMD composed by user space does not generate Interrupt
386    interrupt_flags = 0;
387
388    assert(stream_id <= TOPAZHP_MAX_NUM_STREAMS);
389
390    /* Write command to FIFO */
391    {
392        cmd_word = F_ENCODE(stream_id, MTX_MSG_CORE) |
393            F_ENCODE(cmd_id, MTX_MSG_CMD_ID);
394
395        if (cmd_id & MTX_CMDID_PRIORITY) {
396            /* increment the command counter */
397            ps_cmd->ui32HighCmdCount++;
398
399            /* Prepare high priority command */
400            cmd_word |= F_ENCODE(1, MTX_MSG_PRIORITY) |
401                F_ENCODE(((ps_cmd->ui32LowCmdCount - 1) & 0xff) |(ps_cmd->ui32HighCmdCount << 8), MTX_MSG_COUNT);
402        } else {
403            /* Prepare low priority command */
404            cmd_word |=
405            F_ENCODE(ps_cmd->ui32LowCmdCount & 0xff, MTX_MSG_COUNT);
406            ++(ps_cmd->ui32LowCmdCount);
407        }
408        drv_debug_msg(VIDEO_DEBUG_GENERAL,
409            "%s: cmd_id = 0x%08x\n",
410            __FUNCTION__, cmd_word);
411        *cmdbuf->cmd_idx++ = cmd_word;
412    }
413
414    /* write command word into cmdbuf */
415    *cmdbuf->cmd_idx++ = cmd_data;
416/* Command data address */
417    if (data_addr) {
418	if (cmd_id == MTX_CMDID_RC_UPDATE) {
419	    *cmdbuf->cmd_idx++ = data_addr;
420	    drv_debug_msg(VIDEO_DEBUG_GENERAL,
421		"%s: data_addr = 0x%08x\n",
422		__FUNCTION__, *(cmdbuf->cmd_idx));
423	} else {
424	    if ((cmd_id >= MTX_CMDID_SETQUANT) && (cmd_id <= MTX_CMDID_SETUP)) {
425		tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0);
426	    }
427	    else {
428#ifdef _TNG_RELOC_
429		TNG_RELOC_CMDBUF_START(cmdbuf->cmd_idx, offset, data_addr);
430#else
431		tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0);
432#endif
433	    }
434		drv_debug_msg(VIDEO_DEBUG_GENERAL,
435		    "%s: data_addr = 0x%08x\n",
436		    __FUNCTION__, *(cmdbuf->cmd_idx));
437
438		cmdbuf->cmd_idx++;
439	}
440    } else {
441	*cmdbuf->cmd_idx++ = 0;
442    }
443
444    if (cmd_id == MTX_CMDID_SW_SETUP_CIR) {
445	*cmdbuf->cmd_idx++ = (IMG_INT16)ctx->ui16IntraRefresh;
446	*cmdbuf->cmd_idx++ = ctx->sRCParams.ui32InitialQp;
447	*cmdbuf->cmd_idx++ = ctx->sRCParams.iMinQP;
448	*cmdbuf->cmd_idx++ = ctx->ctx_mem_size.mb_ctrl_in_params;
449	*cmdbuf->cmd_idx++ = ctx->ui32pseudo_rand_seed;
450    }
451
452    /* Command data address */
453    if (cmd_id == MTX_CMDID_SETVIDEO) {
454        *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf));
455        drv_debug_msg(VIDEO_DEBUG_GENERAL,
456            "%s: cmd_param = 0x%08x\n",
457            __FUNCTION__, *(cmdbuf->cmd_idx - 1));
458
459	if (data_addr)
460	    *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(data_addr->drm_buf));
461
462	*(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_mb_ctrl_in_params.drm_buf));
463    }
464
465    if (cmd_id == MTX_CMDID_SETUP_INTERFACE) {
466        *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf));
467        drv_debug_msg(VIDEO_DEBUG_GENERAL,
468            "%s: cmd_param = 0x%08x\n",
469            __FUNCTION__, *(cmdbuf->cmd_idx - 1));
470    }
471
472    if (cmd_id == MTX_CMDID_SHUTDOWN) {
473        *(cmdbuf->cmd_idx)++ = ctx->eCodec;
474
475        drv_debug_msg(VIDEO_DEBUG_GENERAL,
476            "%s: cmd_param = 0x%08x\n",
477            __FUNCTION__, *(cmdbuf->cmd_idx - 1));
478    }
479
480    return ;
481}
482
483
484/*
485 * Advances "obj_context" to the next cmdbuf
486 *
487 * Returns 0 on success
488 */
489int tng_context_get_next_cmdbuf(object_context_p obj_context)
490{
491    tng_cmdbuf_p cmdbuf;
492    int ret;
493
494    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start obj_context->tng_cmdbuf = %x\n", __FUNCTION__, obj_context->tng_cmdbuf);
495
496    if (obj_context->tng_cmdbuf) {
497        return 0;
498    }
499
500    obj_context->cmdbuf_current++;
501    if (obj_context->cmdbuf_current >= TNG_MAX_CMDBUFS_ENCODE) {
502        obj_context->cmdbuf_current = 0;
503    }
504
505    cmdbuf = obj_context->tng_cmdbuf_list[obj_context->cmdbuf_current];
506    ret = tng_cmdbuf_reset(cmdbuf);
507    if (!ret) {
508        /* Success */
509        obj_context->tng_cmdbuf = cmdbuf;
510    }
511
512//    tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->pic_params);
513//    tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->slice_mem);
514    return ret;
515}
516
517/*
518 * This is the user-space do-it-all interface to the drm cmdbuf ioctl.
519 * It allows different buffers as command- and reloc buffer. A list of
520 * cliprects to apply and whether to copy the clipRect content to all
521 * scanout buffers (damage = 1).
522 */
523/*
524 * Don't add debug statements in this function, it gets called with the
525 * DRM lock held and output to an X terminal can cause X to deadlock
526 */
527static int
528ptgDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
529             unsigned cmdBufOffset, unsigned cmdBufSize,
530             unsigned relocBufHandle, unsigned relocBufOffset,
531             unsigned numRelocs, int damage,
532             unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_rep)
533{
534    drm_psb_cmdbuf_arg_t ca;
535    struct psb_validate_arg *arg_list;
536    int i, ret;
537    unsigned int retry = 0;
538    uint64_t mask = PSB_GPU_ACCESS_MASK;
539
540    arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count);
541    if (arg_list == NULL) {
542        drv_debug_msg(VIDEO_DEBUG_ERROR, "Allocate memory failed\n");
543        return -ENOMEM;
544    }
545
546    for (i = 0; i < buffer_count; i++) {
547        struct psb_validate_arg *arg = &(arg_list[i]);
548        struct psb_validate_req *req = &arg->d.req;
549
550        //memset(arg, 0, sizeof(*arg));
551        req->next = (unsigned long) & (arg_list[i+1]);
552
553        req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf));
554        //req->group = 0;
555        req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask;
556        req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask;
557#if 1
558        req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf);
559        req->presumed_flags = PSB_USE_PRESUMED;
560#else
561        req->presumed_flags = 0;
562#endif
563        req->pad64 = (IMG_UINT32)buffer_list[i]->pl_flags;
564    }
565    arg_list[buffer_count-1].d.req.next = 0;
566
567    memset(&ca, 0, sizeof(ca));
568
569    ca.buffer_list = (uint64_t)((unsigned long)arg_list);
570    ca.cmdbuf_handle = cmdBufHandle;
571    ca.cmdbuf_offset = cmdBufOffset;
572    ca.cmdbuf_size = cmdBufSize;
573    ca.reloc_handle = relocBufHandle;
574    ca.reloc_offset = relocBufOffset;
575    ca.num_relocs = numRelocs;
576    ca.engine = engine;
577    ca.fence_flags = fence_flags;
578    ca.fence_arg = (uint64_t)((unsigned long)fence_rep);
579    //ca.damage = damage;
580
581
582    do {
583        ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca));
584        if (ret == -EAGAIN || ret == -EBUSY) {
585            drv_debug_msg(VIDEO_DEBUG_ERROR, "drmCommandWrite returns with %s, retry\n",
586                          ret==-EAGAIN?"EAGAIN":"EBUSY");
587            retry++;
588        }
589    } while (ret == -EAGAIN || ret == -EBUSY);
590
591    if (retry > 0)
592        drv_debug_msg(VIDEO_DEBUG_ERROR,"drmCommandWrite tries %d time, finally %s with ret=%d\n",
593                      retry, ret==0?"okay":"failed!", ret);
594
595    if (ret)
596        goto out;
597
598    for (i = 0; i < buffer_count; i++) {
599        struct psb_validate_arg *arg = &(arg_list[i]);
600        struct psb_validate_rep *rep = &arg->d.rep;
601
602        if (!arg->handled) {
603            ret = -EFAULT;
604            goto out;
605        }
606        if (arg->ret != 0) {
607            ret = arg->ret;
608            goto out;
609        }
610        wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf),
611                       rep->gpu_offset, rep->placement, rep->fence_type_mask);
612    }
613out:
614    free(arg_list);
615    for (i = 0; i < buffer_count; i++) {
616        /*
617         * Buffer no longer queued in userspace
618         */
619        switch (buffer_list[i]->status) {
620        case psb_bs_queued:
621            buffer_list[i]->status = psb_bs_ready;
622            break;
623
624        case psb_bs_abandoned:
625            psb_buffer_destroy(buffer_list[i]);
626            free(buffer_list[i]);
627            break;
628
629        default:
630            /* Not supposed to happen */
631            ASSERT(0);
632        }
633    }
634
635    return ret;
636}
637
638#if 0
639static struct _WsbmFenceObject *
640lnc_fence_wait(psb_driver_data_p driver_data,
641               struct psb_ttm_fence_rep *fence_rep, int *status)
642
643{
644    struct _WsbmFenceObject *fence = NULL;
645    int ret = -1;
646
647    /* copy fence information */
648    if (fence_rep->error != 0) {
649        drv_debug_msg(VIDEO_DEBUG_ERROR, "drm failed to create a fence"
650                           " and has idled the HW\n");
651        DEBUG_FAILURE_RET;
652        return NULL;
653    }
654
655    fence = wsbmFenceCreate(driver_data->fence_mgr, fence_rep->fence_class,
656                            fence_rep->fence_type,
657                            (void *)fence_rep->handle,
658                            0);
659    if (fence)
660        *status = wsbmFenceFinish(fence, fence_rep->fence_type, 0);
661
662    return fence;
663}
664#endif
665
666/*
667 * Submits the current cmdbuf
668 *
669 * Returns 0 on success
670 */
671int tng_context_submit_cmdbuf(object_context_p obj_context)
672{
673
674    return 0;
675}
676
677
678
679/*
680 * FrameSkip is only meaningful for RC enabled mode
681 * Topaz raises this flag after surface N encoding is finished (vaSyncSurface gets back)
682 * then for the next encode surface N+1 (ctx->src_surface) frameskip flag is cleared in vaBeginPicuture
683 * and is always set in vaEndPicture:lnc_PatchRCMode
684 * vaQuerySurfaceStatus is supposed only to be called after vaEndPicture/vaSyncSurface,
685 * The caller should ensure the surface pertains to an encode context
686 */
687int tng_surface_get_frameskip(psb_driver_data_p driver_data,
688                              psb_surface_p surface,
689                              int *frame_skip)
690{
691    /* bit31 indicate if frameskip is already settled, it is used to record the frame skip flag for old surfaces
692     * bit31 is cleared when the surface is used as encode render target or reference/reconstrucure target
693     */
694    if (GET_SURFACE_INFO_skipped_flag(surface) & SURFACE_INFO_SKIP_FLAG_SETTLED) {
695        *frame_skip = GET_SURFACE_INFO_skipped_flag(surface) & 1;
696    } else
697        *frame_skip = 0;
698
699    return 0;
700}
701
702VAStatus tng_set_frame_skip_flag(object_context_p obj_context)
703{
704    VAStatus vaStatus = VA_STATUS_SUCCESS;
705    context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
706    context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
707
708    if (ctx && ps_buf->previous_src_surface) {
709        SET_SURFACE_INFO_skipped_flag(ps_buf->previous_src_surface->psb_surface, 1);
710        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n",
711            ps_buf->previous_src_surface->psb_surface);
712    }
713
714    return vaStatus;
715}
716
717
718/*
719 * Flushes all cmdbufs
720 */
721int tng_context_flush_cmdbuf(object_context_p obj_context)
722{
723    tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf;
724    psb_driver_data_p driver_data = obj_context->driver_data;
725    unsigned int fence_flags;
726    struct psb_ttm_fence_rep fence_rep;
727    unsigned int reloc_offset;
728    unsigned int num_relocs;
729    int ret;
730    unsigned int cmdbuffer_size = (unsigned int) (((unsigned char *)(cmdbuf->cmd_idx)) - cmdbuf->cmd_start); /* In bytes */
731
732    ASSERT(cmdbuffer_size < CMD_SIZE);
733    ASSERT((void *) cmdbuf->cmd_idx < CMD_END(cmdbuf));
734    /* LOCK */
735    ret = LOCK_HARDWARE(driver_data);
736    if (ret) {
737        UNLOCK_HARDWARE(driver_data);
738        DEBUG_FAILURE_RET;
739        return ret;
740    }
741
742    /* Now calculate the total number of relocations */
743    reloc_offset = cmdbuf->reloc_base - cmdbuf->cmd_base;
744    num_relocs = (((unsigned char *) (cmdbuf->reloc_idx)) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
745
746    tng_cmdbuf_unmap(cmdbuf);
747
748    ASSERT(NULL == cmdbuf->reloc_base);
749
750#ifdef DEBUG_TRACE
751    fence_flags = 0;
752#else
753    fence_flags = DRM_PSB_FENCE_NO_USER;
754#endif
755
756
757    wsbmWriteLockKernelBO();
758#if 1 //_PO_DEBUG_
759    ret = ptgDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset, /* FIXME Still use ioctl cmd? */
760                       cmdbuf->buffer_refs, cmdbuf->buffer_refs_count, wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)),
761                       0, cmdbuffer_size,/*unsigned cmdBufSize*/
762                       wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)), reloc_offset, num_relocs,
763                       0, LNC_ENGINE_ENCODE, fence_flags, &fence_rep); /* FIXME use LNC_ENGINE_ENCODE */
764#endif
765    wsbmWriteUnlockKernelBO();
766
767    UNLOCK_HARDWARE(driver_data);
768
769    if (ret) {
770        obj_context->tng_cmdbuf = NULL;
771
772        DEBUG_FAILURE_RET;
773        return ret;
774    }
775
776#if 0 /*DEBUG_TRACE*/
777    int status = -1;
778    struct _WsbmFenceObject *fence = NULL;
779
780    fence = lnc_fence_wait(driver_data, &fence_rep, &status);
781    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence);
782
783    if (fence)
784        wsbmFenceUnreference(fence);
785#endif
786
787    obj_context->tng_cmdbuf = NULL;
788
789    return 0;
790}
791
792
793void tng_cmdbuf_set_phys(IMG_UINT32 *dest_buf, int dest_num,
794    psb_buffer_p ref_buf, unsigned int ref_ofs, unsigned int ref_len)
795{
796    int i = 0;
797    IMG_UINT32 addr_phys = (IMG_UINT32)wsbmBOOffsetHint(ref_buf->drm_buf) + ref_ofs;
798
799//    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: drm_buf 0x%08x, addr_phys 0x%08x, virt addr 0x%08x\n", __FUNCTION__, ref_buf->drm_buf, addr_phys, ref_buf->virtual_addr );
800
801    do {
802        dest_buf[i] =  addr_phys;
803        ++i;
804        addr_phys += ref_len;
805    } while(i < dest_num);
806    return ;
807}
808
809
810int tng_get_pipe_number(object_context_p obj_context)
811{
812
813    context_ENC_p ctx = (context_ENC_p)(obj_context->format_data);
814    return ctx->ui8PipesToUse;
815
816}
817
818