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