aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/i915_execbuf.c')
-rw-r--r--linux-core/i915_execbuf.c917
1 files changed, 917 insertions, 0 deletions
diff --git a/linux-core/i915_execbuf.c b/linux-core/i915_execbuf.c
new file mode 100644
index 00000000..804f3ac1
--- /dev/null
+++ b/linux-core/i915_execbuf.c
@@ -0,0 +1,917 @@
1/*
2 * Copyright 2003-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3 * All Rights Reserved.
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 TUNGSTEN GRAPHICS 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 * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
27 * Dave Airlie
28 * Keith Packard
29 * ... ?
30 */
31
32#include "drmP.h"
33#include "drm.h"
34#include "i915_drm.h"
35#include "i915_drv.h"
36
37#if DRM_DEBUG_CODE
38#define DRM_DEBUG_RELOCATION (drm_debug != 0)
39#else
40#define DRM_DEBUG_RELOCATION 0
41#endif
42
43enum i915_buf_idle {
44 I915_RELOC_UNCHECKED,
45 I915_RELOC_IDLE,
46 I915_RELOC_BUSY
47};
48
49struct i915_relocatee_info {
50 struct drm_buffer_object *buf;
51 unsigned long offset;
52 uint32_t *data_page;
53 unsigned page_offset;
54 struct drm_bo_kmap_obj kmap;
55 int is_iomem;
56 int dst;
57 int idle;
58 int performed_ring_relocs;
59#ifdef DRM_KMAP_ATOMIC_PROT_PFN
60 unsigned long pfn;
61 pgprot_t pg_prot;
62#endif
63};
64
65struct drm_i915_validate_buffer {
66 struct drm_buffer_object *buffer;
67 int presumed_offset_correct;
68 void __user *data;
69 int ret;
70 enum i915_buf_idle idle;
71};
72
73/*
74 * I'd like to use MI_STORE_DATA_IMM here, but I can't make
75 * it work. Seems like GART writes are broken with that
76 * instruction. Also I'm not sure that MI_FLUSH will
77 * act as a memory barrier for that instruction. It will
78 * for this single dword 2D blit.
79 */
80
81static void i915_emit_ring_reloc(struct drm_device *dev, uint32_t offset,
82 uint32_t value)
83{
84 struct drm_i915_private *dev_priv =
85 (struct drm_i915_private *)dev->dev_private;
86
87 RING_LOCALS;
88 i915_kernel_lost_context(dev);
89 BEGIN_LP_RING(6);
90 OUT_RING((0x02 << 29) | (0x40 << 22) | (0x3 << 20) | (0x3));
91 OUT_RING((0x3 << 24) | (0xF0 << 16) | (0x40));
92 OUT_RING((0x1 << 16) | (0x4));
93 OUT_RING(offset);
94 OUT_RING(value);
95 OUT_RING(0);
96 ADVANCE_LP_RING();
97}
98
99static void i915_dereference_buffers_locked(struct drm_i915_validate_buffer
100 *buffers, unsigned num_buffers)
101{
102 while (num_buffers--)
103 drm_bo_usage_deref_locked(&buffers[num_buffers].buffer);
104}
105
106int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
107 struct drm_i915_validate_buffer *buffers,
108 struct i915_relocatee_info *relocatee, uint32_t * reloc)
109{
110 unsigned index;
111 unsigned long new_cmd_offset;
112 u32 val;
113 int ret, i;
114 int buf_index = -1;
115
116 /*
117 * FIXME: O(relocs * buffers) complexity.
118 */
119
120 for (i = 0; i <= num_buffers; i++)
121 if (buffers[i].buffer)
122 if (reloc[2] == buffers[i].buffer->base.hash.key)
123 buf_index = i;
124
125 if (buf_index == -1) {
126 DRM_ERROR("Illegal relocation buffer %08X\n", reloc[2]);
127 return -EINVAL;
128 }
129
130 /*
131 * Short-circuit relocations that were correctly
132 * guessed by the client
133 */
134 if (buffers[buf_index].presumed_offset_correct && !DRM_DEBUG_RELOCATION)
135 return 0;
136
137 new_cmd_offset = reloc[0];
138 if (!relocatee->data_page ||
139 !drm_bo_same_page(relocatee->offset, new_cmd_offset)) {
140 struct drm_bo_mem_reg *mem = &relocatee->buf->mem;
141
142 drm_bo_kunmap(&relocatee->kmap);
143 relocatee->data_page = NULL;
144 relocatee->offset = new_cmd_offset;
145
146 if (unlikely(relocatee->idle == I915_RELOC_UNCHECKED)) {
147 ret = drm_bo_wait(relocatee->buf, 0, 1, 0, 0);
148 if (ret)
149 return ret;
150 relocatee->idle = I915_RELOC_IDLE;
151 }
152
153 if (unlikely((mem->mem_type != DRM_BO_MEM_LOCAL) &&
154 (mem->flags & DRM_BO_FLAG_CACHED_MAPPED)))
155 drm_bo_evict_cached(relocatee->buf);
156
157 ret = drm_bo_kmap(relocatee->buf, new_cmd_offset >> PAGE_SHIFT,
158 1, &relocatee->kmap);
159 if (ret) {
160 DRM_ERROR
161 ("Could not map command buffer to apply relocs\n %08lx",
162 new_cmd_offset);
163 return ret;
164 }
165 relocatee->data_page = drm_bmo_virtual(&relocatee->kmap,
166 &relocatee->is_iomem);
167 relocatee->page_offset = (relocatee->offset & PAGE_MASK);
168 }
169
170 val = buffers[buf_index].buffer->offset;
171 index = (reloc[0] - relocatee->page_offset) >> 2;
172
173 /* add in validate */
174 val = val + reloc[1];
175
176 if (DRM_DEBUG_RELOCATION) {
177 if (buffers[buf_index].presumed_offset_correct &&
178 relocatee->data_page[index] != val) {
179 DRM_DEBUG
180 ("Relocation mismatch source %d target %d buffer %d user %08x kernel %08x\n",
181 reloc[0], reloc[1], buf_index,
182 relocatee->data_page[index], val);
183 }
184 }
185
186 if (relocatee->is_iomem)
187 iowrite32(val, relocatee->data_page + index);
188 else
189 relocatee->data_page[index] = val;
190 return 0;
191}
192
193int i915_process_relocs(struct drm_file *file_priv,
194 uint32_t buf_handle,
195 uint32_t __user ** reloc_user_ptr,
196 struct i915_relocatee_info *relocatee,
197 struct drm_i915_validate_buffer *buffers,
198 uint32_t num_buffers)
199{
200 int ret, reloc_stride;
201 uint32_t cur_offset;
202 uint32_t reloc_count;
203 uint32_t reloc_type;
204 uint32_t reloc_buf_size;
205 uint32_t *reloc_buf = NULL;
206 int i;
207
208 /* do a copy from user from the user ptr */
209 ret = get_user(reloc_count, *reloc_user_ptr);
210 if (ret) {
211 DRM_ERROR("Could not map relocation buffer.\n");
212 goto out;
213 }
214
215 ret = get_user(reloc_type, (*reloc_user_ptr) + 1);
216 if (ret) {
217 DRM_ERROR("Could not map relocation buffer.\n");
218 goto out;
219 }
220
221 if (reloc_type != 0) {
222 DRM_ERROR("Unsupported relocation type requested\n");
223 ret = -EINVAL;
224 goto out;
225 }
226
227 reloc_buf_size =
228 (I915_RELOC_HEADER +
229 (reloc_count * I915_RELOC0_STRIDE)) * sizeof(uint32_t);
230 reloc_buf = kmalloc(reloc_buf_size, GFP_KERNEL);
231 if (!reloc_buf) {
232 DRM_ERROR("Out of memory for reloc buffer\n");
233 ret = -ENOMEM;
234 goto out;
235 }
236
237 if (copy_from_user(reloc_buf, *reloc_user_ptr, reloc_buf_size)) {
238 ret = -EFAULT;
239 goto out;
240 }
241
242 /* get next relocate buffer handle */
243 *reloc_user_ptr = (uint32_t *) * (unsigned long *)&reloc_buf[2];
244
245 reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); /* may be different for other types of relocs */
246
247 DRM_DEBUG("num relocs is %d, next is %p\n", reloc_count,
248 *reloc_user_ptr);
249
250 for (i = 0; i < reloc_count; i++) {
251 cur_offset = I915_RELOC_HEADER + (i * I915_RELOC0_STRIDE);
252
253 ret = i915_apply_reloc(file_priv, num_buffers, buffers,
254 relocatee, reloc_buf + cur_offset);
255 if (ret)
256 goto out;
257 }
258
259 out:
260 if (reloc_buf)
261 kfree(reloc_buf);
262
263 if (relocatee->data_page) {
264 drm_bo_kunmap(&relocatee->kmap);
265 relocatee->data_page = NULL;
266 }
267
268 return ret;
269}
270
271static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
272 uint32_t __user * reloc_user_ptr,
273 struct drm_i915_validate_buffer *buffers,
274 uint32_t buf_count)
275{
276 struct drm_device *dev = file_priv->minor->dev;
277 struct i915_relocatee_info relocatee;
278 int ret = 0;
279 int b;
280
281 /*
282 * Short circuit relocations when all previous
283 * buffers offsets were correctly guessed by
284 * the client
285 */
286 if (!DRM_DEBUG_RELOCATION) {
287 for (b = 0; b < buf_count; b++)
288 if (!buffers[b].presumed_offset_correct)
289 break;
290
291 if (b == buf_count)
292 return 0;
293 }
294
295 memset(&relocatee, 0, sizeof(relocatee));
296 relocatee.idle = I915_RELOC_UNCHECKED;
297
298 mutex_lock(&dev->struct_mutex);
299 relocatee.buf = drm_lookup_buffer_object(file_priv, buf_handle, 1);
300 mutex_unlock(&dev->struct_mutex);
301 if (!relocatee.buf) {
302 DRM_DEBUG("relocatee buffer invalid %08x\n", buf_handle);
303 ret = -EINVAL;
304 goto out_err;
305 }
306
307 mutex_lock(&relocatee.buf->mutex);
308 while (reloc_user_ptr) {
309 ret =
310 i915_process_relocs(file_priv, buf_handle, &reloc_user_ptr,
311 &relocatee, buffers, buf_count);
312 if (ret) {
313 DRM_ERROR("process relocs failed\n");
314 goto out_err1;
315 }
316 }
317
318 out_err1:
319 mutex_unlock(&relocatee.buf->mutex);
320 drm_bo_usage_deref_unlocked(&relocatee.buf);
321 out_err:
322 return ret;
323}
324
325static void i915_clear_relocatee(struct i915_relocatee_info *relocatee)
326{
327 if (relocatee->data_page) {
328#ifndef DRM_KMAP_ATOMIC_PROT_PFN
329 drm_bo_kunmap(&relocatee->kmap);
330#else
331 kunmap_atomic(relocatee->data_page, KM_USER0);
332#endif
333 relocatee->data_page = NULL;
334 }
335 relocatee->buf = NULL;
336 relocatee->dst = ~0;
337}
338
339static int i915_update_relocatee(struct i915_relocatee_info *relocatee,
340 struct drm_i915_validate_buffer *buffers,
341 unsigned int dst, unsigned long dst_offset)
342{
343 int ret;
344
345 if (unlikely(dst != relocatee->dst || NULL == relocatee->buf)) {
346 i915_clear_relocatee(relocatee);
347 relocatee->dst = dst;
348 relocatee->buf = buffers[dst].buffer;
349 relocatee->idle = buffers[dst].idle;
350
351 /*
352 * Check for buffer idle. If the buffer is busy, revert to
353 * ring relocations.
354 */
355
356 if (relocatee->idle == I915_RELOC_UNCHECKED) {
357 preempt_enable();
358 mutex_lock(&relocatee->buf->mutex);
359
360 ret = drm_bo_wait(relocatee->buf, 0, 1, 1, 0);
361 if (ret == 0)
362 relocatee->idle = I915_RELOC_IDLE;
363 else {
364 relocatee->idle = I915_RELOC_BUSY;
365 relocatee->performed_ring_relocs = 1;
366 }
367 mutex_unlock(&relocatee->buf->mutex);
368 preempt_disable();
369 buffers[dst].idle = relocatee->idle;
370 }
371 }
372
373 if (relocatee->idle == I915_RELOC_BUSY)
374 return 0;
375
376 if (unlikely(dst_offset > relocatee->buf->num_pages * PAGE_SIZE)) {
377 DRM_ERROR("Relocation destination out of bounds.\n");
378 return -EINVAL;
379 }
380 if (unlikely(!drm_bo_same_page(relocatee->page_offset, dst_offset) ||
381 NULL == relocatee->data_page)) {
382#ifdef DRM_KMAP_ATOMIC_PROT_PFN
383 if (NULL != relocatee->data_page) {
384 kunmap_atomic(relocatee->data_page, KM_USER0);
385 relocatee->data_page = NULL;
386 }
387 ret = drm_bo_pfn_prot(relocatee->buf, dst_offset,
388 &relocatee->pfn, &relocatee->pg_prot);
389 if (ret) {
390 DRM_ERROR("Can't map relocation destination.\n");
391 return -EINVAL;
392 }
393 relocatee->data_page =
394 kmap_atomic_prot_pfn(relocatee->pfn, KM_USER0,
395 relocatee->pg_prot);
396#else
397 if (NULL != relocatee->data_page) {
398 drm_bo_kunmap(&relocatee->kmap);
399 relocatee->data_page = NULL;
400 }
401
402 ret = drm_bo_kmap(relocatee->buf, dst_offset >> PAGE_SHIFT,
403 1, &relocatee->kmap);
404 if (ret) {
405 DRM_ERROR("Can't map relocation destination.\n");
406 return ret;
407 }
408
409 relocatee->data_page = drm_bmo_virtual(&relocatee->kmap,
410 &relocatee->is_iomem);
411#endif
412 relocatee->page_offset = dst_offset & PAGE_MASK;
413 }
414 return 0;
415}
416
417static int i915_apply_post_reloc(uint32_t reloc[],
418 struct drm_i915_validate_buffer *buffers,
419 uint32_t num_buffers,
420 struct i915_relocatee_info *relocatee)
421{
422 uint32_t reloc_buffer = reloc[2];
423 uint32_t dst_buffer = reloc[3];
424 uint32_t val;
425 uint32_t index;
426 int ret;
427
428 if (likely(buffers[reloc_buffer].presumed_offset_correct))
429 return 0;
430 if (unlikely(reloc_buffer >= num_buffers)) {
431 DRM_ERROR("Invalid reloc buffer index.\n");
432 return -EINVAL;
433 }
434 if (unlikely(dst_buffer >= num_buffers)) {
435 DRM_ERROR("Invalid dest buffer index.\n");
436 return -EINVAL;
437 }
438
439 ret = i915_update_relocatee(relocatee, buffers, dst_buffer, reloc[0]);
440 if (unlikely(ret))
441 return ret;
442
443 val = buffers[reloc_buffer].buffer->offset;
444 index = (reloc[0] - relocatee->page_offset) >> 2;
445 val = val + reloc[1];
446
447 if (relocatee->idle == I915_RELOC_BUSY) {
448 i915_emit_ring_reloc(relocatee->buf->dev,
449 relocatee->buf->offset + reloc[0], val);
450 return 0;
451 }
452#ifdef DRM_KMAP_ATOMIC_PROT_PFN
453 relocatee->data_page[index] = val;
454#else
455 if (likely(relocatee->is_iomem))
456 iowrite32(val, relocatee->data_page + index);
457 else
458 relocatee->data_page[index] = val;
459#endif
460
461 return 0;
462}
463
464static int i915_post_relocs(struct drm_file *file_priv,
465 uint32_t __user * new_reloc_ptr,
466 struct drm_i915_validate_buffer *buffers,
467 unsigned int num_buffers)
468{
469 uint32_t *reloc;
470 uint32_t reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t);
471 uint32_t header_size = I915_RELOC_HEADER * sizeof(uint32_t);
472 struct i915_relocatee_info relocatee;
473 uint32_t reloc_type;
474 uint32_t num_relocs;
475 uint32_t count;
476 int ret = 0;
477 int i;
478 int short_circuit = 1;
479 uint32_t __user *reloc_ptr;
480 uint64_t new_reloc_data;
481 uint32_t reloc_buf_size;
482 uint32_t *reloc_buf;
483
484 for (i = 0; i < num_buffers; ++i) {
485 if (unlikely(!buffers[i].presumed_offset_correct)) {
486 short_circuit = 0;
487 break;
488 }
489 }
490
491 if (likely(short_circuit))
492 return 0;
493
494 memset(&relocatee, 0, sizeof(relocatee));
495
496 while (new_reloc_ptr) {
497 reloc_ptr = new_reloc_ptr;
498
499 ret = get_user(num_relocs, reloc_ptr);
500 if (unlikely(ret))
501 goto out;
502 if (unlikely(!access_ok(VERIFY_READ, reloc_ptr,
503 header_size +
504 num_relocs * reloc_stride)))
505 return -EFAULT;
506
507 ret = __get_user(reloc_type, reloc_ptr + 1);
508 if (unlikely(ret))
509 goto out;
510
511 if (unlikely(reloc_type != 1)) {
512 DRM_ERROR("Unsupported relocation type requested.\n");
513 ret = -EINVAL;
514 goto out;
515 }
516
517 ret = __get_user(new_reloc_data, reloc_ptr + 2);
518 new_reloc_ptr = (uint32_t __user *) (unsigned long)
519 new_reloc_data;
520
521 reloc_ptr += I915_RELOC_HEADER;
522
523 if (num_relocs == 0)
524 goto out;
525
526 reloc_buf_size =
527 (num_relocs * I915_RELOC0_STRIDE) * sizeof(uint32_t);
528 reloc_buf = kmalloc(reloc_buf_size, GFP_KERNEL);
529 if (!reloc_buf) {
530 DRM_ERROR("Out of memory for reloc buffer\n");
531 ret = -ENOMEM;
532 goto out;
533 }
534
535 if (__copy_from_user(reloc_buf, reloc_ptr, reloc_buf_size)) {
536 ret = -EFAULT;
537 goto out;
538 }
539 reloc = reloc_buf;
540 preempt_disable();
541 for (count = 0; count < num_relocs; ++count) {
542 ret = i915_apply_post_reloc(reloc, buffers,
543 num_buffers, &relocatee);
544 if (unlikely(ret)) {
545 preempt_enable();
546 goto out;
547 }
548 reloc += I915_RELOC0_STRIDE;
549 }
550 preempt_enable();
551
552 if (reloc_buf) {
553 kfree(reloc_buf);
554 reloc_buf = NULL;
555 }
556 i915_clear_relocatee(&relocatee);
557 }
558
559 out:
560 /*
561 * Flush ring relocs so the command parser will pick them up.
562 */
563
564 if (relocatee.performed_ring_relocs)
565 (void)i915_emit_mi_flush(file_priv->minor->dev, 0);
566
567 i915_clear_relocatee(&relocatee);
568 if (reloc_buf) {
569 kfree(reloc_buf);
570 reloc_buf = NULL;
571 }
572
573 return ret;
574}
575
576static int i915_check_presumed(struct drm_i915_op_arg *arg,
577 struct drm_buffer_object *bo,
578 uint32_t __user * data, int *presumed_ok)
579{
580 struct drm_bo_op_req *req = &arg->d.req;
581 uint32_t hint_offset;
582 uint32_t hint = req->bo_req.hint;
583
584 *presumed_ok = 0;
585
586 if (!(hint & DRM_BO_HINT_PRESUMED_OFFSET))
587 return 0;
588 if (bo->offset == req->bo_req.presumed_offset) {
589 *presumed_ok = 1;
590 return 0;
591 }
592
593 /*
594 * We need to turn off the HINT_PRESUMED_OFFSET for this buffer in
595 * the user-space IOCTL argument list, since the buffer has moved,
596 * we're about to apply relocations and we might subsequently
597 * hit an -EAGAIN. In that case the argument list will be reused by
598 * user-space, but the presumed offset is no longer valid.
599 *
600 * Needless to say, this is a bit ugly.
601 */
602
603 hint_offset = (uint32_t *) & req->bo_req.hint - (uint32_t *) arg;
604 hint &= ~DRM_BO_HINT_PRESUMED_OFFSET;
605 return __put_user(hint, data + hint_offset);
606}
607
608/*
609 * Validate, add fence and relocate a block of bos from a userspace list
610 */
611int i915_validate_buffer_list(struct drm_file *file_priv,
612 unsigned int fence_class, uint64_t data,
613 struct drm_i915_validate_buffer *buffers,
614 uint32_t * num_buffers,
615 uint32_t __user ** post_relocs)
616{
617 struct drm_i915_op_arg arg;
618 struct drm_bo_op_req *req = &arg.d.req;
619 int ret = 0;
620 unsigned buf_count = 0;
621 uint32_t buf_handle;
622 uint32_t __user *reloc_user_ptr;
623 struct drm_i915_validate_buffer *item = buffers;
624 *post_relocs = NULL;
625
626 do {
627 if (buf_count >= *num_buffers) {
628 DRM_ERROR("Buffer count exceeded %d\n.", *num_buffers);
629 ret = -EINVAL;
630 goto out_err;
631 }
632 item = buffers + buf_count;
633 item->buffer = NULL;
634 item->presumed_offset_correct = 0;
635 item->idle = I915_RELOC_UNCHECKED;
636
637 if (copy_from_user
638 (&arg, (void __user *)(unsigned long)data, sizeof(arg))) {
639 ret = -EFAULT;
640 goto out_err;
641 }
642
643 ret = 0;
644 if (req->op != drm_bo_validate) {
645 DRM_ERROR
646 ("Buffer object operation wasn't \"validate\".\n");
647 ret = -EINVAL;
648 goto out_err;
649 }
650 item->ret = 0;
651 item->data = (void __user *)(unsigned long)data;
652
653 buf_handle = req->bo_req.handle;
654 reloc_user_ptr = (uint32_t *) (unsigned long)arg.reloc_ptr;
655
656 /*
657 * Switch mode to post-validation relocations?
658 */
659
660 if (unlikely((buf_count == 0) && (*post_relocs == NULL) &&
661 (reloc_user_ptr != NULL))) {
662 uint32_t reloc_type;
663
664 ret = get_user(reloc_type, reloc_user_ptr + 1);
665 if (ret)
666 goto out_err;
667
668 if (reloc_type == 1)
669 *post_relocs = reloc_user_ptr;
670
671 }
672
673 if ((*post_relocs == NULL) && (reloc_user_ptr != NULL)) {
674 ret =
675 i915_exec_reloc(file_priv, buf_handle,
676 reloc_user_ptr, buffers, buf_count);
677 if (ret)
678 goto out_err;
679 DRM_MEMORYBARRIER();
680 }
681
682 ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
683 req->bo_req.flags,
684 req->bo_req.mask, req->bo_req.hint,
685 req->bo_req.fence_class,
686 NULL, &item->buffer);
687 if (ret) {
688 DRM_ERROR("error on handle validate %d\n", ret);
689 goto out_err;
690 }
691
692 buf_count++;
693
694 ret = i915_check_presumed(&arg, item->buffer,
695 (uint32_t __user *)
696 (unsigned long)data,
697 &item->presumed_offset_correct);
698 if (ret)
699 goto out_err;
700
701 data = arg.next;
702 } while (data != 0);
703 out_err:
704 *num_buffers = buf_count;
705 item->ret = (ret != -EAGAIN) ? ret : 0;
706 return ret;
707}
708
709/*
710 * Remove all buffers from the unfenced list.
711 * If the execbuffer operation was aborted, for example due to a signal,
712 * this also make sure that buffers retain their original state and
713 * fence pointers.
714 * Copy back buffer information to user-space unless we were interrupted
715 * by a signal. In which case the IOCTL must be rerun.
716 */
717
718static int i915_handle_copyback(struct drm_device *dev,
719 struct drm_i915_validate_buffer *buffers,
720 unsigned int num_buffers, int ret)
721{
722 int err = ret;
723 int i;
724 struct drm_i915_op_arg arg;
725 struct drm_buffer_object *bo;
726
727 if (ret)
728 drm_putback_buffer_objects(dev);
729
730 if (ret != -EAGAIN) {
731 for (i = 0; i < num_buffers; ++i) {
732 arg.handled = 1;
733 arg.d.rep.ret = buffers->ret;
734 bo = buffers->buffer;
735 mutex_lock(&bo->mutex);
736 drm_bo_fill_rep_arg(bo, &arg.d.rep.bo_info);
737 mutex_unlock(&bo->mutex);
738 if (__copy_to_user(buffers->data, &arg, sizeof(arg)))
739 err = -EFAULT;
740 buffers++;
741 }
742 }
743
744 return err;
745}
746
747/*
748 * Create a fence object, and if that fails, pretend that everything is
749 * OK and just idle the GPU.
750 */
751
752void i915_fence_or_sync(struct drm_file *file_priv,
753 uint32_t fence_flags,
754 struct drm_fence_arg *fence_arg,
755 struct drm_fence_object **fence_p)
756{
757 struct drm_device *dev = file_priv->minor->dev;
758 int ret;
759 struct drm_fence_object *fence;
760
761 ret = drm_fence_buffer_objects(dev, NULL, fence_flags, NULL, &fence);
762
763 if (ret) {
764
765 /*
766 * Fence creation failed.
767 * Fall back to synchronous operation and idle the engine.
768 */
769
770 (void)i915_emit_mi_flush(dev, MI_READ_FLUSH);
771 (void)i915_quiescent(dev);
772
773 if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) {
774
775 /*
776 * Communicate to user-space that
777 * fence creation has failed and that
778 * the engine is idle.
779 */
780
781 fence_arg->handle = ~0;
782 fence_arg->error = ret;
783 }
784 drm_putback_buffer_objects(dev);
785 if (fence_p)
786 *fence_p = NULL;
787 return;
788 }
789
790 if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) {
791
792 ret = drm_fence_add_user_object(file_priv, fence,
793 fence_flags &
794 DRM_FENCE_FLAG_SHAREABLE);
795 if (!ret)
796 drm_fence_fill_arg(fence, fence_arg);
797 else {
798 /*
799 * Fence user object creation failed.
800 * We must idle the engine here as well, as user-
801 * space expects a fence object to wait on. Since we
802 * have a fence object we wait for it to signal
803 * to indicate engine "sufficiently" idle.
804 */
805
806 (void)drm_fence_object_wait(fence, 0, 1, fence->type);
807 drm_fence_usage_deref_unlocked(&fence);
808 fence_arg->handle = ~0;
809 fence_arg->error = ret;
810 }
811 }
812
813 if (fence_p)
814 *fence_p = fence;
815 else if (fence)
816 drm_fence_usage_deref_unlocked(&fence);
817}
818
819int i915_execbuffer(struct drm_device *dev, void *data,
820 struct drm_file *file_priv)
821{
822 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
823 drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
824 dev_priv->sarea_priv;
825 struct drm_i915_execbuffer *exec_buf = data;
826 struct drm_i915_batchbuffer *batch = &exec_buf->batch;
827 struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
828 int num_buffers;
829 int ret;
830 uint32_t __user *post_relocs;
831
832 if (!dev_priv->allow_batchbuffer) {
833 DRM_ERROR("Batchbuffer ioctl disabled\n");
834 return -EINVAL;
835 }
836
837 if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
838 batch->num_cliprects *
839 sizeof(struct
840 drm_clip_rect)))
841 return -EFAULT;
842
843 if (exec_buf->num_buffers > dev_priv->max_validate_buffers)
844 return -EINVAL;
845
846 ret = drm_bo_read_lock(&dev->bm.bm_lock, 1);
847 if (ret)
848 return ret;
849
850 /*
851 * The cmdbuf_mutex makes sure the validate-submit-fence
852 * operation is atomic.
853 */
854
855 ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
856 if (ret) {
857 drm_bo_read_unlock(&dev->bm.bm_lock);
858 return -EAGAIN;
859 }
860
861 num_buffers = exec_buf->num_buffers;
862
863 if (!dev_priv->val_bufs) {
864 dev_priv->val_bufs =
865 vmalloc(sizeof(struct drm_i915_validate_buffer) *
866 dev_priv->max_validate_buffers);
867 }
868 if (!dev_priv->val_bufs) {
869 drm_bo_read_unlock(&dev->bm.bm_lock);
870 mutex_unlock(&dev_priv->cmdbuf_mutex);
871 return -ENOMEM;
872 }
873
874 /* validate buffer list + fixup relocations */
875 ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list,
876 dev_priv->val_bufs, &num_buffers,
877 &post_relocs);
878 if (ret)
879 goto out_err0;
880
881 if (post_relocs) {
882 ret = i915_post_relocs(file_priv, post_relocs,
883 dev_priv->val_bufs, num_buffers);
884 if (ret)
885 goto out_err0;
886 }
887
888 /* make sure all previous memory operations have passed */
889 DRM_MEMORYBARRIER();
890
891 if (!post_relocs) {
892 drm_agp_chipset_flush(dev);
893 batch->start =
894 dev_priv->val_bufs[num_buffers - 1].buffer->offset;
895 } else {
896 batch->start += dev_priv->val_bufs[0].buffer->offset;
897 }
898
899 DRM_DEBUG("i915 exec batchbuffer, start %x used %d cliprects %d\n",
900 batch->start, batch->used, batch->num_cliprects);
901
902 ret = i915_dispatch_batchbuffer(dev, batch);
903 if (ret)
904 goto out_err0;
905 if (sarea_priv)
906 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
907 i915_fence_or_sync(file_priv, fence_arg->flags, fence_arg, NULL);
908
909 out_err0:
910 ret = i915_handle_copyback(dev, dev_priv->val_bufs, num_buffers, ret);
911 mutex_lock(&dev->struct_mutex);
912 i915_dereference_buffers_locked(dev_priv->val_bufs, num_buffers);
913 mutex_unlock(&dev->struct_mutex);
914 mutex_unlock(&dev_priv->cmdbuf_mutex);
915 drm_bo_read_unlock(&dev->bm.bm_lock);
916 return ret;
917}