diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2014-03-18 10:00:56 -0400 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2014-03-28 09:19:03 -0400 |
commit | adebcb20e4ca9330a293c294e1f104edba21dbaf (patch) | |
tree | 09afc68d6963a27e8f2e2e38263e3cd8b6b2c25f | |
parent | 4649926d043205d3693551b36e2ed88a264177a5 (diff) |
drm/vmwgfx: Allow prime fds in the surface reference ioctls
Allow prime fds and at the same time block legacy handles for render-nodes
in the surface reference ioctls. This means these ioctls can be used
directly from prime-aware clients, and that they can be called from
render-nodes.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 105 | ||||
-rw-r--r-- | include/uapi/drm/vmwgfx_drm.h | 12 |
2 files changed, 81 insertions, 36 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index aac243b9ec30..d50cd76378c4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | |||
@@ -876,6 +876,64 @@ out_unlock: | |||
876 | return ret; | 876 | return ret; |
877 | } | 877 | } |
878 | 878 | ||
879 | |||
880 | static int | ||
881 | vmw_surface_handle_reference(struct vmw_private *dev_priv, | ||
882 | struct drm_file *file_priv, | ||
883 | uint32_t u_handle, | ||
884 | enum drm_vmw_handle_type handle_type, | ||
885 | struct ttm_base_object **base_p) | ||
886 | { | ||
887 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
888 | uint32_t handle; | ||
889 | struct ttm_base_object *base; | ||
890 | int ret; | ||
891 | |||
892 | if (handle_type == DRM_VMW_HANDLE_PRIME) { | ||
893 | ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); | ||
894 | if (unlikely(ret != 0)) | ||
895 | return ret; | ||
896 | } else { | ||
897 | if (unlikely(drm_is_render_client(file_priv))) { | ||
898 | DRM_ERROR("Render client refused legacy " | ||
899 | "surface reference.\n"); | ||
900 | return -EACCES; | ||
901 | } | ||
902 | handle = u_handle; | ||
903 | } | ||
904 | |||
905 | ret = -EINVAL; | ||
906 | base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle); | ||
907 | if (unlikely(base == NULL)) { | ||
908 | DRM_ERROR("Could not find surface to reference.\n"); | ||
909 | goto out_no_lookup; | ||
910 | } | ||
911 | |||
912 | if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) { | ||
913 | DRM_ERROR("Referenced object is not a surface.\n"); | ||
914 | goto out_bad_resource; | ||
915 | } | ||
916 | |||
917 | if (handle_type != DRM_VMW_HANDLE_PRIME) { | ||
918 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); | ||
919 | if (unlikely(ret != 0)) { | ||
920 | DRM_ERROR("Could not add a reference to a surface.\n"); | ||
921 | goto out_bad_resource; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | *base_p = base; | ||
926 | return 0; | ||
927 | |||
928 | out_bad_resource: | ||
929 | ttm_base_object_unref(&base); | ||
930 | out_no_lookup: | ||
931 | if (handle_type == DRM_VMW_HANDLE_PRIME) | ||
932 | (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); | ||
933 | |||
934 | return ret; | ||
935 | } | ||
936 | |||
879 | /** | 937 | /** |
880 | * vmw_user_surface_define_ioctl - Ioctl function implementing | 938 | * vmw_user_surface_define_ioctl - Ioctl function implementing |
881 | * the user surface reference functionality. | 939 | * the user surface reference functionality. |
@@ -897,27 +955,16 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
897 | struct vmw_user_surface *user_srf; | 955 | struct vmw_user_surface *user_srf; |
898 | struct drm_vmw_size __user *user_sizes; | 956 | struct drm_vmw_size __user *user_sizes; |
899 | struct ttm_base_object *base; | 957 | struct ttm_base_object *base; |
900 | int ret = -EINVAL; | 958 | int ret; |
901 | |||
902 | base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); | ||
903 | if (unlikely(base == NULL)) { | ||
904 | DRM_ERROR("Could not find surface to reference.\n"); | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | 959 | ||
908 | if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) | 960 | ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, |
909 | goto out_bad_resource; | 961 | req->handle_type, &base); |
962 | if (unlikely(ret != 0)) | ||
963 | return ret; | ||
910 | 964 | ||
911 | user_srf = container_of(base, struct vmw_user_surface, prime.base); | 965 | user_srf = container_of(base, struct vmw_user_surface, prime.base); |
912 | srf = &user_srf->srf; | 966 | srf = &user_srf->srf; |
913 | 967 | ||
914 | ret = ttm_ref_object_add(tfile, &user_srf->prime.base, | ||
915 | TTM_REF_USAGE, NULL); | ||
916 | if (unlikely(ret != 0)) { | ||
917 | DRM_ERROR("Could not add a reference to a surface.\n"); | ||
918 | goto out_no_reference; | ||
919 | } | ||
920 | |||
921 | rep->flags = srf->flags; | 968 | rep->flags = srf->flags; |
922 | rep->format = srf->format; | 969 | rep->format = srf->format; |
923 | memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); | 970 | memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); |
@@ -930,10 +977,10 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
930 | if (unlikely(ret != 0)) { | 977 | if (unlikely(ret != 0)) { |
931 | DRM_ERROR("copy_to_user failed %p %u\n", | 978 | DRM_ERROR("copy_to_user failed %p %u\n", |
932 | user_sizes, srf->num_sizes); | 979 | user_sizes, srf->num_sizes); |
980 | ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE); | ||
933 | ret = -EFAULT; | 981 | ret = -EFAULT; |
934 | } | 982 | } |
935 | out_bad_resource: | 983 | |
936 | out_no_reference: | ||
937 | ttm_base_object_unref(&base); | 984 | ttm_base_object_unref(&base); |
938 | 985 | ||
939 | return ret; | 986 | return ret; |
@@ -1313,14 +1360,10 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
1313 | uint32_t backup_handle; | 1360 | uint32_t backup_handle; |
1314 | int ret = -EINVAL; | 1361 | int ret = -EINVAL; |
1315 | 1362 | ||
1316 | base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); | 1363 | ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, |
1317 | if (unlikely(base == NULL)) { | 1364 | req->handle_type, &base); |
1318 | DRM_ERROR("Could not find surface to reference.\n"); | 1365 | if (unlikely(ret != 0)) |
1319 | return -EINVAL; | 1366 | return ret; |
1320 | } | ||
1321 | |||
1322 | if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) | ||
1323 | goto out_bad_resource; | ||
1324 | 1367 | ||
1325 | user_srf = container_of(base, struct vmw_user_surface, prime.base); | 1368 | user_srf = container_of(base, struct vmw_user_surface, prime.base); |
1326 | srf = &user_srf->srf; | 1369 | srf = &user_srf->srf; |
@@ -1329,13 +1372,6 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
1329 | goto out_bad_resource; | 1372 | goto out_bad_resource; |
1330 | } | 1373 | } |
1331 | 1374 | ||
1332 | ret = ttm_ref_object_add(tfile, &user_srf->prime.base, | ||
1333 | TTM_REF_USAGE, NULL); | ||
1334 | if (unlikely(ret != 0)) { | ||
1335 | DRM_ERROR("Could not add a reference to a GB surface.\n"); | ||
1336 | goto out_bad_resource; | ||
1337 | } | ||
1338 | |||
1339 | mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ | 1375 | mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ |
1340 | ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, | 1376 | ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, |
1341 | &backup_handle); | 1377 | &backup_handle); |
@@ -1344,8 +1380,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
1344 | if (unlikely(ret != 0)) { | 1380 | if (unlikely(ret != 0)) { |
1345 | DRM_ERROR("Could not add a reference to a GB surface " | 1381 | DRM_ERROR("Could not add a reference to a GB surface " |
1346 | "backup buffer.\n"); | 1382 | "backup buffer.\n"); |
1347 | (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, | 1383 | (void) ttm_ref_object_base_unref(tfile, base->hash.key, |
1348 | req->sid, | ||
1349 | TTM_REF_USAGE); | 1384 | TTM_REF_USAGE); |
1350 | goto out_bad_resource; | 1385 | goto out_bad_resource; |
1351 | } | 1386 | } |
diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 87792a5fee3b..4fc66f6b12ce 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h | |||
@@ -90,6 +90,15 @@ | |||
90 | #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 | 90 | #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 |
91 | 91 | ||
92 | /** | 92 | /** |
93 | * enum drm_vmw_handle_type - handle type for ref ioctls | ||
94 | * | ||
95 | */ | ||
96 | enum drm_vmw_handle_type { | ||
97 | DRM_VMW_HANDLE_LEGACY = 0, | ||
98 | DRM_VMW_HANDLE_PRIME = 1 | ||
99 | }; | ||
100 | |||
101 | /** | ||
93 | * struct drm_vmw_getparam_arg | 102 | * struct drm_vmw_getparam_arg |
94 | * | 103 | * |
95 | * @value: Returned value. //Out | 104 | * @value: Returned value. //Out |
@@ -177,6 +186,7 @@ struct drm_vmw_surface_create_req { | |||
177 | * struct drm_wmv_surface_arg | 186 | * struct drm_wmv_surface_arg |
178 | * | 187 | * |
179 | * @sid: Surface id of created surface or surface to destroy or reference. | 188 | * @sid: Surface id of created surface or surface to destroy or reference. |
189 | * @handle_type: Handle type for DRM_VMW_REF_SURFACE Ioctl. | ||
180 | * | 190 | * |
181 | * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. | 191 | * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. |
182 | * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. | 192 | * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. |
@@ -185,7 +195,7 @@ struct drm_vmw_surface_create_req { | |||
185 | 195 | ||
186 | struct drm_vmw_surface_arg { | 196 | struct drm_vmw_surface_arg { |
187 | int32_t sid; | 197 | int32_t sid; |
188 | uint32_t pad64; | 198 | enum drm_vmw_handle_type handle_type; |
189 | }; | 199 | }; |
190 | 200 | ||
191 | /** | 201 | /** |