diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-08-25 21:32:01 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-09-24 02:18:16 -0400 |
commit | f1ab0cc9bacdd33a37603a80852ee0579f809ce7 (patch) | |
tree | 9166ce7dffa11e30ddbe2fb9abfc25879db98747 /drivers/gpu/drm/nouveau | |
parent | 4295f188e8297660b498e021caee430a40558d8b (diff) |
drm/nv50: add new accelerated bo move funtion
Hopefully this one will be better able to cope with moving tiled buffers
around without getting them all scrambled as a result.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 193 |
1 files changed, 145 insertions, 48 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index f6f44779d82f..a2908a91495c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -478,10 +478,12 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, | |||
478 | } | 478 | } |
479 | 479 | ||
480 | static inline uint32_t | 480 | static inline uint32_t |
481 | nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, | 481 | nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, |
482 | struct ttm_mem_reg *mem) | 482 | struct nouveau_channel *chan, struct ttm_mem_reg *mem) |
483 | { | 483 | { |
484 | if (chan == nouveau_bdev(nvbo->bo.bdev)->channel) { | 484 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
485 | |||
486 | if (nvbo->no_vm) { | ||
485 | if (mem->mem_type == TTM_PL_TT) | 487 | if (mem->mem_type == TTM_PL_TT) |
486 | return NvDmaGART; | 488 | return NvDmaGART; |
487 | return NvDmaVRAM; | 489 | return NvDmaVRAM; |
@@ -493,86 +495,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, | |||
493 | } | 495 | } |
494 | 496 | ||
495 | static int | 497 | static int |
496 | nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | 498 | nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
497 | bool no_wait_reserve, bool no_wait_gpu, | 499 | struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) |
498 | struct ttm_mem_reg *new_mem) | ||
499 | { | 500 | { |
500 | struct nouveau_bo *nvbo = nouveau_bo(bo); | ||
501 | struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); | 501 | struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); |
502 | struct ttm_mem_reg *old_mem = &bo->mem; | 502 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
503 | struct nouveau_channel *chan; | 503 | u64 length = (new_mem->num_pages << PAGE_SHIFT); |
504 | uint64_t src_offset, dst_offset; | 504 | u64 src_offset, dst_offset; |
505 | uint32_t page_count; | ||
506 | int ret; | 505 | int ret; |
507 | 506 | ||
508 | chan = nvbo->channel; | ||
509 | if (!chan || nvbo->tile_flags || nvbo->no_vm) | ||
510 | chan = dev_priv->channel; | ||
511 | |||
512 | src_offset = old_mem->mm_node->start << PAGE_SHIFT; | 507 | src_offset = old_mem->mm_node->start << PAGE_SHIFT; |
513 | dst_offset = new_mem->mm_node->start << PAGE_SHIFT; | 508 | dst_offset = new_mem->mm_node->start << PAGE_SHIFT; |
514 | if (chan != dev_priv->channel) { | 509 | if (!nvbo->no_vm) { |
515 | if (old_mem->mem_type == TTM_PL_TT) | 510 | if (old_mem->mem_type == TTM_PL_VRAM) |
516 | src_offset += dev_priv->vm_gart_base; | ||
517 | else | ||
518 | src_offset += dev_priv->vm_vram_base; | 511 | src_offset += dev_priv->vm_vram_base; |
519 | |||
520 | if (new_mem->mem_type == TTM_PL_TT) | ||
521 | dst_offset += dev_priv->vm_gart_base; | ||
522 | else | 512 | else |
513 | src_offset += dev_priv->vm_gart_base; | ||
514 | |||
515 | if (new_mem->mem_type == TTM_PL_VRAM) | ||
523 | dst_offset += dev_priv->vm_vram_base; | 516 | dst_offset += dev_priv->vm_vram_base; |
517 | else | ||
518 | dst_offset += dev_priv->vm_gart_base; | ||
524 | } | 519 | } |
525 | 520 | ||
526 | ret = RING_SPACE(chan, 3); | 521 | ret = RING_SPACE(chan, 3); |
527 | if (ret) | 522 | if (ret) |
528 | return ret; | 523 | return ret; |
529 | BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2); | ||
530 | OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, old_mem)); | ||
531 | OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, new_mem)); | ||
532 | 524 | ||
533 | if (dev_priv->card_type >= NV_50) { | 525 | BEGIN_RING(chan, NvSubM2MF, 0x0184, 2); |
534 | ret = RING_SPACE(chan, 4); | 526 | OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); |
527 | OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); | ||
528 | |||
529 | while (length) { | ||
530 | u32 amount, stride, height; | ||
531 | |||
532 | amount = min(length, (u64)(16 * 1024 * 1024)); | ||
533 | stride = 64 * 4; | ||
534 | height = amount / stride; | ||
535 | |||
536 | if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { | ||
537 | ret = RING_SPACE(chan, 8); | ||
538 | if (ret) | ||
539 | return ret; | ||
540 | |||
541 | BEGIN_RING(chan, NvSubM2MF, 0x0200, 7); | ||
542 | OUT_RING (chan, 0); | ||
543 | OUT_RING (chan, 0x20); | ||
544 | OUT_RING (chan, stride); | ||
545 | OUT_RING (chan, height); | ||
546 | OUT_RING (chan, 1); | ||
547 | OUT_RING (chan, 0); | ||
548 | OUT_RING (chan, 0); | ||
549 | } else { | ||
550 | ret = RING_SPACE(chan, 2); | ||
551 | if (ret) | ||
552 | return ret; | ||
553 | |||
554 | BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); | ||
555 | OUT_RING (chan, 1); | ||
556 | } | ||
557 | if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { | ||
558 | ret = RING_SPACE(chan, 8); | ||
559 | if (ret) | ||
560 | return ret; | ||
561 | |||
562 | BEGIN_RING(chan, NvSubM2MF, 0x021c, 7); | ||
563 | OUT_RING (chan, 0); | ||
564 | OUT_RING (chan, 0x20); | ||
565 | OUT_RING (chan, stride); | ||
566 | OUT_RING (chan, height); | ||
567 | OUT_RING (chan, 1); | ||
568 | OUT_RING (chan, 0); | ||
569 | OUT_RING (chan, 0); | ||
570 | } else { | ||
571 | ret = RING_SPACE(chan, 2); | ||
572 | if (ret) | ||
573 | return ret; | ||
574 | |||
575 | BEGIN_RING(chan, NvSubM2MF, 0x021c, 1); | ||
576 | OUT_RING (chan, 1); | ||
577 | } | ||
578 | |||
579 | ret = RING_SPACE(chan, 14); | ||
535 | if (ret) | 580 | if (ret) |
536 | return ret; | 581 | return ret; |
537 | BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); | 582 | |
538 | OUT_RING(chan, 1); | 583 | BEGIN_RING(chan, NvSubM2MF, 0x0238, 2); |
539 | BEGIN_RING(chan, NvSubM2MF, 0x021c, 1); | 584 | OUT_RING (chan, upper_32_bits(src_offset)); |
540 | OUT_RING(chan, 1); | 585 | OUT_RING (chan, upper_32_bits(dst_offset)); |
586 | BEGIN_RING(chan, NvSubM2MF, 0x030c, 8); | ||
587 | OUT_RING (chan, lower_32_bits(src_offset)); | ||
588 | OUT_RING (chan, lower_32_bits(dst_offset)); | ||
589 | OUT_RING (chan, stride); | ||
590 | OUT_RING (chan, stride); | ||
591 | OUT_RING (chan, stride); | ||
592 | OUT_RING (chan, height); | ||
593 | OUT_RING (chan, 0x00000101); | ||
594 | OUT_RING (chan, 0x00000000); | ||
595 | BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); | ||
596 | OUT_RING (chan, 0); | ||
597 | |||
598 | length -= amount; | ||
599 | src_offset += amount; | ||
600 | dst_offset += amount; | ||
541 | } | 601 | } |
542 | 602 | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int | ||
607 | nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | ||
608 | struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) | ||
609 | { | ||
610 | u32 src_offset = old_mem->mm_node->start << PAGE_SHIFT; | ||
611 | u32 dst_offset = new_mem->mm_node->start << PAGE_SHIFT; | ||
612 | u32 page_count = new_mem->num_pages; | ||
613 | int ret; | ||
614 | |||
615 | ret = RING_SPACE(chan, 3); | ||
616 | if (ret) | ||
617 | return ret; | ||
618 | |||
619 | BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2); | ||
620 | OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); | ||
621 | OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); | ||
622 | |||
543 | page_count = new_mem->num_pages; | 623 | page_count = new_mem->num_pages; |
544 | while (page_count) { | 624 | while (page_count) { |
545 | int line_count = (page_count > 2047) ? 2047 : page_count; | 625 | int line_count = (page_count > 2047) ? 2047 : page_count; |
546 | 626 | ||
547 | if (dev_priv->card_type >= NV_50) { | ||
548 | ret = RING_SPACE(chan, 3); | ||
549 | if (ret) | ||
550 | return ret; | ||
551 | BEGIN_RING(chan, NvSubM2MF, 0x0238, 2); | ||
552 | OUT_RING(chan, upper_32_bits(src_offset)); | ||
553 | OUT_RING(chan, upper_32_bits(dst_offset)); | ||
554 | } | ||
555 | ret = RING_SPACE(chan, 11); | 627 | ret = RING_SPACE(chan, 11); |
556 | if (ret) | 628 | if (ret) |
557 | return ret; | 629 | return ret; |
630 | |||
558 | BEGIN_RING(chan, NvSubM2MF, | 631 | BEGIN_RING(chan, NvSubM2MF, |
559 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); | 632 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); |
560 | OUT_RING(chan, lower_32_bits(src_offset)); | 633 | OUT_RING (chan, src_offset); |
561 | OUT_RING(chan, lower_32_bits(dst_offset)); | 634 | OUT_RING (chan, dst_offset); |
562 | OUT_RING(chan, PAGE_SIZE); /* src_pitch */ | 635 | OUT_RING (chan, PAGE_SIZE); /* src_pitch */ |
563 | OUT_RING(chan, PAGE_SIZE); /* dst_pitch */ | 636 | OUT_RING (chan, PAGE_SIZE); /* dst_pitch */ |
564 | OUT_RING(chan, PAGE_SIZE); /* line_length */ | 637 | OUT_RING (chan, PAGE_SIZE); /* line_length */ |
565 | OUT_RING(chan, line_count); | 638 | OUT_RING (chan, line_count); |
566 | OUT_RING(chan, (1<<8)|(1<<0)); | 639 | OUT_RING (chan, 0x00000101); |
567 | OUT_RING(chan, 0); | 640 | OUT_RING (chan, 0x00000000); |
568 | BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); | 641 | BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1); |
569 | OUT_RING(chan, 0); | 642 | OUT_RING (chan, 0); |
570 | 643 | ||
571 | page_count -= line_count; | 644 | page_count -= line_count; |
572 | src_offset += (PAGE_SIZE * line_count); | 645 | src_offset += (PAGE_SIZE * line_count); |
573 | dst_offset += (PAGE_SIZE * line_count); | 646 | dst_offset += (PAGE_SIZE * line_count); |
574 | } | 647 | } |
575 | 648 | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int | ||
653 | nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | ||
654 | bool no_wait_reserve, bool no_wait_gpu, | ||
655 | struct ttm_mem_reg *new_mem) | ||
656 | { | ||
657 | struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); | ||
658 | struct nouveau_bo *nvbo = nouveau_bo(bo); | ||
659 | struct nouveau_channel *chan; | ||
660 | int ret; | ||
661 | |||
662 | chan = nvbo->channel; | ||
663 | if (!chan || nvbo->no_vm) | ||
664 | chan = dev_priv->channel; | ||
665 | |||
666 | if (dev_priv->card_type < NV_50) | ||
667 | ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); | ||
668 | else | ||
669 | ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem); | ||
670 | if (ret) | ||
671 | return ret; | ||
672 | |||
576 | return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); | 673 | return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); |
577 | } | 674 | } |
578 | 675 | ||