diff options
-rw-r--r-- | drivers/gpu/drm/vmwgfx/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 254 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_va.c | 168 |
3 files changed, 169 insertions, 255 deletions
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 2258908b1436..aac17a640cce 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile | |||
@@ -9,6 +9,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ | |||
9 | vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ | 9 | vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ |
10 | vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ | 10 | vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ |
11 | vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ | 11 | vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ |
12 | vmwgfx_simple_resource.o | 12 | vmwgfx_simple_resource.o vmwgfx_va.o |
13 | 13 | ||
14 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o | 14 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 27033d944b08..fa1037ec8e5f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -45,31 +45,6 @@ struct vmw_bo_user_rep { | |||
45 | uint64_t map_handle; | 45 | uint64_t map_handle; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct vmw_stream { | ||
49 | struct vmw_resource res; | ||
50 | uint32_t stream_id; | ||
51 | }; | ||
52 | |||
53 | struct vmw_user_stream { | ||
54 | struct ttm_base_object base; | ||
55 | struct vmw_stream stream; | ||
56 | }; | ||
57 | |||
58 | |||
59 | static uint64_t vmw_user_stream_size; | ||
60 | |||
61 | static const struct vmw_res_func vmw_stream_func = { | ||
62 | .res_type = vmw_res_stream, | ||
63 | .needs_backup = false, | ||
64 | .may_evict = false, | ||
65 | .type_name = "video streams", | ||
66 | .backup_placement = NULL, | ||
67 | .create = NULL, | ||
68 | .destroy = NULL, | ||
69 | .bind = NULL, | ||
70 | .unbind = NULL | ||
71 | }; | ||
72 | |||
73 | static inline struct vmw_dma_buffer * | 48 | static inline struct vmw_dma_buffer * |
74 | vmw_dma_buffer(struct ttm_buffer_object *bo) | 49 | vmw_dma_buffer(struct ttm_buffer_object *bo) |
75 | { | 50 | { |
@@ -259,24 +234,6 @@ void vmw_resource_activate(struct vmw_resource *res, | |||
259 | write_unlock(&dev_priv->resource_lock); | 234 | write_unlock(&dev_priv->resource_lock); |
260 | } | 235 | } |
261 | 236 | ||
262 | static struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv, | ||
263 | struct idr *idr, int id) | ||
264 | { | ||
265 | struct vmw_resource *res; | ||
266 | |||
267 | read_lock(&dev_priv->resource_lock); | ||
268 | res = idr_find(idr, id); | ||
269 | if (!res || !res->avail || !kref_get_unless_zero(&res->kref)) | ||
270 | res = NULL; | ||
271 | |||
272 | read_unlock(&dev_priv->resource_lock); | ||
273 | |||
274 | if (unlikely(res == NULL)) | ||
275 | return NULL; | ||
276 | |||
277 | return res; | ||
278 | } | ||
279 | |||
280 | /** | 237 | /** |
281 | * vmw_user_resource_lookup_handle - lookup a struct resource from a | 238 | * vmw_user_resource_lookup_handle - lookup a struct resource from a |
282 | * TTM user-space handle and perform basic type checks | 239 | * TTM user-space handle and perform basic type checks |
@@ -776,217 +733,6 @@ int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, | |||
776 | TTM_REF_USAGE, NULL); | 733 | TTM_REF_USAGE, NULL); |
777 | } | 734 | } |
778 | 735 | ||
779 | /* | ||
780 | * Stream management | ||
781 | */ | ||
782 | |||
783 | static void vmw_stream_destroy(struct vmw_resource *res) | ||
784 | { | ||
785 | struct vmw_private *dev_priv = res->dev_priv; | ||
786 | struct vmw_stream *stream; | ||
787 | int ret; | ||
788 | |||
789 | DRM_INFO("%s: unref\n", __func__); | ||
790 | stream = container_of(res, struct vmw_stream, res); | ||
791 | |||
792 | ret = vmw_overlay_unref(dev_priv, stream->stream_id); | ||
793 | WARN_ON(ret != 0); | ||
794 | } | ||
795 | |||
796 | static int vmw_stream_init(struct vmw_private *dev_priv, | ||
797 | struct vmw_stream *stream, | ||
798 | void (*res_free) (struct vmw_resource *res)) | ||
799 | { | ||
800 | struct vmw_resource *res = &stream->res; | ||
801 | int ret; | ||
802 | |||
803 | ret = vmw_resource_init(dev_priv, res, false, res_free, | ||
804 | &vmw_stream_func); | ||
805 | |||
806 | if (unlikely(ret != 0)) { | ||
807 | if (res_free == NULL) | ||
808 | kfree(stream); | ||
809 | else | ||
810 | res_free(&stream->res); | ||
811 | return ret; | ||
812 | } | ||
813 | |||
814 | ret = vmw_overlay_claim(dev_priv, &stream->stream_id); | ||
815 | if (ret) { | ||
816 | vmw_resource_unreference(&res); | ||
817 | return ret; | ||
818 | } | ||
819 | |||
820 | DRM_INFO("%s: claimed\n", __func__); | ||
821 | |||
822 | vmw_resource_activate(&stream->res, vmw_stream_destroy); | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static void vmw_user_stream_free(struct vmw_resource *res) | ||
827 | { | ||
828 | struct vmw_user_stream *stream = | ||
829 | container_of(res, struct vmw_user_stream, stream.res); | ||
830 | struct vmw_private *dev_priv = res->dev_priv; | ||
831 | |||
832 | ttm_base_object_kfree(stream, base); | ||
833 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | ||
834 | vmw_user_stream_size); | ||
835 | } | ||
836 | |||
837 | /** | ||
838 | * This function is called when user space has no more references on the | ||
839 | * base object. It releases the base-object's reference on the resource object. | ||
840 | */ | ||
841 | |||
842 | static void vmw_user_stream_base_release(struct ttm_base_object **p_base) | ||
843 | { | ||
844 | struct ttm_base_object *base = *p_base; | ||
845 | struct vmw_user_stream *stream = | ||
846 | container_of(base, struct vmw_user_stream, base); | ||
847 | struct vmw_resource *res = &stream->stream.res; | ||
848 | |||
849 | *p_base = NULL; | ||
850 | vmw_resource_unreference(&res); | ||
851 | } | ||
852 | |||
853 | int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, | ||
854 | struct drm_file *file_priv) | ||
855 | { | ||
856 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
857 | struct vmw_resource *res; | ||
858 | struct vmw_user_stream *stream; | ||
859 | struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; | ||
860 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
861 | struct idr *idr = &dev_priv->res_idr[vmw_res_stream]; | ||
862 | int ret = 0; | ||
863 | |||
864 | |||
865 | res = vmw_resource_lookup(dev_priv, idr, arg->stream_id); | ||
866 | if (unlikely(res == NULL)) | ||
867 | return -EINVAL; | ||
868 | |||
869 | if (res->res_free != &vmw_user_stream_free) { | ||
870 | ret = -EINVAL; | ||
871 | goto out; | ||
872 | } | ||
873 | |||
874 | stream = container_of(res, struct vmw_user_stream, stream.res); | ||
875 | if (stream->base.tfile != tfile) { | ||
876 | ret = -EINVAL; | ||
877 | goto out; | ||
878 | } | ||
879 | |||
880 | ttm_ref_object_base_unref(tfile, stream->base.hash.key, TTM_REF_USAGE); | ||
881 | out: | ||
882 | vmw_resource_unreference(&res); | ||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, | ||
887 | struct drm_file *file_priv) | ||
888 | { | ||
889 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
890 | struct vmw_user_stream *stream; | ||
891 | struct vmw_resource *res; | ||
892 | struct vmw_resource *tmp; | ||
893 | struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; | ||
894 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
895 | int ret; | ||
896 | |||
897 | /* | ||
898 | * Approximate idr memory usage with 128 bytes. It will be limited | ||
899 | * by maximum number_of streams anyway? | ||
900 | */ | ||
901 | |||
902 | if (unlikely(vmw_user_stream_size == 0)) | ||
903 | vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128; | ||
904 | |||
905 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); | ||
906 | if (unlikely(ret != 0)) | ||
907 | return ret; | ||
908 | |||
909 | ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), | ||
910 | vmw_user_stream_size, | ||
911 | false, true); | ||
912 | ttm_read_unlock(&dev_priv->reservation_sem); | ||
913 | if (unlikely(ret != 0)) { | ||
914 | if (ret != -ERESTARTSYS) | ||
915 | DRM_ERROR("Out of graphics memory for stream" | ||
916 | " creation.\n"); | ||
917 | |||
918 | goto out_ret; | ||
919 | } | ||
920 | |||
921 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
922 | if (unlikely(stream == NULL)) { | ||
923 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | ||
924 | vmw_user_stream_size); | ||
925 | ret = -ENOMEM; | ||
926 | goto out_ret; | ||
927 | } | ||
928 | |||
929 | res = &stream->stream.res; | ||
930 | stream->base.shareable = false; | ||
931 | stream->base.tfile = NULL; | ||
932 | |||
933 | /* | ||
934 | * From here on, the destructor takes over resource freeing. | ||
935 | */ | ||
936 | |||
937 | ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free); | ||
938 | if (unlikely(ret != 0)) | ||
939 | goto out_ret; | ||
940 | |||
941 | tmp = vmw_resource_reference(res); | ||
942 | ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM, | ||
943 | &vmw_user_stream_base_release, NULL); | ||
944 | |||
945 | if (unlikely(ret != 0)) { | ||
946 | vmw_resource_unreference(&tmp); | ||
947 | goto out_err; | ||
948 | } | ||
949 | |||
950 | arg->stream_id = res->id; | ||
951 | out_err: | ||
952 | vmw_resource_unreference(&res); | ||
953 | out_ret: | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | int vmw_user_stream_lookup(struct vmw_private *dev_priv, | ||
958 | struct ttm_object_file *tfile, | ||
959 | uint32_t *inout_id, struct vmw_resource **out) | ||
960 | { | ||
961 | struct vmw_user_stream *stream; | ||
962 | struct vmw_resource *res; | ||
963 | int ret; | ||
964 | |||
965 | res = vmw_resource_lookup(dev_priv, &dev_priv->res_idr[vmw_res_stream], | ||
966 | *inout_id); | ||
967 | if (unlikely(res == NULL)) | ||
968 | return -EINVAL; | ||
969 | |||
970 | if (res->res_free != &vmw_user_stream_free) { | ||
971 | ret = -EINVAL; | ||
972 | goto err_ref; | ||
973 | } | ||
974 | |||
975 | stream = container_of(res, struct vmw_user_stream, stream.res); | ||
976 | if (stream->base.tfile != tfile) { | ||
977 | ret = -EPERM; | ||
978 | goto err_ref; | ||
979 | } | ||
980 | |||
981 | *inout_id = stream->stream.stream_id; | ||
982 | *out = res; | ||
983 | return 0; | ||
984 | err_ref: | ||
985 | vmw_resource_unreference(&res); | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | |||
990 | /** | 736 | /** |
991 | * vmw_dumb_create - Create a dumb kms buffer | 737 | * vmw_dumb_create - Create a dumb kms buffer |
992 | * | 738 | * |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_va.c b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c new file mode 100644 index 000000000000..b4162fd78600 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright © 2012-2016 VMware, Inc., Palo Alto, CA., USA | ||
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 | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | #include "vmwgfx_drv.h" | ||
29 | #include "vmwgfx_resource_priv.h" | ||
30 | |||
31 | /** | ||
32 | * struct vmw_stream - Overlay stream simple resource. | ||
33 | * @sres: The simple resource we derive from. | ||
34 | * @stream_id: The overlay stream id. | ||
35 | */ | ||
36 | struct vmw_stream { | ||
37 | struct vmw_simple_resource sres; | ||
38 | u32 stream_id; | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * vmw_stream - Typecast a struct vmw_resource to a struct vmw_stream. | ||
43 | * @res: Pointer to the struct vmw_resource. | ||
44 | * | ||
45 | * Returns: Returns a pointer to the struct vmw_stream. | ||
46 | */ | ||
47 | static struct vmw_stream * | ||
48 | vmw_stream(struct vmw_resource *res) | ||
49 | { | ||
50 | return container_of(res, struct vmw_stream, sres.res); | ||
51 | } | ||
52 | |||
53 | /*************************************************************************** | ||
54 | * Simple resource callbacks for struct vmw_stream | ||
55 | **************************************************************************/ | ||
56 | static void vmw_stream_hw_destroy(struct vmw_resource *res) | ||
57 | { | ||
58 | struct vmw_private *dev_priv = res->dev_priv; | ||
59 | struct vmw_stream *stream = vmw_stream(res); | ||
60 | int ret; | ||
61 | |||
62 | ret = vmw_overlay_unref(dev_priv, stream->stream_id); | ||
63 | WARN_ON_ONCE(ret != 0); | ||
64 | } | ||
65 | |||
66 | static int vmw_stream_init(struct vmw_resource *res, void *data) | ||
67 | { | ||
68 | struct vmw_stream *stream = vmw_stream(res); | ||
69 | |||
70 | return vmw_overlay_claim(res->dev_priv, &stream->stream_id); | ||
71 | } | ||
72 | |||
73 | static void vmw_stream_set_arg_handle(void *data, u32 handle) | ||
74 | { | ||
75 | struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; | ||
76 | |||
77 | arg->stream_id = handle; | ||
78 | } | ||
79 | |||
80 | static const struct vmw_simple_resource_func va_stream_func = { | ||
81 | .res_func = { | ||
82 | .res_type = vmw_res_stream, | ||
83 | .needs_backup = false, | ||
84 | .may_evict = false, | ||
85 | .type_name = "overlay stream", | ||
86 | .backup_placement = NULL, | ||
87 | .create = NULL, | ||
88 | .destroy = NULL, | ||
89 | .bind = NULL, | ||
90 | .unbind = NULL | ||
91 | }, | ||
92 | .ttm_res_type = VMW_RES_STREAM, | ||
93 | .size = sizeof(struct vmw_stream), | ||
94 | .init = vmw_stream_init, | ||
95 | .hw_destroy = vmw_stream_hw_destroy, | ||
96 | .set_arg_handle = vmw_stream_set_arg_handle, | ||
97 | }; | ||
98 | |||
99 | /*************************************************************************** | ||
100 | * End simple resource callbacks for struct vmw_stream | ||
101 | **************************************************************************/ | ||
102 | |||
103 | /** | ||
104 | * vmw_stream_unref_ioctl - Ioctl to unreference a user-space handle to | ||
105 | * a struct vmw_stream. | ||
106 | * @dev: Pointer to the drm device. | ||
107 | * @data: The ioctl argument | ||
108 | * @file_priv: Pointer to a struct drm_file identifying the caller. | ||
109 | * | ||
110 | * Return: | ||
111 | * 0 if successful. | ||
112 | * Negative error value on failure. | ||
113 | */ | ||
114 | int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, | ||
115 | struct drm_file *file_priv) | ||
116 | { | ||
117 | struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; | ||
118 | |||
119 | return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, | ||
120 | arg->stream_id, TTM_REF_USAGE); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * vmw_stream_claim_ioctl - Ioctl to claim a struct vmw_stream overlay. | ||
125 | * @dev: Pointer to the drm device. | ||
126 | * @data: The ioctl argument | ||
127 | * @file_priv: Pointer to a struct drm_file identifying the caller. | ||
128 | * | ||
129 | * Return: | ||
130 | * 0 if successful. | ||
131 | * Negative error value on failure. | ||
132 | */ | ||
133 | int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, | ||
134 | struct drm_file *file_priv) | ||
135 | { | ||
136 | return vmw_simple_resource_create_ioctl(dev, data, file_priv, | ||
137 | &va_stream_func); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * vmw_user_stream_lookup - Look up a struct vmw_user_stream from a handle. | ||
142 | * @dev_priv: Pointer to a struct vmw_private. | ||
143 | * @tfile: struct ttm_object_file identifying the caller. | ||
144 | * @inout_id: In: The user-space handle. Out: The stream id. | ||
145 | * @out: On output contains a refcounted pointer to the embedded | ||
146 | * struct vmw_resource. | ||
147 | * | ||
148 | * Return: | ||
149 | * 0 if successful. | ||
150 | * Negative error value on failure. | ||
151 | */ | ||
152 | int vmw_user_stream_lookup(struct vmw_private *dev_priv, | ||
153 | struct ttm_object_file *tfile, | ||
154 | uint32_t *inout_id, struct vmw_resource **out) | ||
155 | { | ||
156 | struct vmw_stream *stream; | ||
157 | struct vmw_resource *res = | ||
158 | vmw_simple_resource_lookup(tfile, *inout_id, &va_stream_func); | ||
159 | |||
160 | if (IS_ERR(res)) | ||
161 | return PTR_ERR(res); | ||
162 | |||
163 | stream = vmw_stream(res); | ||
164 | *inout_id = stream->stream_id; | ||
165 | *out = res; | ||
166 | |||
167 | return 0; | ||
168 | } | ||