OSDN Git Service

drm/radeon: fix regression in UMS CS ioctl
[uclinux-h8/linux.git] / drivers / gpu / drm / radeon / radeon_cs.c
1 /*
2  * Copyright 2008 Jerome Glisse.
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 "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jerome Glisse <glisse@freedesktop.org>
26  */
27 #include "drmP.h"
28 #include "radeon_drm.h"
29 #include "radeon_reg.h"
30 #include "radeon.h"
31
32 void r100_cs_dump_packet(struct radeon_cs_parser *p,
33                          struct radeon_cs_packet *pkt);
34
35 int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
36 {
37         struct drm_device *ddev = p->rdev->ddev;
38         struct radeon_cs_chunk *chunk;
39         unsigned i, j;
40         bool duplicate;
41
42         if (p->chunk_relocs_idx == -1) {
43                 return 0;
44         }
45         chunk = &p->chunks[p->chunk_relocs_idx];
46         /* FIXME: we assume that each relocs use 4 dwords */
47         p->nrelocs = chunk->length_dw / 4;
48         p->relocs_ptr = kcalloc(p->nrelocs, sizeof(void *), GFP_KERNEL);
49         if (p->relocs_ptr == NULL) {
50                 return -ENOMEM;
51         }
52         p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL);
53         if (p->relocs == NULL) {
54                 return -ENOMEM;
55         }
56         for (i = 0; i < p->nrelocs; i++) {
57                 struct drm_radeon_cs_reloc *r;
58
59                 duplicate = false;
60                 r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4];
61                 for (j = 0; j < i; j++) {
62                         if (r->handle == p->relocs[j].handle) {
63                                 p->relocs_ptr[i] = &p->relocs[j];
64                                 duplicate = true;
65                                 break;
66                         }
67                 }
68                 if (!duplicate) {
69                         p->relocs[i].gobj = drm_gem_object_lookup(ddev,
70                                                                   p->filp,
71                                                                   r->handle);
72                         if (p->relocs[i].gobj == NULL) {
73                                 DRM_ERROR("gem object lookup failed 0x%x\n",
74                                           r->handle);
75                                 return -ENOENT;
76                         }
77                         p->relocs_ptr[i] = &p->relocs[i];
78                         p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj);
79                         p->relocs[i].lobj.bo = p->relocs[i].robj;
80                         p->relocs[i].lobj.wdomain = r->write_domain;
81                         p->relocs[i].lobj.rdomain = r->read_domains;
82                         p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo;
83                         p->relocs[i].handle = r->handle;
84                         p->relocs[i].flags = r->flags;
85                         radeon_bo_list_add_object(&p->relocs[i].lobj,
86                                                   &p->validated);
87
88                 } else
89                         p->relocs[i].handle = 0;
90         }
91         return radeon_bo_list_validate(&p->validated);
92 }
93
94 static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
95 {
96         p->priority = priority;
97
98         switch (ring) {
99         default:
100                 DRM_ERROR("unknown ring id: %d\n", ring);
101                 return -EINVAL;
102         case RADEON_CS_RING_GFX:
103                 p->ring = RADEON_RING_TYPE_GFX_INDEX;
104                 break;
105         case RADEON_CS_RING_COMPUTE:
106                 if (p->rdev->family >= CHIP_TAHITI) {
107                         if (p->priority > 0)
108                                 p->ring = CAYMAN_RING_TYPE_CP1_INDEX;
109                         else
110                                 p->ring = CAYMAN_RING_TYPE_CP2_INDEX;
111                 } else
112                         p->ring = RADEON_RING_TYPE_GFX_INDEX;
113                 break;
114         }
115         return 0;
116 }
117
118 static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
119 {
120         bool sync_to_ring[RADEON_NUM_RINGS] = { };
121         bool need_sync = false;
122         int i, r;
123
124         for (i = 0; i < p->nrelocs; i++) {
125                 struct radeon_fence *fence;
126
127                 if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj)
128                         continue;
129
130                 fence = p->relocs[i].robj->tbo.sync_obj;
131                 if (fence->ring != p->ring && !radeon_fence_signaled(fence)) {
132                         sync_to_ring[fence->ring] = true;
133                         need_sync = true;
134                 }
135         }
136
137         if (!need_sync) {
138                 return 0;
139         }
140
141         r = radeon_semaphore_create(p->rdev, &p->ib.semaphore);
142         if (r) {
143                 return r;
144         }
145
146         return radeon_semaphore_sync_rings(p->rdev, p->ib.semaphore,
147                                            sync_to_ring, p->ring);
148 }
149
150 /* XXX: note that this is called from the legacy UMS CS ioctl as well */
151 int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
152 {
153         struct drm_radeon_cs *cs = data;
154         uint64_t *chunk_array_ptr;
155         unsigned size, i;
156         u32 ring = RADEON_CS_RING_GFX;
157         s32 priority = 0;
158
159         if (!cs->num_chunks) {
160                 return 0;
161         }
162         /* get chunks */
163         INIT_LIST_HEAD(&p->validated);
164         p->idx = 0;
165         p->ib.sa_bo = NULL;
166         p->ib.semaphore = NULL;
167         p->const_ib.sa_bo = NULL;
168         p->const_ib.semaphore = NULL;
169         p->chunk_ib_idx = -1;
170         p->chunk_relocs_idx = -1;
171         p->chunk_flags_idx = -1;
172         p->chunk_const_ib_idx = -1;
173         p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
174         if (p->chunks_array == NULL) {
175                 return -ENOMEM;
176         }
177         chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
178         if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr,
179                                sizeof(uint64_t)*cs->num_chunks)) {
180                 return -EFAULT;
181         }
182         p->cs_flags = 0;
183         p->nchunks = cs->num_chunks;
184         p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL);
185         if (p->chunks == NULL) {
186                 return -ENOMEM;
187         }
188         for (i = 0; i < p->nchunks; i++) {
189                 struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
190                 struct drm_radeon_cs_chunk user_chunk;
191                 uint32_t __user *cdata;
192
193                 chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i];
194                 if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr,
195                                        sizeof(struct drm_radeon_cs_chunk))) {
196                         return -EFAULT;
197                 }
198                 p->chunks[i].length_dw = user_chunk.length_dw;
199                 p->chunks[i].kdata = NULL;
200                 p->chunks[i].chunk_id = user_chunk.chunk_id;
201
202                 if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {
203                         p->chunk_relocs_idx = i;
204                 }
205                 if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
206                         p->chunk_ib_idx = i;
207                         /* zero length IB isn't useful */
208                         if (p->chunks[i].length_dw == 0)
209                                 return -EINVAL;
210                 }
211                 if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB) {
212                         p->chunk_const_ib_idx = i;
213                         /* zero length CONST IB isn't useful */
214                         if (p->chunks[i].length_dw == 0)
215                                 return -EINVAL;
216                 }
217                 if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
218                         p->chunk_flags_idx = i;
219                         /* zero length flags aren't useful */
220                         if (p->chunks[i].length_dw == 0)
221                                 return -EINVAL;
222                 }
223
224                 p->chunks[i].length_dw = user_chunk.length_dw;
225                 p->chunks[i].user_ptr = (void __user *)(unsigned long)user_chunk.chunk_data;
226
227                 cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data;
228                 if ((p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) ||
229                     (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS)) {
230                         size = p->chunks[i].length_dw * sizeof(uint32_t);
231                         p->chunks[i].kdata = kmalloc(size, GFP_KERNEL);
232                         if (p->chunks[i].kdata == NULL) {
233                                 return -ENOMEM;
234                         }
235                         if (DRM_COPY_FROM_USER(p->chunks[i].kdata,
236                                                p->chunks[i].user_ptr, size)) {
237                                 return -EFAULT;
238                         }
239                         if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
240                                 p->cs_flags = p->chunks[i].kdata[0];
241                                 if (p->chunks[i].length_dw > 1)
242                                         ring = p->chunks[i].kdata[1];
243                                 if (p->chunks[i].length_dw > 2)
244                                         priority = (s32)p->chunks[i].kdata[2];
245                         }
246                 }
247         }
248
249         /* these are KMS only */
250         if (p->rdev) {
251                 if ((p->cs_flags & RADEON_CS_USE_VM) &&
252                     !p->rdev->vm_manager.enabled) {
253                         DRM_ERROR("VM not active on asic!\n");
254                         return -EINVAL;
255                 }
256
257                 /* we only support VM on SI+ */
258                 if ((p->rdev->family >= CHIP_TAHITI) &&
259                     ((p->cs_flags & RADEON_CS_USE_VM) == 0)) {
260                         DRM_ERROR("VM required on SI+!\n");
261                         return -EINVAL;
262                 }
263
264                 if (radeon_cs_get_ring(p, ring, priority))
265                         return -EINVAL;
266         }
267
268         /* deal with non-vm */
269         if ((p->chunk_ib_idx != -1) &&
270             ((p->cs_flags & RADEON_CS_USE_VM) == 0) &&
271             (p->chunks[p->chunk_ib_idx].chunk_id == RADEON_CHUNK_ID_IB)) {
272                 if (p->chunks[p->chunk_ib_idx].length_dw > (16 * 1024)) {
273                         DRM_ERROR("cs IB too big: %d\n",
274                                   p->chunks[p->chunk_ib_idx].length_dw);
275                         return -EINVAL;
276                 }
277                 if ((p->rdev->flags & RADEON_IS_AGP)) {
278                         p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
279                         p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
280                         if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
281                             p->chunks[p->chunk_ib_idx].kpage[1] == NULL) {
282                                 kfree(p->chunks[i].kpage[0]);
283                                 kfree(p->chunks[i].kpage[1]);
284                                 return -ENOMEM;
285                         }
286                 }
287                 p->chunks[p->chunk_ib_idx].kpage_idx[0] = -1;
288                 p->chunks[p->chunk_ib_idx].kpage_idx[1] = -1;
289                 p->chunks[p->chunk_ib_idx].last_copied_page = -1;
290                 p->chunks[p->chunk_ib_idx].last_page_index =
291                         ((p->chunks[p->chunk_ib_idx].length_dw * 4) - 1) / PAGE_SIZE;
292         }
293
294         return 0;
295 }
296
297 /**
298  * cs_parser_fini() - clean parser states
299  * @parser:     parser structure holding parsing context.
300  * @error:      error number
301  *
302  * If error is set than unvalidate buffer, otherwise just free memory
303  * used by parsing context.
304  **/
305 static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
306 {
307         unsigned i;
308
309         if (!error)
310                 ttm_eu_fence_buffer_objects(&parser->validated,
311                                             parser->ib.fence);
312         else
313                 ttm_eu_backoff_reservation(&parser->validated);
314
315         if (parser->relocs != NULL) {
316                 for (i = 0; i < parser->nrelocs; i++) {
317                         if (parser->relocs[i].gobj)
318                                 drm_gem_object_unreference_unlocked(parser->relocs[i].gobj);
319                 }
320         }
321         kfree(parser->track);
322         kfree(parser->relocs);
323         kfree(parser->relocs_ptr);
324         for (i = 0; i < parser->nchunks; i++) {
325                 kfree(parser->chunks[i].kdata);
326                 if ((parser->rdev->flags & RADEON_IS_AGP)) {
327                         kfree(parser->chunks[i].kpage[0]);
328                         kfree(parser->chunks[i].kpage[1]);
329                 }
330         }
331         kfree(parser->chunks);
332         kfree(parser->chunks_array);
333         radeon_ib_free(parser->rdev, &parser->ib);
334         radeon_ib_free(parser->rdev, &parser->const_ib);
335 }
336
337 static int radeon_cs_ib_chunk(struct radeon_device *rdev,
338                               struct radeon_cs_parser *parser)
339 {
340         struct radeon_cs_chunk *ib_chunk;
341         int r;
342
343         if (parser->chunk_ib_idx == -1)
344                 return 0;
345
346         if (parser->cs_flags & RADEON_CS_USE_VM)
347                 return 0;
348
349         ib_chunk = &parser->chunks[parser->chunk_ib_idx];
350         /* Copy the packet into the IB, the parser will read from the
351          * input memory (cached) and write to the IB (which can be
352          * uncached).
353          */
354         r =  radeon_ib_get(rdev, parser->ring, &parser->ib,
355                            ib_chunk->length_dw * 4);
356         if (r) {
357                 DRM_ERROR("Failed to get ib !\n");
358                 return r;
359         }
360         parser->ib.length_dw = ib_chunk->length_dw;
361         r = radeon_cs_parse(rdev, parser->ring, parser);
362         if (r || parser->parser_error) {
363                 DRM_ERROR("Invalid command stream !\n");
364                 return r;
365         }
366         r = radeon_cs_finish_pages(parser);
367         if (r) {
368                 DRM_ERROR("Invalid command stream !\n");
369                 return r;
370         }
371         r = radeon_cs_sync_rings(parser);
372         if (r) {
373                 DRM_ERROR("Failed to synchronize rings !\n");
374         }
375         parser->ib.vm_id = 0;
376         r = radeon_ib_schedule(rdev, &parser->ib);
377         if (r) {
378                 DRM_ERROR("Failed to schedule IB !\n");
379         }
380         return 0;
381 }
382
383 static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser,
384                                    struct radeon_vm *vm)
385 {
386         struct radeon_bo_list *lobj;
387         struct radeon_bo *bo;
388         int r;
389
390         list_for_each_entry(lobj, &parser->validated, tv.head) {
391                 bo = lobj->bo;
392                 r = radeon_vm_bo_update_pte(parser->rdev, vm, bo, &bo->tbo.mem);
393                 if (r) {
394                         return r;
395                 }
396         }
397         return 0;
398 }
399
400 static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
401                                  struct radeon_cs_parser *parser)
402 {
403         struct radeon_cs_chunk *ib_chunk;
404         struct radeon_fpriv *fpriv = parser->filp->driver_priv;
405         struct radeon_vm *vm = &fpriv->vm;
406         int r;
407
408         if (parser->chunk_ib_idx == -1)
409                 return 0;
410
411         if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
412                 return 0;
413
414         if ((rdev->family >= CHIP_TAHITI) &&
415             (parser->chunk_const_ib_idx != -1)) {
416                 ib_chunk = &parser->chunks[parser->chunk_const_ib_idx];
417                 if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
418                         DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw);
419                         return -EINVAL;
420                 }
421                 r =  radeon_ib_get(rdev, parser->ring, &parser->const_ib,
422                                    ib_chunk->length_dw * 4);
423                 if (r) {
424                         DRM_ERROR("Failed to get const ib !\n");
425                         return r;
426                 }
427                 parser->const_ib.is_const_ib = true;
428                 parser->const_ib.length_dw = ib_chunk->length_dw;
429                 /* Copy the packet into the IB */
430                 if (DRM_COPY_FROM_USER(parser->const_ib.ptr, ib_chunk->user_ptr,
431                                        ib_chunk->length_dw * 4)) {
432                         return -EFAULT;
433                 }
434                 r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib);
435                 if (r) {
436                         return r;
437                 }
438         }
439
440         ib_chunk = &parser->chunks[parser->chunk_ib_idx];
441         if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
442                 DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw);
443                 return -EINVAL;
444         }
445         r =  radeon_ib_get(rdev, parser->ring, &parser->ib,
446                            ib_chunk->length_dw * 4);
447         if (r) {
448                 DRM_ERROR("Failed to get ib !\n");
449                 return r;
450         }
451         parser->ib.length_dw = ib_chunk->length_dw;
452         /* Copy the packet into the IB */
453         if (DRM_COPY_FROM_USER(parser->ib.ptr, ib_chunk->user_ptr,
454                                ib_chunk->length_dw * 4)) {
455                 return -EFAULT;
456         }
457         r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib);
458         if (r) {
459                 return r;
460         }
461
462         mutex_lock(&vm->mutex);
463         r = radeon_vm_bind(rdev, vm);
464         if (r) {
465                 goto out;
466         }
467         r = radeon_bo_vm_update_pte(parser, vm);
468         if (r) {
469                 goto out;
470         }
471         r = radeon_cs_sync_rings(parser);
472         if (r) {
473                 DRM_ERROR("Failed to synchronize rings !\n");
474         }
475
476         if ((rdev->family >= CHIP_TAHITI) &&
477             (parser->chunk_const_ib_idx != -1)) {
478                 parser->const_ib.vm_id = vm->id;
479                 /* ib pool is bind at 0 in virtual address space to gpu_addr is the
480                  * offset inside the pool bo
481                  */
482                 parser->const_ib.gpu_addr = parser->const_ib.sa_bo->soffset;
483                 r = radeon_ib_schedule(rdev, &parser->const_ib);
484                 if (r)
485                         goto out;
486         }
487
488         parser->ib.vm_id = vm->id;
489         /* ib pool is bind at 0 in virtual address space to gpu_addr is the
490          * offset inside the pool bo
491          */
492         parser->ib.gpu_addr = parser->ib.sa_bo->soffset;
493         parser->ib.is_const_ib = false;
494         r = radeon_ib_schedule(rdev, &parser->ib);
495 out:
496         if (!r) {
497                 if (vm->fence) {
498                         radeon_fence_unref(&vm->fence);
499                 }
500                 vm->fence = radeon_fence_ref(parser->ib.fence);
501         }
502         mutex_unlock(&fpriv->vm.mutex);
503         return r;
504 }
505
506 static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r)
507 {
508         if (r == -EDEADLK) {
509                 r = radeon_gpu_reset(rdev);
510                 if (!r)
511                         r = -EAGAIN;
512         }
513         return r;
514 }
515
516 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
517 {
518         struct radeon_device *rdev = dev->dev_private;
519         struct radeon_cs_parser parser;
520         int r;
521
522         radeon_mutex_lock(&rdev->cs_mutex);
523         if (!rdev->accel_working) {
524                 radeon_mutex_unlock(&rdev->cs_mutex);
525                 return -EBUSY;
526         }
527         /* initialize parser */
528         memset(&parser, 0, sizeof(struct radeon_cs_parser));
529         parser.filp = filp;
530         parser.rdev = rdev;
531         parser.dev = rdev->dev;
532         parser.family = rdev->family;
533         r = radeon_cs_parser_init(&parser, data);
534         if (r) {
535                 DRM_ERROR("Failed to initialize parser !\n");
536                 radeon_cs_parser_fini(&parser, r);
537                 r = radeon_cs_handle_lockup(rdev, r);
538                 radeon_mutex_unlock(&rdev->cs_mutex);
539                 return r;
540         }
541         r = radeon_cs_parser_relocs(&parser);
542         if (r) {
543                 if (r != -ERESTARTSYS)
544                         DRM_ERROR("Failed to parse relocation %d!\n", r);
545                 radeon_cs_parser_fini(&parser, r);
546                 r = radeon_cs_handle_lockup(rdev, r);
547                 radeon_mutex_unlock(&rdev->cs_mutex);
548                 return r;
549         }
550         r = radeon_cs_ib_chunk(rdev, &parser);
551         if (r) {
552                 goto out;
553         }
554         r = radeon_cs_ib_vm_chunk(rdev, &parser);
555         if (r) {
556                 goto out;
557         }
558 out:
559         radeon_cs_parser_fini(&parser, r);
560         r = radeon_cs_handle_lockup(rdev, r);
561         radeon_mutex_unlock(&rdev->cs_mutex);
562         return r;
563 }
564
565 int radeon_cs_finish_pages(struct radeon_cs_parser *p)
566 {
567         struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
568         int i;
569         int size = PAGE_SIZE;
570
571         for (i = ibc->last_copied_page + 1; i <= ibc->last_page_index; i++) {
572                 if (i == ibc->last_page_index) {
573                         size = (ibc->length_dw * 4) % PAGE_SIZE;
574                         if (size == 0)
575                                 size = PAGE_SIZE;
576                 }
577                 
578                 if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
579                                        ibc->user_ptr + (i * PAGE_SIZE),
580                                        size))
581                         return -EFAULT;
582         }
583         return 0;
584 }
585
586 static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
587 {
588         int new_page;
589         struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
590         int i;
591         int size = PAGE_SIZE;
592         bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true;
593
594         for (i = ibc->last_copied_page + 1; i < pg_idx; i++) {
595                 if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
596                                        ibc->user_ptr + (i * PAGE_SIZE),
597                                        PAGE_SIZE)) {
598                         p->parser_error = -EFAULT;
599                         return 0;
600                 }
601         }
602
603         if (pg_idx == ibc->last_page_index) {
604                 size = (ibc->length_dw * 4) % PAGE_SIZE;
605                 if (size == 0)
606                         size = PAGE_SIZE;
607         }
608
609         new_page = ibc->kpage_idx[0] < ibc->kpage_idx[1] ? 0 : 1;
610         if (copy1)
611                 ibc->kpage[new_page] = p->ib.ptr + (pg_idx * (PAGE_SIZE / 4));
612
613         if (DRM_COPY_FROM_USER(ibc->kpage[new_page],
614                                ibc->user_ptr + (pg_idx * PAGE_SIZE),
615                                size)) {
616                 p->parser_error = -EFAULT;
617                 return 0;
618         }
619
620         /* copy to IB for non single case */
621         if (!copy1)
622                 memcpy((void *)(p->ib.ptr+(pg_idx*(PAGE_SIZE/4))), ibc->kpage[new_page], size);
623
624         ibc->last_copied_page = pg_idx;
625         ibc->kpage_idx[new_page] = pg_idx;
626
627         return new_page;
628 }
629
630 u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)
631 {
632         struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
633         u32 pg_idx, pg_offset;
634         u32 idx_value = 0;
635         int new_page;
636
637         pg_idx = (idx * 4) / PAGE_SIZE;
638         pg_offset = (idx * 4) % PAGE_SIZE;
639
640         if (ibc->kpage_idx[0] == pg_idx)
641                 return ibc->kpage[0][pg_offset/4];
642         if (ibc->kpage_idx[1] == pg_idx)
643                 return ibc->kpage[1][pg_offset/4];
644
645         new_page = radeon_cs_update_pages(p, pg_idx);
646         if (new_page < 0) {
647                 p->parser_error = new_page;
648                 return 0;
649         }
650
651         idx_value = ibc->kpage[new_page][pg_offset/4];
652         return idx_value;
653 }