diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 170 |
1 files changed, 65 insertions, 105 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b44c09ab8928..1177ff577914 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -635,9 +635,7 @@ fast_user_write(struct io_mapping *mapping, | |||
635 | unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset, | 635 | unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset, |
636 | user_data, length); | 636 | user_data, length); |
637 | io_mapping_unmap_atomic(vaddr_atomic, KM_USER0); | 637 | io_mapping_unmap_atomic(vaddr_atomic, KM_USER0); |
638 | if (unwritten) | 638 | return unwritten; |
639 | return -EFAULT; | ||
640 | return 0; | ||
641 | } | 639 | } |
642 | 640 | ||
643 | /* Here's the write path which can sleep for | 641 | /* Here's the write path which can sleep for |
@@ -670,14 +668,14 @@ fast_shmem_write(struct page **pages, | |||
670 | char __user *data, | 668 | char __user *data, |
671 | int length) | 669 | int length) |
672 | { | 670 | { |
673 | int unwritten; | ||
674 | char *vaddr; | 671 | char *vaddr; |
672 | int ret; | ||
675 | 673 | ||
676 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); | 674 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); |
677 | unwritten = __copy_from_user_inatomic(vaddr + page_offset, data, length); | 675 | ret = __copy_from_user_inatomic(vaddr + page_offset, data, length); |
678 | kunmap_atomic(vaddr, KM_USER0); | 676 | kunmap_atomic(vaddr, KM_USER0); |
679 | 677 | ||
680 | return unwritten ? -EFAULT : 0; | 678 | return ret; |
681 | } | 679 | } |
682 | 680 | ||
683 | /** | 681 | /** |
@@ -695,24 +693,10 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | |||
695 | loff_t offset, page_base; | 693 | loff_t offset, page_base; |
696 | char __user *user_data; | 694 | char __user *user_data; |
697 | int page_offset, page_length; | 695 | int page_offset, page_length; |
698 | int ret; | ||
699 | 696 | ||
700 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 697 | user_data = (char __user *) (uintptr_t) args->data_ptr; |
701 | remain = args->size; | 698 | remain = args->size; |
702 | 699 | ||
703 | ret = i915_mutex_lock_interruptible(dev); | ||
704 | if (ret) | ||
705 | return ret; | ||
706 | |||
707 | ret = i915_gem_object_pin(obj, 0); | ||
708 | if (ret) { | ||
709 | mutex_unlock(&dev->struct_mutex); | ||
710 | return ret; | ||
711 | } | ||
712 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); | ||
713 | if (ret) | ||
714 | goto fail; | ||
715 | |||
716 | obj_priv = to_intel_bo(obj); | 700 | obj_priv = to_intel_bo(obj); |
717 | offset = obj_priv->gtt_offset + args->offset; | 701 | offset = obj_priv->gtt_offset + args->offset; |
718 | 702 | ||
@@ -729,26 +713,21 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | |||
729 | if ((page_offset + remain) > PAGE_SIZE) | 713 | if ((page_offset + remain) > PAGE_SIZE) |
730 | page_length = PAGE_SIZE - page_offset; | 714 | page_length = PAGE_SIZE - page_offset; |
731 | 715 | ||
732 | ret = fast_user_write (dev_priv->mm.gtt_mapping, page_base, | ||
733 | page_offset, user_data, page_length); | ||
734 | |||
735 | /* If we get a fault while copying data, then (presumably) our | 716 | /* If we get a fault while copying data, then (presumably) our |
736 | * source page isn't available. Return the error and we'll | 717 | * source page isn't available. Return the error and we'll |
737 | * retry in the slow path. | 718 | * retry in the slow path. |
738 | */ | 719 | */ |
739 | if (ret) | 720 | if (fast_user_write(dev_priv->mm.gtt_mapping, page_base, |
740 | goto fail; | 721 | page_offset, user_data, page_length)) |
722 | |||
723 | return -EFAULT; | ||
741 | 724 | ||
742 | remain -= page_length; | 725 | remain -= page_length; |
743 | user_data += page_length; | 726 | user_data += page_length; |
744 | offset += page_length; | 727 | offset += page_length; |
745 | } | 728 | } |
746 | 729 | ||
747 | fail: | 730 | return 0; |
748 | i915_gem_object_unpin(obj); | ||
749 | mutex_unlock(&dev->struct_mutex); | ||
750 | |||
751 | return ret; | ||
752 | } | 731 | } |
753 | 732 | ||
754 | /** | 733 | /** |
@@ -785,30 +764,24 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
785 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 764 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
786 | num_pages = last_data_page - first_data_page + 1; | 765 | num_pages = last_data_page - first_data_page + 1; |
787 | 766 | ||
788 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); | 767 | user_pages = drm_malloc_ab(num_pages, sizeof(struct page *)); |
789 | if (user_pages == NULL) | 768 | if (user_pages == NULL) |
790 | return -ENOMEM; | 769 | return -ENOMEM; |
791 | 770 | ||
771 | mutex_unlock(&dev->struct_mutex); | ||
792 | down_read(&mm->mmap_sem); | 772 | down_read(&mm->mmap_sem); |
793 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, | 773 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, |
794 | num_pages, 0, 0, user_pages, NULL); | 774 | num_pages, 0, 0, user_pages, NULL); |
795 | up_read(&mm->mmap_sem); | 775 | up_read(&mm->mmap_sem); |
776 | mutex_lock(&dev->struct_mutex); | ||
796 | if (pinned_pages < num_pages) { | 777 | if (pinned_pages < num_pages) { |
797 | ret = -EFAULT; | 778 | ret = -EFAULT; |
798 | goto out_unpin_pages; | 779 | goto out_unpin_pages; |
799 | } | 780 | } |
800 | 781 | ||
801 | ret = i915_mutex_lock_interruptible(dev); | ||
802 | if (ret) | ||
803 | goto out_unpin_pages; | ||
804 | |||
805 | ret = i915_gem_object_pin(obj, 0); | ||
806 | if (ret) | ||
807 | goto out_unlock; | ||
808 | |||
809 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); | 782 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
810 | if (ret) | 783 | if (ret) |
811 | goto out_unpin_object; | 784 | goto out_unpin_pages; |
812 | 785 | ||
813 | obj_priv = to_intel_bo(obj); | 786 | obj_priv = to_intel_bo(obj); |
814 | offset = obj_priv->gtt_offset + args->offset; | 787 | offset = obj_priv->gtt_offset + args->offset; |
@@ -844,10 +817,6 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
844 | data_ptr += page_length; | 817 | data_ptr += page_length; |
845 | } | 818 | } |
846 | 819 | ||
847 | out_unpin_object: | ||
848 | i915_gem_object_unpin(obj); | ||
849 | out_unlock: | ||
850 | mutex_unlock(&dev->struct_mutex); | ||
851 | out_unpin_pages: | 820 | out_unpin_pages: |
852 | for (i = 0; i < pinned_pages; i++) | 821 | for (i = 0; i < pinned_pages; i++) |
853 | page_cache_release(user_pages[i]); | 822 | page_cache_release(user_pages[i]); |
@@ -870,23 +839,10 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | |||
870 | loff_t offset, page_base; | 839 | loff_t offset, page_base; |
871 | char __user *user_data; | 840 | char __user *user_data; |
872 | int page_offset, page_length; | 841 | int page_offset, page_length; |
873 | int ret; | ||
874 | 842 | ||
875 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 843 | user_data = (char __user *) (uintptr_t) args->data_ptr; |
876 | remain = args->size; | 844 | remain = args->size; |
877 | 845 | ||
878 | ret = i915_mutex_lock_interruptible(dev); | ||
879 | if (ret) | ||
880 | return ret; | ||
881 | |||
882 | ret = i915_gem_object_get_pages(obj, 0); | ||
883 | if (ret != 0) | ||
884 | goto fail_unlock; | ||
885 | |||
886 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); | ||
887 | if (ret != 0) | ||
888 | goto fail_put_pages; | ||
889 | |||
890 | obj_priv = to_intel_bo(obj); | 846 | obj_priv = to_intel_bo(obj); |
891 | offset = args->offset; | 847 | offset = args->offset; |
892 | obj_priv->dirty = 1; | 848 | obj_priv->dirty = 1; |
@@ -904,23 +860,17 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, | |||
904 | if ((page_offset + remain) > PAGE_SIZE) | 860 | if ((page_offset + remain) > PAGE_SIZE) |
905 | page_length = PAGE_SIZE - page_offset; | 861 | page_length = PAGE_SIZE - page_offset; |
906 | 862 | ||
907 | ret = fast_shmem_write(obj_priv->pages, | 863 | if (fast_shmem_write(obj_priv->pages, |
908 | page_base, page_offset, | 864 | page_base, page_offset, |
909 | user_data, page_length); | 865 | user_data, page_length)) |
910 | if (ret) | 866 | return -EFAULT; |
911 | goto fail_put_pages; | ||
912 | 867 | ||
913 | remain -= page_length; | 868 | remain -= page_length; |
914 | user_data += page_length; | 869 | user_data += page_length; |
915 | offset += page_length; | 870 | offset += page_length; |
916 | } | 871 | } |
917 | 872 | ||
918 | fail_put_pages: | 873 | return 0; |
919 | i915_gem_object_put_pages(obj); | ||
920 | fail_unlock: | ||
921 | mutex_unlock(&dev->struct_mutex); | ||
922 | |||
923 | return ret; | ||
924 | } | 874 | } |
925 | 875 | ||
926 | /** | 876 | /** |
@@ -962,28 +912,22 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
962 | if (user_pages == NULL) | 912 | if (user_pages == NULL) |
963 | return -ENOMEM; | 913 | return -ENOMEM; |
964 | 914 | ||
915 | mutex_unlock(&dev->struct_mutex); | ||
965 | down_read(&mm->mmap_sem); | 916 | down_read(&mm->mmap_sem); |
966 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, | 917 | pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr, |
967 | num_pages, 0, 0, user_pages, NULL); | 918 | num_pages, 0, 0, user_pages, NULL); |
968 | up_read(&mm->mmap_sem); | 919 | up_read(&mm->mmap_sem); |
920 | mutex_lock(&dev->struct_mutex); | ||
969 | if (pinned_pages < num_pages) { | 921 | if (pinned_pages < num_pages) { |
970 | ret = -EFAULT; | 922 | ret = -EFAULT; |
971 | goto fail_put_user_pages; | 923 | goto out; |
972 | } | 924 | } |
973 | 925 | ||
974 | do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); | 926 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); |
975 | |||
976 | ret = i915_mutex_lock_interruptible(dev); | ||
977 | if (ret) | ||
978 | goto fail_put_user_pages; | ||
979 | |||
980 | ret = i915_gem_object_get_pages_or_evict(obj); | ||
981 | if (ret) | 927 | if (ret) |
982 | goto fail_unlock; | 928 | goto out; |
983 | 929 | ||
984 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); | 930 | do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); |
985 | if (ret != 0) | ||
986 | goto fail_put_pages; | ||
987 | 931 | ||
988 | obj_priv = to_intel_bo(obj); | 932 | obj_priv = to_intel_bo(obj); |
989 | offset = args->offset; | 933 | offset = args->offset; |
@@ -1029,11 +973,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
1029 | offset += page_length; | 973 | offset += page_length; |
1030 | } | 974 | } |
1031 | 975 | ||
1032 | fail_put_pages: | 976 | out: |
1033 | i915_gem_object_put_pages(obj); | ||
1034 | fail_unlock: | ||
1035 | mutex_unlock(&dev->struct_mutex); | ||
1036 | fail_put_user_pages: | ||
1037 | for (i = 0; i < pinned_pages; i++) | 977 | for (i = 0; i < pinned_pages; i++) |
1038 | page_cache_release(user_pages[i]); | 978 | page_cache_release(user_pages[i]); |
1039 | drm_free_large(user_pages); | 979 | drm_free_large(user_pages); |
@@ -1048,18 +988,24 @@ fail_put_user_pages: | |||
1048 | */ | 988 | */ |
1049 | int | 989 | int |
1050 | i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | 990 | i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, |
1051 | struct drm_file *file_priv) | 991 | struct drm_file *file) |
1052 | { | 992 | { |
1053 | struct drm_i915_gem_pwrite *args = data; | 993 | struct drm_i915_gem_pwrite *args = data; |
1054 | struct drm_gem_object *obj; | 994 | struct drm_gem_object *obj; |
1055 | struct drm_i915_gem_object *obj_priv; | 995 | struct drm_i915_gem_object *obj_priv; |
1056 | int ret = 0; | 996 | int ret = 0; |
1057 | 997 | ||
1058 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 998 | obj = drm_gem_object_lookup(dev, file, args->handle); |
1059 | if (obj == NULL) | 999 | if (obj == NULL) |
1060 | return -ENOENT; | 1000 | return -ENOENT; |
1061 | obj_priv = to_intel_bo(obj); | 1001 | obj_priv = to_intel_bo(obj); |
1062 | 1002 | ||
1003 | ret = i915_mutex_lock_interruptible(dev); | ||
1004 | if (ret) { | ||
1005 | drm_gem_object_unreference_unlocked(obj); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1063 | /* Bounds check destination. */ | 1009 | /* Bounds check destination. */ |
1064 | if (args->offset > obj->size || args->size > obj->size - args->offset) { | 1010 | if (args->offset > obj->size || args->size > obj->size - args->offset) { |
1065 | ret = -EINVAL; | 1011 | ret = -EINVAL; |
@@ -1090,32 +1036,46 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
1090 | * perspective, requiring manual detiling by the client. | 1036 | * perspective, requiring manual detiling by the client. |
1091 | */ | 1037 | */ |
1092 | if (obj_priv->phys_obj) | 1038 | if (obj_priv->phys_obj) |
1093 | ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); | 1039 | ret = i915_gem_phys_pwrite(dev, obj, args, file); |
1094 | else if (obj_priv->tiling_mode == I915_TILING_NONE && | 1040 | else if (obj_priv->tiling_mode == I915_TILING_NONE && |
1095 | obj_priv->gtt_space && | 1041 | obj_priv->gtt_space && |
1096 | obj->write_domain != I915_GEM_DOMAIN_CPU) { | 1042 | obj->write_domain != I915_GEM_DOMAIN_CPU) { |
1097 | ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); | 1043 | ret = i915_gem_object_pin(obj, 0); |
1098 | if (ret == -EFAULT) { | 1044 | if (ret) |
1099 | ret = i915_gem_gtt_pwrite_slow(dev, obj, args, | 1045 | goto out; |
1100 | file_priv); | 1046 | |
1101 | } | 1047 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
1102 | } else if (i915_gem_object_needs_bit17_swizzle(obj)) { | 1048 | if (ret) |
1103 | ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file_priv); | 1049 | goto out_unpin; |
1050 | |||
1051 | ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file); | ||
1052 | if (ret == -EFAULT) | ||
1053 | ret = i915_gem_gtt_pwrite_slow(dev, obj, args, file); | ||
1054 | |||
1055 | out_unpin: | ||
1056 | i915_gem_object_unpin(obj); | ||
1104 | } else { | 1057 | } else { |
1105 | ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file_priv); | 1058 | ret = i915_gem_object_get_pages_or_evict(obj); |
1106 | if (ret == -EFAULT) { | 1059 | if (ret) |
1107 | ret = i915_gem_shmem_pwrite_slow(dev, obj, args, | 1060 | goto out; |
1108 | file_priv); | ||
1109 | } | ||
1110 | } | ||
1111 | 1061 | ||
1112 | #if WATCH_PWRITE | 1062 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); |
1113 | if (ret) | 1063 | if (ret) |
1114 | DRM_INFO("pwrite failed %d\n", ret); | 1064 | goto out_put; |
1115 | #endif | 1065 | |
1066 | ret = -EFAULT; | ||
1067 | if (!i915_gem_object_needs_bit17_swizzle(obj)) | ||
1068 | ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file); | ||
1069 | if (ret == -EFAULT) | ||
1070 | ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file); | ||
1071 | |||
1072 | out_put: | ||
1073 | i915_gem_object_put_pages(obj); | ||
1074 | } | ||
1116 | 1075 | ||
1117 | out: | 1076 | out: |
1118 | drm_gem_object_unreference_unlocked(obj); | 1077 | drm_gem_object_unreference(obj); |
1078 | mutex_unlock(&dev->struct_mutex); | ||
1119 | return ret; | 1079 | return ret; |
1120 | } | 1080 | } |
1121 | 1081 | ||