diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_surface.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 467 |
1 files changed, 463 insertions, 4 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 0fc93398bba2..3bb3331acdaf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | |||
@@ -41,7 +41,6 @@ struct vmw_user_surface { | |||
41 | struct ttm_prime_object prime; | 41 | struct ttm_prime_object prime; |
42 | struct vmw_surface srf; | 42 | struct vmw_surface srf; |
43 | uint32_t size; | 43 | uint32_t size; |
44 | uint32_t backup_handle; | ||
45 | }; | 44 | }; |
46 | 45 | ||
47 | /** | 46 | /** |
@@ -68,6 +67,14 @@ static int vmw_legacy_srf_unbind(struct vmw_resource *res, | |||
68 | struct ttm_validate_buffer *val_buf); | 67 | struct ttm_validate_buffer *val_buf); |
69 | static int vmw_legacy_srf_create(struct vmw_resource *res); | 68 | static int vmw_legacy_srf_create(struct vmw_resource *res); |
70 | static int vmw_legacy_srf_destroy(struct vmw_resource *res); | 69 | static int vmw_legacy_srf_destroy(struct vmw_resource *res); |
70 | static int vmw_gb_surface_create(struct vmw_resource *res); | ||
71 | static int vmw_gb_surface_bind(struct vmw_resource *res, | ||
72 | struct ttm_validate_buffer *val_buf); | ||
73 | static int vmw_gb_surface_unbind(struct vmw_resource *res, | ||
74 | bool readback, | ||
75 | struct ttm_validate_buffer *val_buf); | ||
76 | static int vmw_gb_surface_destroy(struct vmw_resource *res); | ||
77 | |||
71 | 78 | ||
72 | static const struct vmw_user_resource_conv user_surface_conv = { | 79 | static const struct vmw_user_resource_conv user_surface_conv = { |
73 | .object_type = VMW_RES_SURFACE, | 80 | .object_type = VMW_RES_SURFACE, |
@@ -93,6 +100,18 @@ static const struct vmw_res_func vmw_legacy_surface_func = { | |||
93 | .unbind = &vmw_legacy_srf_unbind | 100 | .unbind = &vmw_legacy_srf_unbind |
94 | }; | 101 | }; |
95 | 102 | ||
103 | static const struct vmw_res_func vmw_gb_surface_func = { | ||
104 | .res_type = vmw_res_surface, | ||
105 | .needs_backup = true, | ||
106 | .may_evict = true, | ||
107 | .type_name = "guest backed surfaces", | ||
108 | .backup_placement = &vmw_mob_placement, | ||
109 | .create = vmw_gb_surface_create, | ||
110 | .destroy = vmw_gb_surface_destroy, | ||
111 | .bind = vmw_gb_surface_bind, | ||
112 | .unbind = vmw_gb_surface_unbind | ||
113 | }; | ||
114 | |||
96 | /** | 115 | /** |
97 | * struct vmw_surface_dma - SVGA3D DMA command | 116 | * struct vmw_surface_dma - SVGA3D DMA command |
98 | */ | 117 | */ |
@@ -291,6 +310,11 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) | |||
291 | struct vmw_surface *srf; | 310 | struct vmw_surface *srf; |
292 | void *cmd; | 311 | void *cmd; |
293 | 312 | ||
313 | if (res->func->destroy == vmw_gb_surface_destroy) { | ||
314 | (void) vmw_gb_surface_destroy(res); | ||
315 | return; | ||
316 | } | ||
317 | |||
294 | if (res->id != -1) { | 318 | if (res->id != -1) { |
295 | 319 | ||
296 | cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size()); | 320 | cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size()); |
@@ -549,12 +573,15 @@ static int vmw_surface_init(struct vmw_private *dev_priv, | |||
549 | struct vmw_resource *res = &srf->res; | 573 | struct vmw_resource *res = &srf->res; |
550 | 574 | ||
551 | BUG_ON(res_free == NULL); | 575 | BUG_ON(res_free == NULL); |
552 | (void) vmw_3d_resource_inc(dev_priv, false); | 576 | if (!dev_priv->has_mob) |
577 | (void) vmw_3d_resource_inc(dev_priv, false); | ||
553 | ret = vmw_resource_init(dev_priv, res, true, res_free, | 578 | ret = vmw_resource_init(dev_priv, res, true, res_free, |
579 | (dev_priv->has_mob) ? &vmw_gb_surface_func : | ||
554 | &vmw_legacy_surface_func); | 580 | &vmw_legacy_surface_func); |
555 | 581 | ||
556 | if (unlikely(ret != 0)) { | 582 | if (unlikely(ret != 0)) { |
557 | vmw_3d_resource_dec(dev_priv, false); | 583 | if (!dev_priv->has_mob) |
584 | vmw_3d_resource_dec(dev_priv, false); | ||
558 | res_free(res); | 585 | res_free(res); |
559 | return ret; | 586 | return ret; |
560 | } | 587 | } |
@@ -750,7 +777,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | |||
750 | 777 | ||
751 | srf->base_size = *srf->sizes; | 778 | srf->base_size = *srf->sizes; |
752 | srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; | 779 | srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; |
753 | srf->multisample_count = 1; | 780 | srf->multisample_count = 0; |
754 | 781 | ||
755 | cur_bo_offset = 0; | 782 | cur_bo_offset = 0; |
756 | cur_offset = srf->offsets; | 783 | cur_offset = srf->offsets; |
@@ -894,3 +921,435 @@ out_no_reference: | |||
894 | 921 | ||
895 | return ret; | 922 | return ret; |
896 | } | 923 | } |
924 | |||
925 | /** | ||
926 | * vmw_surface_define_encode - Encode a surface_define command. | ||
927 | * | ||
928 | * @srf: Pointer to a struct vmw_surface object. | ||
929 | * @cmd_space: Pointer to memory area in which the commands should be encoded. | ||
930 | */ | ||
931 | static int vmw_gb_surface_create(struct vmw_resource *res) | ||
932 | { | ||
933 | struct vmw_private *dev_priv = res->dev_priv; | ||
934 | struct vmw_surface *srf = vmw_res_to_srf(res); | ||
935 | uint32_t cmd_len, submit_len; | ||
936 | int ret; | ||
937 | struct { | ||
938 | SVGA3dCmdHeader header; | ||
939 | SVGA3dCmdDefineGBSurface body; | ||
940 | } *cmd; | ||
941 | |||
942 | if (likely(res->id != -1)) | ||
943 | return 0; | ||
944 | |||
945 | (void) vmw_3d_resource_inc(dev_priv, false); | ||
946 | ret = vmw_resource_alloc_id(res); | ||
947 | if (unlikely(ret != 0)) { | ||
948 | DRM_ERROR("Failed to allocate a surface id.\n"); | ||
949 | goto out_no_id; | ||
950 | } | ||
951 | |||
952 | if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) { | ||
953 | ret = -EBUSY; | ||
954 | goto out_no_fifo; | ||
955 | } | ||
956 | |||
957 | cmd_len = sizeof(cmd->body); | ||
958 | submit_len = sizeof(*cmd); | ||
959 | cmd = vmw_fifo_reserve(dev_priv, submit_len); | ||
960 | if (unlikely(cmd == NULL)) { | ||
961 | DRM_ERROR("Failed reserving FIFO space for surface " | ||
962 | "creation.\n"); | ||
963 | ret = -ENOMEM; | ||
964 | goto out_no_fifo; | ||
965 | } | ||
966 | |||
967 | cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SURFACE; | ||
968 | cmd->header.size = cmd_len; | ||
969 | cmd->body.sid = srf->res.id; | ||
970 | cmd->body.surfaceFlags = srf->flags; | ||
971 | cmd->body.format = cpu_to_le32(srf->format); | ||
972 | cmd->body.numMipLevels = srf->mip_levels[0]; | ||
973 | cmd->body.multisampleCount = srf->multisample_count; | ||
974 | cmd->body.autogenFilter = srf->autogen_filter; | ||
975 | cmd->body.size.width = srf->base_size.width; | ||
976 | cmd->body.size.height = srf->base_size.height; | ||
977 | cmd->body.size.depth = srf->base_size.depth; | ||
978 | vmw_fifo_commit(dev_priv, submit_len); | ||
979 | |||
980 | return 0; | ||
981 | |||
982 | out_no_fifo: | ||
983 | vmw_resource_release_id(res); | ||
984 | out_no_id: | ||
985 | vmw_3d_resource_dec(dev_priv, false); | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | |||
990 | static int vmw_gb_surface_bind(struct vmw_resource *res, | ||
991 | struct ttm_validate_buffer *val_buf) | ||
992 | { | ||
993 | struct vmw_private *dev_priv = res->dev_priv; | ||
994 | struct { | ||
995 | SVGA3dCmdHeader header; | ||
996 | SVGA3dCmdBindGBSurface body; | ||
997 | } *cmd1; | ||
998 | struct { | ||
999 | SVGA3dCmdHeader header; | ||
1000 | SVGA3dCmdUpdateGBSurface body; | ||
1001 | } *cmd2; | ||
1002 | uint32_t submit_size; | ||
1003 | struct ttm_buffer_object *bo = val_buf->bo; | ||
1004 | |||
1005 | BUG_ON(bo->mem.mem_type != VMW_PL_MOB); | ||
1006 | |||
1007 | submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0); | ||
1008 | |||
1009 | cmd1 = vmw_fifo_reserve(dev_priv, submit_size); | ||
1010 | if (unlikely(cmd1 == NULL)) { | ||
1011 | DRM_ERROR("Failed reserving FIFO space for surface " | ||
1012 | "binding.\n"); | ||
1013 | return -ENOMEM; | ||
1014 | } | ||
1015 | |||
1016 | cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; | ||
1017 | cmd1->header.size = sizeof(cmd1->body); | ||
1018 | cmd1->body.sid = res->id; | ||
1019 | cmd1->body.mobid = bo->mem.start; | ||
1020 | if (res->backup_dirty) { | ||
1021 | cmd2 = (void *) &cmd1[1]; | ||
1022 | cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; | ||
1023 | cmd2->header.size = sizeof(cmd2->body); | ||
1024 | cmd2->body.sid = res->id; | ||
1025 | res->backup_dirty = false; | ||
1026 | } | ||
1027 | vmw_fifo_commit(dev_priv, submit_size); | ||
1028 | |||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static int vmw_gb_surface_unbind(struct vmw_resource *res, | ||
1033 | bool readback, | ||
1034 | struct ttm_validate_buffer *val_buf) | ||
1035 | { | ||
1036 | struct vmw_private *dev_priv = res->dev_priv; | ||
1037 | struct ttm_buffer_object *bo = val_buf->bo; | ||
1038 | struct vmw_fence_obj *fence; | ||
1039 | |||
1040 | struct { | ||
1041 | SVGA3dCmdHeader header; | ||
1042 | SVGA3dCmdReadbackGBSurface body; | ||
1043 | } *cmd1; | ||
1044 | struct { | ||
1045 | SVGA3dCmdHeader header; | ||
1046 | SVGA3dCmdInvalidateGBSurface body; | ||
1047 | } *cmd2; | ||
1048 | struct { | ||
1049 | SVGA3dCmdHeader header; | ||
1050 | SVGA3dCmdBindGBSurface body; | ||
1051 | } *cmd3; | ||
1052 | uint32_t submit_size; | ||
1053 | uint8_t *cmd; | ||
1054 | |||
1055 | |||
1056 | BUG_ON(bo->mem.mem_type != VMW_PL_MOB); | ||
1057 | |||
1058 | submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2)); | ||
1059 | cmd = vmw_fifo_reserve(dev_priv, submit_size); | ||
1060 | if (unlikely(cmd == NULL)) { | ||
1061 | DRM_ERROR("Failed reserving FIFO space for surface " | ||
1062 | "unbinding.\n"); | ||
1063 | return -ENOMEM; | ||
1064 | } | ||
1065 | |||
1066 | if (readback) { | ||
1067 | cmd1 = (void *) cmd; | ||
1068 | cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; | ||
1069 | cmd1->header.size = sizeof(cmd1->body); | ||
1070 | cmd1->body.sid = res->id; | ||
1071 | cmd3 = (void *) &cmd1[1]; | ||
1072 | } else { | ||
1073 | cmd2 = (void *) cmd; | ||
1074 | cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE; | ||
1075 | cmd2->header.size = sizeof(cmd2->body); | ||
1076 | cmd2->body.sid = res->id; | ||
1077 | cmd3 = (void *) &cmd2[1]; | ||
1078 | } | ||
1079 | |||
1080 | cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; | ||
1081 | cmd3->header.size = sizeof(cmd3->body); | ||
1082 | cmd3->body.sid = res->id; | ||
1083 | cmd3->body.mobid = SVGA3D_INVALID_ID; | ||
1084 | |||
1085 | vmw_fifo_commit(dev_priv, submit_size); | ||
1086 | |||
1087 | /* | ||
1088 | * Create a fence object and fence the backup buffer. | ||
1089 | */ | ||
1090 | |||
1091 | (void) vmw_execbuf_fence_commands(NULL, dev_priv, | ||
1092 | &fence, NULL); | ||
1093 | |||
1094 | vmw_fence_single_bo(val_buf->bo, fence); | ||
1095 | |||
1096 | if (likely(fence != NULL)) | ||
1097 | vmw_fence_obj_unreference(&fence); | ||
1098 | |||
1099 | return 0; | ||
1100 | } | ||
1101 | |||
1102 | static int vmw_gb_surface_destroy(struct vmw_resource *res) | ||
1103 | { | ||
1104 | struct vmw_private *dev_priv = res->dev_priv; | ||
1105 | struct { | ||
1106 | SVGA3dCmdHeader header; | ||
1107 | SVGA3dCmdDestroyGBSurface body; | ||
1108 | } *cmd; | ||
1109 | |||
1110 | if (likely(res->id == -1)) | ||
1111 | return 0; | ||
1112 | |||
1113 | mutex_lock(&dev_priv->binding_mutex); | ||
1114 | vmw_context_binding_res_list_kill(&res->binding_head); | ||
1115 | |||
1116 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | ||
1117 | if (unlikely(cmd == NULL)) { | ||
1118 | DRM_ERROR("Failed reserving FIFO space for surface " | ||
1119 | "destruction.\n"); | ||
1120 | return -ENOMEM; | ||
1121 | } | ||
1122 | |||
1123 | cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE; | ||
1124 | cmd->header.size = sizeof(cmd->body); | ||
1125 | cmd->body.sid = res->id; | ||
1126 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | ||
1127 | mutex_unlock(&dev_priv->binding_mutex); | ||
1128 | vmw_resource_release_id(res); | ||
1129 | vmw_3d_resource_dec(dev_priv, false); | ||
1130 | |||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | /** | ||
1135 | * vmw_gb_surface_define_ioctl - Ioctl function implementing | ||
1136 | * the user surface define functionality. | ||
1137 | * | ||
1138 | * @dev: Pointer to a struct drm_device. | ||
1139 | * @data: Pointer to data copied from / to user-space. | ||
1140 | * @file_priv: Pointer to a drm file private structure. | ||
1141 | */ | ||
1142 | int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, | ||
1143 | struct drm_file *file_priv) | ||
1144 | { | ||
1145 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1146 | struct vmw_user_surface *user_srf; | ||
1147 | struct vmw_surface *srf; | ||
1148 | struct vmw_resource *res; | ||
1149 | struct vmw_resource *tmp; | ||
1150 | union drm_vmw_gb_surface_create_arg *arg = | ||
1151 | (union drm_vmw_gb_surface_create_arg *)data; | ||
1152 | struct drm_vmw_gb_surface_create_req *req = &arg->req; | ||
1153 | struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; | ||
1154 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
1155 | int ret; | ||
1156 | uint32_t size; | ||
1157 | struct vmw_master *vmaster = vmw_master(file_priv->master); | ||
1158 | const struct svga3d_surface_desc *desc; | ||
1159 | uint32_t backup_handle; | ||
1160 | |||
1161 | if (unlikely(vmw_user_surface_size == 0)) | ||
1162 | vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + | ||
1163 | 128; | ||
1164 | |||
1165 | size = vmw_user_surface_size + 128; | ||
1166 | |||
1167 | desc = svga3dsurface_get_desc(req->format); | ||
1168 | if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { | ||
1169 | DRM_ERROR("Invalid surface format for surface creation.\n"); | ||
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | |||
1173 | ret = ttm_read_lock(&vmaster->lock, true); | ||
1174 | if (unlikely(ret != 0)) | ||
1175 | return ret; | ||
1176 | |||
1177 | ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), | ||
1178 | size, false, true); | ||
1179 | if (unlikely(ret != 0)) { | ||
1180 | if (ret != -ERESTARTSYS) | ||
1181 | DRM_ERROR("Out of graphics memory for surface" | ||
1182 | " creation.\n"); | ||
1183 | goto out_unlock; | ||
1184 | } | ||
1185 | |||
1186 | user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); | ||
1187 | if (unlikely(user_srf == NULL)) { | ||
1188 | ret = -ENOMEM; | ||
1189 | goto out_no_user_srf; | ||
1190 | } | ||
1191 | |||
1192 | srf = &user_srf->srf; | ||
1193 | res = &srf->res; | ||
1194 | |||
1195 | srf->flags = req->svga3d_flags; | ||
1196 | srf->format = req->format; | ||
1197 | srf->scanout = req->drm_surface_flags & drm_vmw_surface_flag_scanout; | ||
1198 | srf->mip_levels[0] = req->mip_levels; | ||
1199 | srf->num_sizes = 1; | ||
1200 | srf->sizes = NULL; | ||
1201 | srf->offsets = NULL; | ||
1202 | user_srf->size = size; | ||
1203 | srf->base_size = req->base_size; | ||
1204 | srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; | ||
1205 | srf->multisample_count = req->multisample_count; | ||
1206 | res->backup_size = svga3dsurface_get_serialized_size | ||
1207 | (srf->format, srf->base_size, srf->mip_levels[0], | ||
1208 | srf->flags & SVGA3D_SURFACE_CUBEMAP); | ||
1209 | |||
1210 | user_srf->prime.base.shareable = false; | ||
1211 | user_srf->prime.base.tfile = NULL; | ||
1212 | |||
1213 | /** | ||
1214 | * From this point, the generic resource management functions | ||
1215 | * destroy the object on failure. | ||
1216 | */ | ||
1217 | |||
1218 | ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); | ||
1219 | if (unlikely(ret != 0)) | ||
1220 | goto out_unlock; | ||
1221 | |||
1222 | if (req->buffer_handle != SVGA3D_INVALID_ID) { | ||
1223 | ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, | ||
1224 | &res->backup); | ||
1225 | } else if (req->drm_surface_flags & | ||
1226 | drm_vmw_surface_flag_create_buffer) | ||
1227 | ret = vmw_user_dmabuf_alloc(dev_priv, tfile, | ||
1228 | res->backup_size, | ||
1229 | req->drm_surface_flags & | ||
1230 | drm_vmw_surface_flag_shareable, | ||
1231 | &backup_handle, | ||
1232 | &res->backup); | ||
1233 | |||
1234 | if (unlikely(ret != 0)) { | ||
1235 | vmw_resource_unreference(&res); | ||
1236 | goto out_unlock; | ||
1237 | } | ||
1238 | |||
1239 | tmp = vmw_resource_reference(&srf->res); | ||
1240 | ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, | ||
1241 | req->drm_surface_flags & | ||
1242 | drm_vmw_surface_flag_shareable, | ||
1243 | VMW_RES_SURFACE, | ||
1244 | &vmw_user_surface_base_release, NULL); | ||
1245 | |||
1246 | if (unlikely(ret != 0)) { | ||
1247 | vmw_resource_unreference(&tmp); | ||
1248 | vmw_resource_unreference(&res); | ||
1249 | goto out_unlock; | ||
1250 | } | ||
1251 | |||
1252 | rep->handle = user_srf->prime.base.hash.key; | ||
1253 | rep->backup_size = res->backup_size; | ||
1254 | if (res->backup) { | ||
1255 | rep->buffer_map_handle = | ||
1256 | drm_vma_node_offset_addr(&res->backup->base.vma_node); | ||
1257 | rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; | ||
1258 | rep->buffer_handle = backup_handle; | ||
1259 | } else { | ||
1260 | rep->buffer_map_handle = 0; | ||
1261 | rep->buffer_size = 0; | ||
1262 | rep->buffer_handle = SVGA3D_INVALID_ID; | ||
1263 | } | ||
1264 | |||
1265 | vmw_resource_unreference(&res); | ||
1266 | |||
1267 | ttm_read_unlock(&vmaster->lock); | ||
1268 | return 0; | ||
1269 | out_no_user_srf: | ||
1270 | ttm_mem_global_free(vmw_mem_glob(dev_priv), size); | ||
1271 | out_unlock: | ||
1272 | ttm_read_unlock(&vmaster->lock); | ||
1273 | return ret; | ||
1274 | } | ||
1275 | |||
1276 | /** | ||
1277 | * vmw_gb_surface_reference_ioctl - Ioctl function implementing | ||
1278 | * the user surface reference functionality. | ||
1279 | * | ||
1280 | * @dev: Pointer to a struct drm_device. | ||
1281 | * @data: Pointer to data copied from / to user-space. | ||
1282 | * @file_priv: Pointer to a drm file private structure. | ||
1283 | */ | ||
1284 | int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, | ||
1285 | struct drm_file *file_priv) | ||
1286 | { | ||
1287 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
1288 | union drm_vmw_gb_surface_reference_arg *arg = | ||
1289 | (union drm_vmw_gb_surface_reference_arg *)data; | ||
1290 | struct drm_vmw_surface_arg *req = &arg->req; | ||
1291 | struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; | ||
1292 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | ||
1293 | struct vmw_surface *srf; | ||
1294 | struct vmw_user_surface *user_srf; | ||
1295 | struct ttm_base_object *base; | ||
1296 | uint32_t backup_handle; | ||
1297 | int ret = -EINVAL; | ||
1298 | |||
1299 | base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); | ||
1300 | if (unlikely(base == NULL)) { | ||
1301 | DRM_ERROR("Could not find surface to reference.\n"); | ||
1302 | return -EINVAL; | ||
1303 | } | ||
1304 | |||
1305 | if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) | ||
1306 | goto out_bad_resource; | ||
1307 | |||
1308 | user_srf = container_of(base, struct vmw_user_surface, prime.base); | ||
1309 | srf = &user_srf->srf; | ||
1310 | if (srf->res.backup == NULL) { | ||
1311 | DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); | ||
1312 | goto out_bad_resource; | ||
1313 | } | ||
1314 | |||
1315 | ret = ttm_ref_object_add(tfile, &user_srf->prime.base, | ||
1316 | TTM_REF_USAGE, NULL); | ||
1317 | if (unlikely(ret != 0)) { | ||
1318 | DRM_ERROR("Could not add a reference to a GB surface.\n"); | ||
1319 | goto out_bad_resource; | ||
1320 | } | ||
1321 | |||
1322 | mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ | ||
1323 | ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, | ||
1324 | &backup_handle); | ||
1325 | mutex_unlock(&dev_priv->cmdbuf_mutex); | ||
1326 | |||
1327 | if (unlikely(ret != 0)) { | ||
1328 | DRM_ERROR("Could not add a reference to a GB surface " | ||
1329 | "backup buffer.\n"); | ||
1330 | (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, | ||
1331 | req->sid, | ||
1332 | TTM_REF_USAGE); | ||
1333 | goto out_bad_resource; | ||
1334 | } | ||
1335 | |||
1336 | rep->creq.svga3d_flags = srf->flags; | ||
1337 | rep->creq.format = srf->format; | ||
1338 | rep->creq.mip_levels = srf->mip_levels[0]; | ||
1339 | rep->creq.drm_surface_flags = 0; | ||
1340 | rep->creq.multisample_count = srf->multisample_count; | ||
1341 | rep->creq.autogen_filter = srf->autogen_filter; | ||
1342 | rep->creq.buffer_handle = backup_handle; | ||
1343 | rep->creq.base_size = srf->base_size; | ||
1344 | rep->crep.handle = user_srf->prime.base.hash.key; | ||
1345 | rep->crep.backup_size = srf->res.backup_size; | ||
1346 | rep->crep.buffer_handle = backup_handle; | ||
1347 | rep->crep.buffer_map_handle = | ||
1348 | drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); | ||
1349 | rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; | ||
1350 | |||
1351 | out_bad_resource: | ||
1352 | ttm_base_object_unref(&base); | ||
1353 | |||
1354 | return ret; | ||
1355 | } | ||