aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_surface.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c467
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);
69static int vmw_legacy_srf_create(struct vmw_resource *res); 68static int vmw_legacy_srf_create(struct vmw_resource *res);
70static int vmw_legacy_srf_destroy(struct vmw_resource *res); 69static int vmw_legacy_srf_destroy(struct vmw_resource *res);
70static int vmw_gb_surface_create(struct vmw_resource *res);
71static int vmw_gb_surface_bind(struct vmw_resource *res,
72 struct ttm_validate_buffer *val_buf);
73static int vmw_gb_surface_unbind(struct vmw_resource *res,
74 bool readback,
75 struct ttm_validate_buffer *val_buf);
76static int vmw_gb_surface_destroy(struct vmw_resource *res);
77
71 78
72static const struct vmw_user_resource_conv user_surface_conv = { 79static 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
103static 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 */
931static 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
982out_no_fifo:
983 vmw_resource_release_id(res);
984out_no_id:
985 vmw_3d_resource_dec(dev_priv, false);
986 return ret;
987}
988
989
990static 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
1032static 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
1102static 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 */
1142int 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;
1269out_no_user_srf:
1270 ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
1271out_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 */
1284int 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
1351out_bad_resource:
1352 ttm_base_object_unref(&base);
1353
1354 return ret;
1355}