Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the
      6  * "Software"), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sub license, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Binglin Chen <binglin.chen (at) intel.com>
     26  *
     27  */
     28 
     29 #include "vsp_VPP.h"
     30 #include "vsp_cmdbuf.h"
     31 #include "psb_drv_debug.h"
     32 
     33 #define CMD_SIZE              (0x3000)
     34 #define LLDMA_SIZE            (0x2000)
     35 #define RELOC_SIZE            (0x3000)
     36 
     37 static int
     38 vspDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
     39 	     unsigned cmdBufOffset, unsigned cmdBufSize,
     40 	     unsigned relocBufHandle, unsigned relocBufOffset,
     41 	     unsigned numRelocs, int damage,
     42 	     unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_rep);
     43 
     44 /*
     45  * Create command buffer
     46  */
     47 VAStatus vsp_cmdbuf_create(
     48 	object_context_p obj_context,
     49 	psb_driver_data_p driver_data,
     50 	vsp_cmdbuf_p cmdbuf)
     51 {
     52 	VAStatus vaStatus = VA_STATUS_SUCCESS;
     53 	unsigned int size = CMD_SIZE + RELOC_SIZE;
     54 	context_VPP_p ctx = (context_VPP_p) obj_context->format_data;
     55 
     56 	cmdbuf->size = 0;
     57 	cmdbuf->cmd_base = NULL;
     58 	cmdbuf->cmd_idx = NULL;
     59 	cmdbuf->reloc_base = NULL;
     60 	cmdbuf->reloc_idx = NULL;
     61 	cmdbuf->buffer_refs_count = 0;
     62 	cmdbuf->buffer_refs_allocated = 10;
     63 	cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
     64 	if (NULL == cmdbuf->buffer_refs) {
     65 		cmdbuf->buffer_refs_allocated = 0;
     66 		vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
     67 		goto err1;
     68 	}
     69 
     70 	vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_only, &cmdbuf->buf);
     71 	cmdbuf->size = size;
     72 
     73 	if (VA_STATUS_SUCCESS != vaStatus)
     74 		goto err2;
     75 
     76 	vaStatus = psb_buffer_create(driver_data, ctx->param_sz, psb_bt_cpu_vpu, &cmdbuf->param_mem);
     77 	if (VA_STATUS_SUCCESS != vaStatus)
     78 		goto err3;
     79 
     80 	return vaStatus;
     81 err3:
     82 	psb_buffer_destroy(&cmdbuf->buf);
     83 err2:
     84 	free(cmdbuf->buffer_refs);
     85 	cmdbuf->buffer_refs = NULL;
     86 	cmdbuf->buffer_refs_allocated = 0;
     87 err1:
     88 	return vaStatus;
     89 }
     90 
     91 /*
     92  * Destroy buffer
     93  */
     94 void vsp_cmdbuf_destroy(vsp_cmdbuf_p cmdbuf)
     95 {
     96 	if (cmdbuf->size) {
     97 		psb_buffer_destroy(&cmdbuf->buf);
     98 		cmdbuf->size = 0;
     99 	}
    100 	if (cmdbuf->buffer_refs_allocated) {
    101 		free(cmdbuf->buffer_refs);
    102 		cmdbuf->buffer_refs = NULL;
    103 		cmdbuf->buffer_refs_allocated = 0;
    104 	}
    105 	psb_buffer_destroy(&cmdbuf->param_mem);
    106 }
    107 
    108 /*
    109  * Reset buffer & map
    110  *
    111  * Returns 0 on success
    112  */
    113 int vsp_cmdbuf_reset(vsp_cmdbuf_p cmdbuf)
    114 {
    115 	int ret;
    116 
    117 	cmdbuf->cmd_base = NULL;
    118 	cmdbuf->cmd_idx = NULL;
    119 	cmdbuf->reloc_base = NULL;
    120 	cmdbuf->reloc_idx = NULL;
    121 
    122 	cmdbuf->buffer_refs_count = 0;
    123 	cmdbuf->cmd_count = 0;
    124 
    125 	ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
    126 	if (ret) {
    127 		return ret;
    128 	}
    129 
    130 	cmdbuf->cmd_start = cmdbuf->cmd_base;
    131 	cmdbuf->cmd_idx = (uint32_t *) cmdbuf->cmd_base;
    132 
    133 	cmdbuf->reloc_base = cmdbuf->cmd_base + CMD_SIZE;
    134 	cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base;
    135 
    136 	/* Add ourselves to the buffer list */
    137 	vsp_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 0 */
    138 
    139 	return ret;
    140 }
    141 
    142 /*
    143  * Unmap buffer
    144  *
    145  * Returns 0 on success
    146  */
    147 int vsp_cmdbuf_unmap(vsp_cmdbuf_p cmdbuf)
    148 {
    149 	cmdbuf->cmd_base = NULL;
    150 	cmdbuf->cmd_start = NULL;
    151 	cmdbuf->cmd_idx = NULL;
    152 	cmdbuf->reloc_base = NULL;
    153 	cmdbuf->reloc_idx = NULL;
    154 	cmdbuf->cmd_count = 0;
    155 	psb_buffer_unmap(&cmdbuf->buf);
    156 	return 0;
    157 }
    158 
    159 /*
    160  * Reference an addtional buffer "buf" in the command stream
    161  * Returns a reference index that can be used to refer to "buf" in
    162  * relocation records, -1 on error
    163  */
    164 int vsp_cmdbuf_buffer_ref(vsp_cmdbuf_p cmdbuf, psb_buffer_p buf)
    165 {
    166 	int item_loc = 0;
    167 
    168 	/*Reserve the same TTM BO twice will cause kernel lock up*/
    169 	while ((item_loc < cmdbuf->buffer_refs_count)
    170 	       && (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf))
    171 		   != wsbmKBufHandle(wsbmKBuf(buf->drm_buf)))) {
    172 		item_loc++;
    173 	}
    174 	if (item_loc == cmdbuf->buffer_refs_count) {
    175 		/* Add new entry */
    176 		if (item_loc >= cmdbuf->buffer_refs_allocated) {
    177 			/* Allocate more entries */
    178 			int new_size = cmdbuf->buffer_refs_allocated + 10;
    179 			psb_buffer_p *new_array;
    180 			new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size);
    181 			if (NULL == new_array) {
    182 				return -1; /* Allocation failure */
    183 			}
    184 			memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
    185 			free(cmdbuf->buffer_refs);
    186 			cmdbuf->buffer_refs_allocated = new_size;
    187 			cmdbuf->buffer_refs = new_array;
    188 		}
    189 		cmdbuf->buffer_refs[item_loc] = buf;
    190 		cmdbuf->buffer_refs_count++;
    191 		buf->status = psb_bs_queued;
    192 	}
    193 	return item_loc;
    194 }
    195 
    196 /* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address
    197  * "addr_in_cmdbuf"
    198  * The relocation is based on the device virtual address of "ref_buffer"
    199  * "buf_offset" is be added to the device virtual address, and the sum is then
    200  * right shifted with "align_shift".
    201  * "mask" determines which bits of the target DWORD will be updated with the so
    202  * constructed address. The remaining bits will be filled with bits from "background".
    203  */
    204 void vsp_cmdbuf_add_relocation(vsp_cmdbuf_p cmdbuf,
    205 			       uint32_t *addr_in_dst_buffer,/*addr of dst_buffer for the DWORD*/
    206 			       psb_buffer_p ref_buffer,
    207 			       uint32_t buf_offset,
    208 			       uint32_t mask,
    209 			       uint32_t background,
    210 			       uint32_t align_shift,
    211 			       uint32_t dst_buffer,
    212 			       uint32_t *start_of_dst_buffer) /*Index of the list refered by cmdbuf->buffer_refs */
    213 {
    214     struct drm_psb_reloc *reloc = cmdbuf->reloc_idx;
    215     uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf);
    216 
    217     reloc->where = addr_in_dst_buffer - start_of_dst_buffer; /* Offset in DWORDs */
    218 
    219     reloc->buffer = vsp_cmdbuf_buffer_ref(cmdbuf, ref_buffer);
    220     ASSERT(reloc->buffer != -1);
    221 
    222     reloc->reloc_op = PSB_RELOC_OP_OFFSET;
    223 #ifndef VA_EMULATOR
    224     if (presumed_offset) {
    225 	uint32_t new_val =  presumed_offset + buf_offset;
    226 
    227 	new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT));
    228 	new_val = (background & ~mask) | (new_val & mask);
    229 	*addr_in_dst_buffer = new_val;
    230     } else {
    231 	*addr_in_dst_buffer = PSB_RELOC_MAGIC;
    232     }
    233 #else
    234     /* indicate subscript of relocation buffer */
    235     *addr_in_dst_buffer = reloc - (struct drm_psb_reloc *)cmdbuf->reloc_base;
    236 #endif
    237     reloc->mask = mask;
    238     reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT;
    239     reloc->pre_add = buf_offset;
    240     reloc->background = background;
    241     reloc->dst_buffer = dst_buffer;
    242     cmdbuf->reloc_idx++;
    243 
    244     ASSERT(((unsigned char *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf));
    245 }
    246 
    247 /*
    248  * Advances "obj_context" to the next cmdbuf
    249  *
    250  * Returns 0 on success
    251  */
    252 int vsp_context_get_next_cmdbuf(object_context_p obj_context)
    253 {
    254 	vsp_cmdbuf_p cmdbuf;
    255 	int ret;
    256 
    257 	if (obj_context->vsp_cmdbuf) {
    258 		return 0;
    259 	}
    260 
    261 	obj_context->cmdbuf_current++;
    262 	if (obj_context->cmdbuf_current >= VSP_MAX_CMDBUFS) {
    263 		obj_context->cmdbuf_current = 0;
    264 	}
    265 
    266 	cmdbuf = obj_context->vsp_cmdbuf_list[obj_context->cmdbuf_current];
    267 
    268 	ret = vsp_cmdbuf_reset(cmdbuf);
    269 	if (!ret) {
    270 		/* Success */
    271 		obj_context->vsp_cmdbuf = cmdbuf;
    272 	}
    273 
    274 	cmdbuf->param_mem_loc = vsp_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->param_mem);
    275 
    276 	return ret;
    277 }
    278 
    279 /*
    280  * This is the user-space do-it-all interface to the drm cmdbuf ioctl.
    281  * It allows different buffers as command- and reloc buffer. A list of
    282  * cliprects to apply and whether to copy the clipRect content to all
    283  * scanout buffers (damage = 1).
    284  */
    285 /*
    286  * Don't add debug statements in this function, it gets called with the
    287  * DRM lock held and output to an X terminal can cause X to deadlock
    288  */
    289 static int
    290 vspDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
    291 	     unsigned cmdBufOffset, unsigned cmdBufSize,
    292 	     unsigned relocBufHandle, unsigned relocBufOffset,
    293 	     unsigned numRelocs, int __maybe_unused damage,
    294 	     unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_rep)
    295 {
    296 	drm_psb_cmdbuf_arg_t ca;
    297 	struct psb_validate_arg *arg_list;
    298 	int i;
    299 	int ret = 0;
    300 	uint64_t mask = PSB_GPU_ACCESS_MASK;
    301 	arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count);
    302 	if (arg_list == NULL) {
    303 		drv_debug_msg(VIDEO_DEBUG_ERROR, "Allocate memory failed\n");
    304 		return -ENOMEM;
    305 	}
    306 
    307 	for (i = 0; i < buffer_count; i++) {
    308 		struct psb_validate_arg *arg = &(arg_list[i]);
    309 		struct psb_validate_req *req = &arg->d.req;
    310 
    311 		req->next = (unsigned long) & (arg_list[i+1]);
    312 
    313 		req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf));
    314 		//req->group = 0;
    315 		req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask;
    316 		req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask;
    317 #if 1
    318 		req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf);
    319 		req->presumed_flags = PSB_USE_PRESUMED;
    320                 req->unfence_flag = buffer_list[i]->unfence_flag;
    321 #else
    322 		req->presumed_flags = 0;
    323 #endif
    324 		req->pad64 = (uint32_t)buffer_list[i]->pl_flags;
    325 	}
    326 	arg_list[buffer_count-1].d.req.next = 0;
    327 
    328 	ca.buffer_list = (uint64_t)((unsigned long)arg_list);
    329 	ca.cmdbuf_handle = cmdBufHandle;
    330 	ca.cmdbuf_offset = cmdBufOffset;
    331 	ca.cmdbuf_size = cmdBufSize;
    332 	ca.reloc_handle = relocBufHandle;
    333 	ca.reloc_offset = relocBufOffset;
    334 	ca.num_relocs = numRelocs;
    335 	ca.engine = engine;
    336 	ca.fence_flags = fence_flags;
    337 	ca.fence_arg = (uint64_t)((unsigned long)fence_rep);
    338 
    339 	do {
    340 		ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca));
    341 	} while (ret == EAGAIN);
    342 
    343 	if (ret)
    344 		goto out;
    345 
    346 	for (i = 0; i < buffer_count; i++) {
    347 		struct psb_validate_arg *arg = &(arg_list[i]);
    348 		struct psb_validate_rep *rep = &arg->d.rep;
    349 
    350 		if (!arg->handled) {
    351 			ret = -EFAULT;
    352 			goto out;
    353 		}
    354 		if (arg->ret != 0) {
    355 			ret = arg->ret;
    356 			goto out;
    357 		}
    358 		wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf),
    359 			       rep->gpu_offset, rep->placement, rep->fence_type_mask);
    360 	}
    361 out:
    362 	free(arg_list);
    363 	for (i = 0; i < buffer_count; i++) {
    364 		/*
    365 		 * Buffer no longer queued in userspace
    366 		 */
    367 		switch (buffer_list[i]->status) {
    368 		case psb_bs_queued:
    369 			buffer_list[i]->status = psb_bs_ready;
    370 			break;
    371 
    372 		case psb_bs_abandoned:
    373 			psb_buffer_destroy(buffer_list[i]);
    374 			free(buffer_list[i]);
    375 			break;
    376 
    377 		default:
    378 			/* Not supposed to happen */
    379 			ASSERT(0);
    380 		}
    381 	}
    382 
    383 	return ret;
    384 }
    385 
    386 /*
    387  * Submits the current cmdbuf
    388  *
    389  * Returns 0 on success
    390  */
    391 int vsp_context_submit_cmdbuf(object_context_p __maybe_unused obj_context)
    392 {
    393 	return 0;
    394 }
    395 
    396 
    397 /*
    398  * Flushes all cmdbufs
    399  */
    400 int vsp_context_flush_cmdbuf(object_context_p obj_context)
    401 {
    402 	vsp_cmdbuf_p cmdbuf = obj_context->vsp_cmdbuf;
    403 	psb_driver_data_p driver_data = obj_context->driver_data;
    404 	unsigned int fence_flags;
    405 	struct psb_ttm_fence_rep fence_rep;
    406 	unsigned int reloc_offset;
    407 	unsigned int num_relocs;
    408 	int ret;
    409 	unsigned int cmdbuffer_size = (unsigned char *)cmdbuf->cmd_idx - cmdbuf->cmd_start; /* In bytes */
    410 
    411 	ASSERT(cmdbuffer_size < CMD_SIZE);
    412 	ASSERT((void *) cmdbuf->cmd_idx < CMD_END(cmdbuf));
    413 	/* LOCK */
    414 	ret = LOCK_HARDWARE(driver_data);
    415 	if (ret) {
    416 		UNLOCK_HARDWARE(driver_data);
    417 		DEBUG_FAILURE_RET;
    418 		return ret;
    419 	}
    420 
    421 	/* Now calculate the total number of relocations */
    422 	reloc_offset = cmdbuf->reloc_base - cmdbuf->cmd_base;
    423 	num_relocs = ((unsigned char *)cmdbuf->reloc_idx - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
    424 
    425 	vsp_cmdbuf_unmap(cmdbuf);
    426 
    427 	ASSERT(NULL == cmdbuf->reloc_base);
    428 
    429 #ifdef DEBUG_TRACE
    430 	fence_flags = 0;
    431 #else
    432 	fence_flags = DRM_PSB_FENCE_NO_USER;
    433 #endif
    434 
    435 #ifndef VSP_ENGINE_VPP
    436 #define VSP_ENGINE_VPP  6
    437 #endif
    438 	wsbmWriteLockKernelBO();
    439 	ret = vspDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset,
    440 			   cmdbuf->buffer_refs, cmdbuf->buffer_refs_count, wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)),
    441 			   0, cmdbuffer_size,/*unsigned cmdBufSize*/
    442 			   wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)), reloc_offset, num_relocs,
    443 			   0, VSP_ENGINE_VPP, fence_flags, &fence_rep);
    444 	wsbmWriteUnlockKernelBO();
    445 	UNLOCK_HARDWARE(driver_data);
    446 
    447 	if (ret) {
    448 		obj_context->vsp_cmdbuf = NULL;
    449 
    450 		DEBUG_FAILURE_RET;
    451 		return ret;
    452 	}
    453 
    454 	obj_context->vsp_cmdbuf = NULL;
    455 
    456 	return 0;
    457 }
    458