diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_gart.c | 147 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_gem.c | 47 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_object.c | 2 |
4 files changed, 154 insertions, 72 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8cca1d2f0510..4d67f0f5a5a3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -292,17 +292,20 @@ struct radeon_mman { | |||
292 | 292 | ||
293 | /* bo virtual address in a specific vm */ | 293 | /* bo virtual address in a specific vm */ |
294 | struct radeon_bo_va { | 294 | struct radeon_bo_va { |
295 | /* bo list is protected by bo being reserved */ | 295 | /* protected by bo being reserved */ |
296 | struct list_head bo_list; | 296 | struct list_head bo_list; |
297 | /* vm list is protected by vm mutex */ | ||
298 | struct list_head vm_list; | ||
299 | /* constant after initialization */ | ||
300 | struct radeon_vm *vm; | ||
301 | struct radeon_bo *bo; | ||
302 | uint64_t soffset; | 297 | uint64_t soffset; |
303 | uint64_t eoffset; | 298 | uint64_t eoffset; |
304 | uint32_t flags; | 299 | uint32_t flags; |
305 | bool valid; | 300 | bool valid; |
301 | unsigned ref_count; | ||
302 | |||
303 | /* protected by vm mutex */ | ||
304 | struct list_head vm_list; | ||
305 | |||
306 | /* constant after initialization */ | ||
307 | struct radeon_vm *vm; | ||
308 | struct radeon_bo *bo; | ||
306 | }; | 309 | }; |
307 | 310 | ||
308 | struct radeon_bo { | 311 | struct radeon_bo { |
@@ -1848,14 +1851,15 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, | |||
1848 | struct radeon_bo *bo); | 1851 | struct radeon_bo *bo); |
1849 | struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, | 1852 | struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, |
1850 | struct radeon_bo *bo); | 1853 | struct radeon_bo *bo); |
1851 | int radeon_vm_bo_add(struct radeon_device *rdev, | 1854 | struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, |
1852 | struct radeon_vm *vm, | 1855 | struct radeon_vm *vm, |
1853 | struct radeon_bo *bo, | 1856 | struct radeon_bo *bo); |
1854 | uint64_t offset, | 1857 | int radeon_vm_bo_set_addr(struct radeon_device *rdev, |
1855 | uint32_t flags); | 1858 | struct radeon_bo_va *bo_va, |
1859 | uint64_t offset, | ||
1860 | uint32_t flags); | ||
1856 | int radeon_vm_bo_rmv(struct radeon_device *rdev, | 1861 | int radeon_vm_bo_rmv(struct radeon_device *rdev, |
1857 | struct radeon_vm *vm, | 1862 | struct radeon_bo_va *bo_va); |
1858 | struct radeon_bo *bo); | ||
1859 | 1863 | ||
1860 | /* audio */ | 1864 | /* audio */ |
1861 | void r600_audio_update_hdmi(struct work_struct *work); | 1865 | void r600_audio_update_hdmi(struct work_struct *work); |
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2c594910064d..2f28ff34c085 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c | |||
@@ -693,51 +693,83 @@ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, | |||
693 | * @rdev: radeon_device pointer | 693 | * @rdev: radeon_device pointer |
694 | * @vm: requested vm | 694 | * @vm: requested vm |
695 | * @bo: radeon buffer object | 695 | * @bo: radeon buffer object |
696 | * @offset: requested offset of the buffer in the VM address space | ||
697 | * @flags: attributes of pages (read/write/valid/etc.) | ||
698 | * | 696 | * |
699 | * Add @bo into the requested vm (cayman+). | 697 | * Add @bo into the requested vm (cayman+). |
700 | * Add @bo to the list of bos associated with the vm and validate | 698 | * Add @bo to the list of bos associated with the vm |
701 | * the offset requested within the vm address space. | 699 | * Returns newly added bo_va or NULL for failure |
702 | * Returns 0 for success, error for failure. | ||
703 | * | 700 | * |
704 | * Object has to be reserved! | 701 | * Object has to be reserved! |
705 | */ | 702 | */ |
706 | int radeon_vm_bo_add(struct radeon_device *rdev, | 703 | struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, |
707 | struct radeon_vm *vm, | 704 | struct radeon_vm *vm, |
708 | struct radeon_bo *bo, | 705 | struct radeon_bo *bo) |
709 | uint64_t offset, | ||
710 | uint32_t flags) | ||
711 | { | 706 | { |
712 | struct radeon_bo_va *bo_va, *tmp; | 707 | struct radeon_bo_va *bo_va; |
713 | struct list_head *head; | ||
714 | uint64_t size = radeon_bo_size(bo), last_offset = 0; | ||
715 | unsigned last_pfn; | ||
716 | 708 | ||
717 | bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); | 709 | bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); |
718 | if (bo_va == NULL) { | 710 | if (bo_va == NULL) { |
719 | return -ENOMEM; | 711 | return NULL; |
720 | } | 712 | } |
721 | bo_va->vm = vm; | 713 | bo_va->vm = vm; |
722 | bo_va->bo = bo; | 714 | bo_va->bo = bo; |
723 | bo_va->soffset = offset; | 715 | bo_va->soffset = 0; |
724 | bo_va->eoffset = offset + size; | 716 | bo_va->eoffset = 0; |
725 | bo_va->flags = flags; | 717 | bo_va->flags = 0; |
726 | bo_va->valid = false; | 718 | bo_va->valid = false; |
719 | bo_va->ref_count = 1; | ||
727 | INIT_LIST_HEAD(&bo_va->bo_list); | 720 | INIT_LIST_HEAD(&bo_va->bo_list); |
728 | INIT_LIST_HEAD(&bo_va->vm_list); | 721 | INIT_LIST_HEAD(&bo_va->vm_list); |
729 | /* make sure object fit at this offset */ | ||
730 | if (bo_va->soffset >= bo_va->eoffset) { | ||
731 | kfree(bo_va); | ||
732 | return -EINVAL; | ||
733 | } | ||
734 | 722 | ||
735 | last_pfn = bo_va->eoffset / RADEON_GPU_PAGE_SIZE; | 723 | mutex_lock(&vm->mutex); |
736 | if (last_pfn > rdev->vm_manager.max_pfn) { | 724 | list_add(&bo_va->vm_list, &vm->va); |
737 | kfree(bo_va); | 725 | list_add_tail(&bo_va->bo_list, &bo->va); |
738 | dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", | 726 | mutex_unlock(&vm->mutex); |
739 | last_pfn, rdev->vm_manager.max_pfn); | 727 | |
740 | return -EINVAL; | 728 | return bo_va; |
729 | } | ||
730 | |||
731 | /** | ||
732 | * radeon_vm_bo_set_addr - set bos virtual address inside a vm | ||
733 | * | ||
734 | * @rdev: radeon_device pointer | ||
735 | * @bo_va: bo_va to store the address | ||
736 | * @soffset: requested offset of the buffer in the VM address space | ||
737 | * @flags: attributes of pages (read/write/valid/etc.) | ||
738 | * | ||
739 | * Set offset of @bo_va (cayman+). | ||
740 | * Validate and set the offset requested within the vm address space. | ||
741 | * Returns 0 for success, error for failure. | ||
742 | * | ||
743 | * Object has to be reserved! | ||
744 | */ | ||
745 | int radeon_vm_bo_set_addr(struct radeon_device *rdev, | ||
746 | struct radeon_bo_va *bo_va, | ||
747 | uint64_t soffset, | ||
748 | uint32_t flags) | ||
749 | { | ||
750 | uint64_t size = radeon_bo_size(bo_va->bo); | ||
751 | uint64_t eoffset, last_offset = 0; | ||
752 | struct radeon_vm *vm = bo_va->vm; | ||
753 | struct radeon_bo_va *tmp; | ||
754 | struct list_head *head; | ||
755 | unsigned last_pfn; | ||
756 | |||
757 | if (soffset) { | ||
758 | /* make sure object fit at this offset */ | ||
759 | eoffset = soffset + size; | ||
760 | if (soffset >= eoffset) { | ||
761 | return -EINVAL; | ||
762 | } | ||
763 | |||
764 | last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; | ||
765 | if (last_pfn > rdev->vm_manager.max_pfn) { | ||
766 | dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", | ||
767 | last_pfn, rdev->vm_manager.max_pfn); | ||
768 | return -EINVAL; | ||
769 | } | ||
770 | |||
771 | } else { | ||
772 | eoffset = last_pfn = 0; | ||
741 | } | 773 | } |
742 | 774 | ||
743 | mutex_lock(&vm->mutex); | 775 | mutex_lock(&vm->mutex); |
@@ -758,24 +790,33 @@ int radeon_vm_bo_add(struct radeon_device *rdev, | |||
758 | head = &vm->va; | 790 | head = &vm->va; |
759 | last_offset = 0; | 791 | last_offset = 0; |
760 | list_for_each_entry(tmp, &vm->va, vm_list) { | 792 | list_for_each_entry(tmp, &vm->va, vm_list) { |
761 | if (bo_va->soffset >= last_offset && bo_va->eoffset <= tmp->soffset) { | 793 | if (bo_va == tmp) { |
794 | /* skip over currently modified bo */ | ||
795 | continue; | ||
796 | } | ||
797 | |||
798 | if (soffset >= last_offset && eoffset <= tmp->soffset) { | ||
762 | /* bo can be added before this one */ | 799 | /* bo can be added before this one */ |
763 | break; | 800 | break; |
764 | } | 801 | } |
765 | if (bo_va->eoffset > tmp->soffset && bo_va->soffset < tmp->eoffset) { | 802 | if (eoffset > tmp->soffset && soffset < tmp->eoffset) { |
766 | /* bo and tmp overlap, invalid offset */ | 803 | /* bo and tmp overlap, invalid offset */ |
767 | dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", | 804 | dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", |
768 | bo, (unsigned)bo_va->soffset, tmp->bo, | 805 | bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, |
769 | (unsigned)tmp->soffset, (unsigned)tmp->eoffset); | 806 | (unsigned)tmp->soffset, (unsigned)tmp->eoffset); |
770 | kfree(bo_va); | ||
771 | mutex_unlock(&vm->mutex); | 807 | mutex_unlock(&vm->mutex); |
772 | return -EINVAL; | 808 | return -EINVAL; |
773 | } | 809 | } |
774 | last_offset = tmp->eoffset; | 810 | last_offset = tmp->eoffset; |
775 | head = &tmp->vm_list; | 811 | head = &tmp->vm_list; |
776 | } | 812 | } |
777 | list_add(&bo_va->vm_list, head); | 813 | |
778 | list_add_tail(&bo_va->bo_list, &bo->va); | 814 | bo_va->soffset = soffset; |
815 | bo_va->eoffset = eoffset; | ||
816 | bo_va->flags = flags; | ||
817 | bo_va->valid = false; | ||
818 | list_move(&bo_va->vm_list, head); | ||
819 | |||
779 | mutex_unlock(&vm->mutex); | 820 | mutex_unlock(&vm->mutex); |
780 | return 0; | 821 | return 0; |
781 | } | 822 | } |
@@ -855,6 +896,12 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, | |||
855 | return -EINVAL; | 896 | return -EINVAL; |
856 | } | 897 | } |
857 | 898 | ||
899 | if (!bo_va->soffset) { | ||
900 | dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", | ||
901 | bo, vm); | ||
902 | return -EINVAL; | ||
903 | } | ||
904 | |||
858 | if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) | 905 | if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) |
859 | return 0; | 906 | return 0; |
860 | 907 | ||
@@ -921,33 +968,26 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, | |||
921 | * radeon_vm_bo_rmv - remove a bo to a specific vm | 968 | * radeon_vm_bo_rmv - remove a bo to a specific vm |
922 | * | 969 | * |
923 | * @rdev: radeon_device pointer | 970 | * @rdev: radeon_device pointer |
924 | * @vm: requested vm | 971 | * @bo_va: requested bo_va |
925 | * @bo: radeon buffer object | ||
926 | * | 972 | * |
927 | * Remove @bo from the requested vm (cayman+). | 973 | * Remove @bo_va->bo from the requested vm (cayman+). |
928 | * Remove @bo from the list of bos associated with the vm and | 974 | * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and |
929 | * remove the ptes for @bo in the page table. | 975 | * remove the ptes for @bo_va in the page table. |
930 | * Returns 0 for success. | 976 | * Returns 0 for success. |
931 | * | 977 | * |
932 | * Object have to be reserved! | 978 | * Object have to be reserved! |
933 | */ | 979 | */ |
934 | int radeon_vm_bo_rmv(struct radeon_device *rdev, | 980 | int radeon_vm_bo_rmv(struct radeon_device *rdev, |
935 | struct radeon_vm *vm, | 981 | struct radeon_bo_va *bo_va) |
936 | struct radeon_bo *bo) | ||
937 | { | 982 | { |
938 | struct radeon_bo_va *bo_va; | ||
939 | int r; | 983 | int r; |
940 | 984 | ||
941 | bo_va = radeon_vm_bo_find(vm, bo); | ||
942 | if (bo_va == NULL) | ||
943 | return 0; | ||
944 | |||
945 | mutex_lock(&rdev->vm_manager.lock); | 985 | mutex_lock(&rdev->vm_manager.lock); |
946 | mutex_lock(&vm->mutex); | 986 | mutex_lock(&bo_va->vm->mutex); |
947 | r = radeon_vm_bo_update_pte(rdev, vm, bo, NULL); | 987 | r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); |
948 | mutex_unlock(&rdev->vm_manager.lock); | 988 | mutex_unlock(&rdev->vm_manager.lock); |
949 | list_del(&bo_va->vm_list); | 989 | list_del(&bo_va->vm_list); |
950 | mutex_unlock(&vm->mutex); | 990 | mutex_unlock(&bo_va->vm->mutex); |
951 | list_del(&bo_va->bo_list); | 991 | list_del(&bo_va->bo_list); |
952 | 992 | ||
953 | kfree(bo_va); | 993 | kfree(bo_va); |
@@ -987,6 +1027,7 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, | |||
987 | */ | 1027 | */ |
988 | int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) | 1028 | int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) |
989 | { | 1029 | { |
1030 | struct radeon_bo_va *bo_va; | ||
990 | int r; | 1031 | int r; |
991 | 1032 | ||
992 | vm->id = 0; | 1033 | vm->id = 0; |
@@ -1006,8 +1047,10 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) | |||
1006 | /* map the ib pool buffer at 0 in virtual address space, set | 1047 | /* map the ib pool buffer at 0 in virtual address space, set |
1007 | * read only | 1048 | * read only |
1008 | */ | 1049 | */ |
1009 | r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, RADEON_VA_IB_OFFSET, | 1050 | bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); |
1010 | RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); | 1051 | r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, |
1052 | RADEON_VM_PAGE_READABLE | | ||
1053 | RADEON_VM_PAGE_SNOOPED); | ||
1011 | return r; | 1054 | return r; |
1012 | } | 1055 | } |
1013 | 1056 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index cfad667ce785..6579befa5101 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c | |||
@@ -124,6 +124,30 @@ void radeon_gem_fini(struct radeon_device *rdev) | |||
124 | */ | 124 | */ |
125 | int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) | 125 | int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) |
126 | { | 126 | { |
127 | struct radeon_bo *rbo = gem_to_radeon_bo(obj); | ||
128 | struct radeon_device *rdev = rbo->rdev; | ||
129 | struct radeon_fpriv *fpriv = file_priv->driver_priv; | ||
130 | struct radeon_vm *vm = &fpriv->vm; | ||
131 | struct radeon_bo_va *bo_va; | ||
132 | int r; | ||
133 | |||
134 | if (rdev->family < CHIP_CAYMAN) { | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | r = radeon_bo_reserve(rbo, false); | ||
139 | if (r) { | ||
140 | return r; | ||
141 | } | ||
142 | |||
143 | bo_va = radeon_vm_bo_find(vm, rbo); | ||
144 | if (!bo_va) { | ||
145 | bo_va = radeon_vm_bo_add(rdev, vm, rbo); | ||
146 | } else { | ||
147 | ++bo_va->ref_count; | ||
148 | } | ||
149 | radeon_bo_unreserve(rbo); | ||
150 | |||
127 | return 0; | 151 | return 0; |
128 | } | 152 | } |
129 | 153 | ||
@@ -134,6 +158,7 @@ void radeon_gem_object_close(struct drm_gem_object *obj, | |||
134 | struct radeon_device *rdev = rbo->rdev; | 158 | struct radeon_device *rdev = rbo->rdev; |
135 | struct radeon_fpriv *fpriv = file_priv->driver_priv; | 159 | struct radeon_fpriv *fpriv = file_priv->driver_priv; |
136 | struct radeon_vm *vm = &fpriv->vm; | 160 | struct radeon_vm *vm = &fpriv->vm; |
161 | struct radeon_bo_va *bo_va; | ||
137 | int r; | 162 | int r; |
138 | 163 | ||
139 | if (rdev->family < CHIP_CAYMAN) { | 164 | if (rdev->family < CHIP_CAYMAN) { |
@@ -146,7 +171,12 @@ void radeon_gem_object_close(struct drm_gem_object *obj, | |||
146 | "we fail to reserve bo (%d)\n", r); | 171 | "we fail to reserve bo (%d)\n", r); |
147 | return; | 172 | return; |
148 | } | 173 | } |
149 | radeon_vm_bo_rmv(rdev, vm, rbo); | 174 | bo_va = radeon_vm_bo_find(vm, rbo); |
175 | if (bo_va) { | ||
176 | if (--bo_va->ref_count == 0) { | ||
177 | radeon_vm_bo_rmv(rdev, bo_va); | ||
178 | } | ||
179 | } | ||
150 | radeon_bo_unreserve(rbo); | 180 | radeon_bo_unreserve(rbo); |
151 | } | 181 | } |
152 | 182 | ||
@@ -462,19 +492,24 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, | |||
462 | drm_gem_object_unreference_unlocked(gobj); | 492 | drm_gem_object_unreference_unlocked(gobj); |
463 | return r; | 493 | return r; |
464 | } | 494 | } |
495 | bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); | ||
496 | if (!bo_va) { | ||
497 | args->operation = RADEON_VA_RESULT_ERROR; | ||
498 | drm_gem_object_unreference_unlocked(gobj); | ||
499 | return -ENOENT; | ||
500 | } | ||
501 | |||
465 | switch (args->operation) { | 502 | switch (args->operation) { |
466 | case RADEON_VA_MAP: | 503 | case RADEON_VA_MAP: |
467 | bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); | 504 | if (bo_va->soffset) { |
468 | if (bo_va) { | ||
469 | args->operation = RADEON_VA_RESULT_VA_EXIST; | 505 | args->operation = RADEON_VA_RESULT_VA_EXIST; |
470 | args->offset = bo_va->soffset; | 506 | args->offset = bo_va->soffset; |
471 | goto out; | 507 | goto out; |
472 | } | 508 | } |
473 | r = radeon_vm_bo_add(rdev, &fpriv->vm, rbo, | 509 | r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); |
474 | args->offset, args->flags); | ||
475 | break; | 510 | break; |
476 | case RADEON_VA_UNMAP: | 511 | case RADEON_VA_UNMAP: |
477 | r = radeon_vm_bo_rmv(rdev, &fpriv->vm, rbo); | 512 | r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0); |
478 | break; | 513 | break; |
479 | default: | 514 | default: |
480 | break; | 515 | break; |
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8d23b7e2ae3d..a236795dc69a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -52,7 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo) | |||
52 | 52 | ||
53 | list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) { | 53 | list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) { |
54 | /* remove from all vm address space */ | 54 | /* remove from all vm address space */ |
55 | radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo); | 55 | radeon_vm_bo_rmv(bo->rdev, bo_va); |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||