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