diff options
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 153 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 149 |
4 files changed, 209 insertions, 111 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 43546d09d1b0..e61bd85b6975 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
| @@ -123,6 +123,7 @@ struct vmw_sw_context{ | |||
| 123 | uint32_t last_cid; | 123 | uint32_t last_cid; |
| 124 | bool cid_valid; | 124 | bool cid_valid; |
| 125 | uint32_t last_sid; | 125 | uint32_t last_sid; |
| 126 | uint32_t sid_translation; | ||
| 126 | bool sid_valid; | 127 | bool sid_valid; |
| 127 | struct ttm_object_file *tfile; | 128 | struct ttm_object_file *tfile; |
| 128 | struct list_head validate_nodes; | 129 | struct list_head validate_nodes; |
| @@ -317,9 +318,10 @@ extern void vmw_surface_res_free(struct vmw_resource *res); | |||
| 317 | extern int vmw_surface_init(struct vmw_private *dev_priv, | 318 | extern int vmw_surface_init(struct vmw_private *dev_priv, |
| 318 | struct vmw_surface *srf, | 319 | struct vmw_surface *srf, |
| 319 | void (*res_free) (struct vmw_resource *res)); | 320 | void (*res_free) (struct vmw_resource *res)); |
| 320 | extern int vmw_user_surface_lookup(struct vmw_private *dev_priv, | 321 | extern int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, |
| 321 | struct ttm_object_file *tfile, | 322 | struct ttm_object_file *tfile, |
| 322 | int sid, struct vmw_surface **out); | 323 | uint32_t handle, |
| 324 | struct vmw_surface **out); | ||
| 323 | extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, | 325 | extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, |
| 324 | struct drm_file *file_priv); | 326 | struct drm_file *file_priv); |
| 325 | extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | 327 | extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data, |
| @@ -328,7 +330,7 @@ extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
| 328 | struct drm_file *file_priv); | 330 | struct drm_file *file_priv); |
| 329 | extern int vmw_surface_check(struct vmw_private *dev_priv, | 331 | extern int vmw_surface_check(struct vmw_private *dev_priv, |
| 330 | struct ttm_object_file *tfile, | 332 | struct ttm_object_file *tfile, |
| 331 | int id); | 333 | uint32_t handle, int *id); |
| 332 | extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); | 334 | extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); |
| 333 | extern int vmw_dmabuf_init(struct vmw_private *dev_priv, | 335 | extern int vmw_dmabuf_init(struct vmw_private *dev_priv, |
| 334 | struct vmw_dma_buffer *vmw_bo, | 336 | struct vmw_dma_buffer *vmw_bo, |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 7e73cf51e298..2e92da567403 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
| @@ -73,21 +73,32 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv, | |||
| 73 | 73 | ||
| 74 | static int vmw_cmd_sid_check(struct vmw_private *dev_priv, | 74 | static int vmw_cmd_sid_check(struct vmw_private *dev_priv, |
| 75 | struct vmw_sw_context *sw_context, | 75 | struct vmw_sw_context *sw_context, |
| 76 | uint32_t sid) | 76 | uint32_t *sid) |
| 77 | { | 77 | { |
| 78 | if (unlikely((!sw_context->sid_valid || sid != sw_context->last_sid) && | 78 | if (*sid == SVGA3D_INVALID_ID) |
| 79 | sid != SVGA3D_INVALID_ID)) { | 79 | return 0; |
| 80 | int ret = vmw_surface_check(dev_priv, sw_context->tfile, sid); | 80 | |
| 81 | if (unlikely((!sw_context->sid_valid || | ||
| 82 | *sid != sw_context->last_sid))) { | ||
| 83 | int real_id; | ||
| 84 | int ret = vmw_surface_check(dev_priv, sw_context->tfile, | ||
| 85 | *sid, &real_id); | ||
| 81 | 86 | ||
| 82 | if (unlikely(ret != 0)) { | 87 | if (unlikely(ret != 0)) { |
| 83 | DRM_ERROR("Could ot find or use surface %u\n", | 88 | DRM_ERROR("Could ot find or use surface 0x%08x " |
| 84 | (unsigned) sid); | 89 | "address 0x%08lx\n", |
| 90 | (unsigned int) *sid, | ||
| 91 | (unsigned long) sid); | ||
| 85 | return ret; | 92 | return ret; |
| 86 | } | 93 | } |
| 87 | 94 | ||
| 88 | sw_context->last_sid = sid; | 95 | sw_context->last_sid = *sid; |
| 89 | sw_context->sid_valid = true; | 96 | sw_context->sid_valid = true; |
| 90 | } | 97 | *sid = real_id; |
| 98 | sw_context->sid_translation = real_id; | ||
| 99 | } else | ||
| 100 | *sid = sw_context->sid_translation; | ||
| 101 | |||
| 91 | return 0; | 102 | return 0; |
| 92 | } | 103 | } |
| 93 | 104 | ||
| @@ -107,7 +118,8 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv, | |||
| 107 | return ret; | 118 | return ret; |
| 108 | 119 | ||
| 109 | cmd = container_of(header, struct vmw_sid_cmd, header); | 120 | cmd = container_of(header, struct vmw_sid_cmd, header); |
| 110 | return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.target.sid); | 121 | ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.target.sid); |
| 122 | return ret; | ||
| 111 | } | 123 | } |
| 112 | 124 | ||
| 113 | static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, | 125 | static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, |
| @@ -121,10 +133,10 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, | |||
| 121 | int ret; | 133 | int ret; |
| 122 | 134 | ||
| 123 | cmd = container_of(header, struct vmw_sid_cmd, header); | 135 | cmd = container_of(header, struct vmw_sid_cmd, header); |
| 124 | ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid); | 136 | ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid); |
| 125 | if (unlikely(ret != 0)) | 137 | if (unlikely(ret != 0)) |
| 126 | return ret; | 138 | return ret; |
| 127 | return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid); | 139 | return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid); |
| 128 | } | 140 | } |
| 129 | 141 | ||
| 130 | static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv, | 142 | static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv, |
| @@ -138,10 +150,10 @@ static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv, | |||
| 138 | int ret; | 150 | int ret; |
| 139 | 151 | ||
| 140 | cmd = container_of(header, struct vmw_sid_cmd, header); | 152 | cmd = container_of(header, struct vmw_sid_cmd, header); |
| 141 | ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid); | 153 | ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid); |
| 142 | if (unlikely(ret != 0)) | 154 | if (unlikely(ret != 0)) |
| 143 | return ret; | 155 | return ret; |
| 144 | return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid); | 156 | return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid); |
| 145 | } | 157 | } |
| 146 | 158 | ||
| 147 | static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv, | 159 | static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv, |
| @@ -154,7 +166,7 @@ static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv, | |||
| 154 | } *cmd; | 166 | } *cmd; |
| 155 | 167 | ||
| 156 | cmd = container_of(header, struct vmw_sid_cmd, header); | 168 | cmd = container_of(header, struct vmw_sid_cmd, header); |
| 157 | return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.srcImage.sid); | 169 | return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.srcImage.sid); |
| 158 | } | 170 | } |
| 159 | 171 | ||
| 160 | static int vmw_cmd_present_check(struct vmw_private *dev_priv, | 172 | static int vmw_cmd_present_check(struct vmw_private *dev_priv, |
| @@ -167,7 +179,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv, | |||
| 167 | } *cmd; | 179 | } *cmd; |
| 168 | 180 | ||
| 169 | cmd = container_of(header, struct vmw_sid_cmd, header); | 181 | cmd = container_of(header, struct vmw_sid_cmd, header); |
| 170 | return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.sid); | 182 | return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid); |
| 171 | } | 183 | } |
| 172 | 184 | ||
| 173 | static int vmw_cmd_dma(struct vmw_private *dev_priv, | 185 | static int vmw_cmd_dma(struct vmw_private *dev_priv, |
| @@ -187,12 +199,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, | |||
| 187 | uint32_t cur_validate_node; | 199 | uint32_t cur_validate_node; |
| 188 | struct ttm_validate_buffer *val_buf; | 200 | struct ttm_validate_buffer *val_buf; |
| 189 | 201 | ||
| 190 | |||
| 191 | cmd = container_of(header, struct vmw_dma_cmd, header); | 202 | cmd = container_of(header, struct vmw_dma_cmd, header); |
| 192 | ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->dma.host.sid); | ||
| 193 | if (unlikely(ret != 0)) | ||
| 194 | return ret; | ||
| 195 | |||
| 196 | handle = cmd->dma.guest.ptr.gmrId; | 203 | handle = cmd->dma.guest.ptr.gmrId; |
| 197 | ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo); | 204 | ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo); |
| 198 | if (unlikely(ret != 0)) { | 205 | if (unlikely(ret != 0)) { |
| @@ -228,14 +235,23 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, | |||
| 228 | ++sw_context->cur_val_buf; | 235 | ++sw_context->cur_val_buf; |
| 229 | } | 236 | } |
| 230 | 237 | ||
| 231 | ret = vmw_user_surface_lookup(dev_priv, sw_context->tfile, | 238 | ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile, |
| 232 | cmd->dma.host.sid, &srf); | 239 | cmd->dma.host.sid, &srf); |
| 233 | if (ret) { | 240 | if (ret) { |
| 234 | DRM_ERROR("could not find surface\n"); | 241 | DRM_ERROR("could not find surface\n"); |
| 235 | goto out_no_reloc; | 242 | goto out_no_reloc; |
| 236 | } | 243 | } |
| 237 | 244 | ||
| 245 | /** | ||
| 246 | * Patch command stream with device SID. | ||
| 247 | */ | ||
| 248 | |||
| 249 | cmd->dma.host.sid = srf->res.id; | ||
| 238 | vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header); | 250 | vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header); |
| 251 | /** | ||
| 252 | * FIXME: May deadlock here when called from the | ||
| 253 | * command parsing code. | ||
| 254 | */ | ||
| 239 | vmw_surface_unreference(&srf); | 255 | vmw_surface_unreference(&srf); |
| 240 | 256 | ||
| 241 | out_no_reloc: | 257 | out_no_reloc: |
| @@ -243,6 +259,90 @@ out_no_reloc: | |||
| 243 | return ret; | 259 | return ret; |
| 244 | } | 260 | } |
| 245 | 261 | ||
| 262 | static int vmw_cmd_draw(struct vmw_private *dev_priv, | ||
| 263 | struct vmw_sw_context *sw_context, | ||
| 264 | SVGA3dCmdHeader *header) | ||
| 265 | { | ||
| 266 | struct vmw_draw_cmd { | ||
| 267 | SVGA3dCmdHeader header; | ||
| 268 | SVGA3dCmdDrawPrimitives body; | ||
| 269 | } *cmd; | ||
| 270 | SVGA3dVertexDecl *decl = (SVGA3dVertexDecl *)( | ||
| 271 | (unsigned long)header + sizeof(*cmd)); | ||
| 272 | SVGA3dPrimitiveRange *range; | ||
| 273 | uint32_t i; | ||
| 274 | uint32_t maxnum; | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | ret = vmw_cmd_cid_check(dev_priv, sw_context, header); | ||
| 278 | if (unlikely(ret != 0)) | ||
| 279 | return ret; | ||
| 280 | |||
| 281 | cmd = container_of(header, struct vmw_draw_cmd, header); | ||
| 282 | maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl); | ||
| 283 | |||
| 284 | if (unlikely(cmd->body.numVertexDecls > maxnum)) { | ||
| 285 | DRM_ERROR("Illegal number of vertex declarations.\n"); | ||
| 286 | return -EINVAL; | ||
| 287 | } | ||
| 288 | |||
| 289 | for (i = 0; i < cmd->body.numVertexDecls; ++i, ++decl) { | ||
| 290 | ret = vmw_cmd_sid_check(dev_priv, sw_context, | ||
| 291 | &decl->array.surfaceId); | ||
| 292 | if (unlikely(ret != 0)) | ||
| 293 | return ret; | ||
| 294 | } | ||
| 295 | |||
| 296 | maxnum = (header->size - sizeof(cmd->body) - | ||
| 297 | cmd->body.numVertexDecls * sizeof(*decl)) / sizeof(*range); | ||
| 298 | if (unlikely(cmd->body.numRanges > maxnum)) { | ||
| 299 | DRM_ERROR("Illegal number of index ranges.\n"); | ||
| 300 | return -EINVAL; | ||
| 301 | } | ||
| 302 | |||
| 303 | range = (SVGA3dPrimitiveRange *) decl; | ||
| 304 | for (i = 0; i < cmd->body.numRanges; ++i, ++range) { | ||
| 305 | ret = vmw_cmd_sid_check(dev_priv, sw_context, | ||
| 306 | &range->indexArray.surfaceId); | ||
| 307 | if (unlikely(ret != 0)) | ||
| 308 | return ret; | ||
| 309 | } | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | static int vmw_cmd_tex_state(struct vmw_private *dev_priv, | ||
| 315 | struct vmw_sw_context *sw_context, | ||
| 316 | SVGA3dCmdHeader *header) | ||
| 317 | { | ||
| 318 | struct vmw_tex_state_cmd { | ||
| 319 | SVGA3dCmdHeader header; | ||
| 320 | SVGA3dCmdSetTextureState state; | ||
| 321 | }; | ||
| 322 | |||
| 323 | SVGA3dTextureState *last_state = (SVGA3dTextureState *) | ||
| 324 | ((unsigned long) header + header->size + sizeof(header)); | ||
| 325 | SVGA3dTextureState *cur_state = (SVGA3dTextureState *) | ||
| 326 | ((unsigned long) header + sizeof(struct vmw_tex_state_cmd)); | ||
| 327 | int ret; | ||
| 328 | |||
| 329 | ret = vmw_cmd_cid_check(dev_priv, sw_context, header); | ||
| 330 | if (unlikely(ret != 0)) | ||
| 331 | return ret; | ||
| 332 | |||
| 333 | for (; cur_state < last_state; ++cur_state) { | ||
| 334 | if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE)) | ||
| 335 | continue; | ||
| 336 | |||
| 337 | ret = vmw_cmd_sid_check(dev_priv, sw_context, | ||
| 338 | &cur_state->value); | ||
| 339 | if (unlikely(ret != 0)) | ||
| 340 | return ret; | ||
| 341 | } | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 246 | 346 | ||
| 247 | typedef int (*vmw_cmd_func) (struct vmw_private *, | 347 | typedef int (*vmw_cmd_func) (struct vmw_private *, |
| 248 | struct vmw_sw_context *, | 348 | struct vmw_sw_context *, |
| @@ -264,7 +364,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = { | |||
| 264 | VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check), | 364 | VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check), |
| 265 | VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET, | 365 | VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET, |
| 266 | &vmw_cmd_set_render_target_check), | 366 | &vmw_cmd_set_render_target_check), |
| 267 | VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_cid_check), | 367 | VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state), |
| 268 | VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check), | 368 | VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check), |
| 269 | VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check), | 369 | VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check), |
| 270 | VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check), | 370 | VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check), |
| @@ -276,7 +376,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = { | |||
| 276 | VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check), | 376 | VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check), |
| 277 | VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check), | 377 | VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check), |
| 278 | VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check), | 378 | VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check), |
| 279 | VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_cid_check), | 379 | VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw), |
| 280 | VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check), | 380 | VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check), |
| 281 | VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check), | 381 | VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check), |
| 282 | VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check), | 382 | VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check), |
| @@ -291,6 +391,7 @@ static int vmw_cmd_check(struct vmw_private *dev_priv, | |||
| 291 | void *buf, uint32_t *size) | 391 | void *buf, uint32_t *size) |
| 292 | { | 392 | { |
| 293 | uint32_t cmd_id; | 393 | uint32_t cmd_id; |
| 394 | uint32_t size_remaining = *size; | ||
| 294 | SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf; | 395 | SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf; |
| 295 | int ret; | 396 | int ret; |
| 296 | 397 | ||
| @@ -304,6 +405,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv, | |||
| 304 | *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader); | 405 | *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader); |
| 305 | 406 | ||
| 306 | cmd_id -= SVGA_3D_CMD_BASE; | 407 | cmd_id -= SVGA_3D_CMD_BASE; |
| 408 | if (unlikely(*size > size_remaining)) | ||
| 409 | goto out_err; | ||
| 410 | |||
| 307 | if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE)) | 411 | if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE)) |
| 308 | goto out_err; | 412 | goto out_err; |
| 309 | 413 | ||
| @@ -326,6 +430,7 @@ static int vmw_cmd_check_all(struct vmw_private *dev_priv, | |||
| 326 | int ret; | 430 | int ret; |
| 327 | 431 | ||
| 328 | while (cur_size > 0) { | 432 | while (cur_size > 0) { |
| 433 | size = cur_size; | ||
| 329 | ret = vmw_cmd_check(dev_priv, sw_context, buf, &size); | 434 | ret = vmw_cmd_check(dev_priv, sw_context, buf, &size); |
| 330 | if (unlikely(ret != 0)) | 435 | if (unlikely(ret != 0)) |
| 331 | return ret; | 436 | return ret; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index e9403be446fe..b1af76e371c3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
| @@ -106,8 +106,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | |||
| 106 | int ret; | 106 | int ret; |
| 107 | 107 | ||
| 108 | if (handle) { | 108 | if (handle) { |
| 109 | ret = vmw_user_surface_lookup(dev_priv, tfile, | 109 | ret = vmw_user_surface_lookup_handle(dev_priv, tfile, |
| 110 | handle, &surface); | 110 | handle, &surface); |
| 111 | if (!ret) { | 111 | if (!ret) { |
| 112 | if (!surface->snooper.image) { | 112 | if (!surface->snooper.image) { |
| 113 | DRM_ERROR("surface not suitable for cursor\n"); | 113 | DRM_ERROR("surface not suitable for cursor\n"); |
| @@ -704,8 +704,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, | |||
| 704 | struct vmw_dma_buffer *bo = NULL; | 704 | struct vmw_dma_buffer *bo = NULL; |
| 705 | int ret; | 705 | int ret; |
| 706 | 706 | ||
| 707 | ret = vmw_user_surface_lookup(dev_priv, tfile, | 707 | ret = vmw_user_surface_lookup_handle(dev_priv, tfile, |
| 708 | mode_cmd->handle, &surface); | 708 | mode_cmd->handle, &surface); |
| 709 | if (ret) | 709 | if (ret) |
| 710 | goto try_dmabuf; | 710 | goto try_dmabuf; |
| 711 | 711 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index a1ceed0c8e07..c012d5927f65 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
| @@ -488,28 +488,44 @@ static void vmw_user_surface_free(struct vmw_resource *res) | |||
| 488 | kfree(user_srf); | 488 | kfree(user_srf); |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | int vmw_user_surface_lookup(struct vmw_private *dev_priv, | 491 | int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, |
| 492 | struct ttm_object_file *tfile, | 492 | struct ttm_object_file *tfile, |
| 493 | int sid, struct vmw_surface **out) | 493 | uint32_t handle, struct vmw_surface **out) |
| 494 | { | 494 | { |
| 495 | struct vmw_resource *res; | 495 | struct vmw_resource *res; |
| 496 | struct vmw_surface *srf; | 496 | struct vmw_surface *srf; |
| 497 | struct vmw_user_surface *user_srf; | 497 | struct vmw_user_surface *user_srf; |
| 498 | struct ttm_base_object *base; | ||
| 499 | int ret = -EINVAL; | ||
| 498 | 500 | ||
| 499 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, sid); | 501 | base = ttm_base_object_lookup(tfile, handle); |
| 500 | if (unlikely(res == NULL)) | 502 | if (unlikely(base == NULL)) |
| 501 | return -EINVAL; | 503 | return -EINVAL; |
| 502 | 504 | ||
| 503 | if (res->res_free != &vmw_user_surface_free) | 505 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
| 504 | return -EINVAL; | 506 | goto out_bad_resource; |
| 505 | 507 | ||
| 506 | srf = container_of(res, struct vmw_surface, res); | 508 | user_srf = container_of(base, struct vmw_user_surface, base); |
| 507 | user_srf = container_of(srf, struct vmw_user_surface, srf); | 509 | srf = &user_srf->srf; |
| 508 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) | 510 | res = &srf->res; |
| 509 | return -EPERM; | 511 | |
| 512 | read_lock(&dev_priv->resource_lock); | ||
| 513 | |||
| 514 | if (!res->avail || res->res_free != &vmw_user_surface_free) { | ||
| 515 | read_unlock(&dev_priv->resource_lock); | ||
| 516 | goto out_bad_resource; | ||
| 517 | } | ||
| 518 | |||
| 519 | kref_get(&res->kref); | ||
| 520 | read_unlock(&dev_priv->resource_lock); | ||
| 510 | 521 | ||
| 511 | *out = srf; | 522 | *out = srf; |
| 512 | return 0; | 523 | ret = 0; |
| 524 | |||
| 525 | out_bad_resource: | ||
| 526 | ttm_base_object_unref(&base); | ||
| 527 | |||
| 528 | return ret; | ||
| 513 | } | 529 | } |
| 514 | 530 | ||
| 515 | static void vmw_user_surface_base_release(struct ttm_base_object **p_base) | 531 | static void vmw_user_surface_base_release(struct ttm_base_object **p_base) |
| @@ -526,35 +542,10 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) | |||
| 526 | int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, | 542 | int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, |
| 527 | struct drm_file *file_priv) | 543 | struct drm_file *file_priv) |
| 528 | { | 544 | { |
| 529 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
| 530 | struct vmw_resource *res; | ||
| 531 | struct vmw_surface *srf; | ||
| 532 | struct vmw_user_surface *user_srf; | ||
| 533 | struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; | 545 | struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; |
| 534 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 546 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
| 535 | int ret = 0; | ||
| 536 | |||
| 537 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, arg->sid); | ||
| 538 | if (unlikely(res == NULL)) | ||
| 539 | return -EINVAL; | ||
| 540 | |||
| 541 | if (res->res_free != &vmw_user_surface_free) { | ||
| 542 | ret = -EINVAL; | ||
| 543 | goto out; | ||
| 544 | } | ||
| 545 | 547 | ||
| 546 | srf = container_of(res, struct vmw_surface, res); | 548 | return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE); |
| 547 | user_srf = container_of(srf, struct vmw_user_surface, srf); | ||
| 548 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) { | ||
| 549 | ret = -EPERM; | ||
| 550 | goto out; | ||
| 551 | } | ||
| 552 | |||
| 553 | ttm_ref_object_base_unref(tfile, user_srf->base.hash.key, | ||
| 554 | TTM_REF_USAGE); | ||
| 555 | out: | ||
| 556 | vmw_resource_unreference(&res); | ||
| 557 | return ret; | ||
| 558 | } | 549 | } |
| 559 | 550 | ||
| 560 | int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | 551 | int vmw_surface_define_ioctl(struct drm_device *dev, void *data, |
| @@ -649,7 +640,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | |||
| 649 | } | 640 | } |
| 650 | srf->snooper.crtc = NULL; | 641 | srf->snooper.crtc = NULL; |
| 651 | 642 | ||
| 652 | rep->sid = res->id; | 643 | rep->sid = user_srf->base.hash.key; |
| 644 | if (rep->sid == SVGA3D_INVALID_ID) | ||
| 645 | DRM_ERROR("Created bad Surface ID.\n"); | ||
| 646 | |||
| 653 | vmw_resource_unreference(&res); | 647 | vmw_resource_unreference(&res); |
| 654 | return 0; | 648 | return 0; |
| 655 | out_err1: | 649 | out_err1: |
| @@ -662,39 +656,33 @@ out_err0: | |||
| 662 | int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | 656 | int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, |
| 663 | struct drm_file *file_priv) | 657 | struct drm_file *file_priv) |
| 664 | { | 658 | { |
| 665 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
| 666 | union drm_vmw_surface_reference_arg *arg = | 659 | union drm_vmw_surface_reference_arg *arg = |
| 667 | (union drm_vmw_surface_reference_arg *)data; | 660 | (union drm_vmw_surface_reference_arg *)data; |
| 668 | struct drm_vmw_surface_arg *req = &arg->req; | 661 | struct drm_vmw_surface_arg *req = &arg->req; |
| 669 | struct drm_vmw_surface_create_req *rep = &arg->rep; | 662 | struct drm_vmw_surface_create_req *rep = &arg->rep; |
| 670 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 663 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
| 671 | struct vmw_resource *res; | ||
| 672 | struct vmw_surface *srf; | 664 | struct vmw_surface *srf; |
| 673 | struct vmw_user_surface *user_srf; | 665 | struct vmw_user_surface *user_srf; |
| 674 | struct drm_vmw_size __user *user_sizes; | 666 | struct drm_vmw_size __user *user_sizes; |
| 675 | int ret; | 667 | struct ttm_base_object *base; |
| 668 | int ret = -EINVAL; | ||
| 676 | 669 | ||
| 677 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, req->sid); | 670 | base = ttm_base_object_lookup(tfile, req->sid); |
| 678 | if (unlikely(res == NULL)) | 671 | if (unlikely(base == NULL)) { |
| 672 | DRM_ERROR("Could not find surface to reference.\n"); | ||
| 679 | return -EINVAL; | 673 | return -EINVAL; |
| 680 | |||
| 681 | if (res->res_free != &vmw_user_surface_free) { | ||
| 682 | ret = -EINVAL; | ||
| 683 | goto out; | ||
| 684 | } | 674 | } |
| 685 | 675 | ||
| 686 | srf = container_of(res, struct vmw_surface, res); | 676 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
| 687 | user_srf = container_of(srf, struct vmw_user_surface, srf); | 677 | goto out_bad_resource; |
| 688 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) { | 678 | |
| 689 | DRM_ERROR("Tried to reference none shareable surface\n"); | 679 | user_srf = container_of(base, struct vmw_user_surface, base); |
| 690 | ret = -EPERM; | 680 | srf = &user_srf->srf; |
| 691 | goto out; | ||
| 692 | } | ||
| 693 | 681 | ||
| 694 | ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL); | 682 | ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL); |
| 695 | if (unlikely(ret != 0)) { | 683 | if (unlikely(ret != 0)) { |
| 696 | DRM_ERROR("Could not add a reference to a surface.\n"); | 684 | DRM_ERROR("Could not add a reference to a surface.\n"); |
| 697 | goto out; | 685 | goto out_no_reference; |
| 698 | } | 686 | } |
| 699 | 687 | ||
| 700 | rep->flags = srf->flags; | 688 | rep->flags = srf->flags; |
| @@ -706,40 +694,43 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
| 706 | if (user_sizes) | 694 | if (user_sizes) |
| 707 | ret = copy_to_user(user_sizes, srf->sizes, | 695 | ret = copy_to_user(user_sizes, srf->sizes, |
| 708 | srf->num_sizes * sizeof(*srf->sizes)); | 696 | srf->num_sizes * sizeof(*srf->sizes)); |
| 709 | if (unlikely(ret != 0)) { | 697 | if (unlikely(ret != 0)) |
| 710 | DRM_ERROR("copy_to_user failed %p %u\n", | 698 | DRM_ERROR("copy_to_user failed %p %u\n", |
| 711 | user_sizes, srf->num_sizes); | 699 | user_sizes, srf->num_sizes); |
| 712 | /** | 700 | out_bad_resource: |
| 713 | * FIXME: Unreference surface here? | 701 | out_no_reference: |
| 714 | */ | 702 | ttm_base_object_unref(&base); |
| 715 | goto out; | 703 | |
| 716 | } | ||
| 717 | out: | ||
| 718 | vmw_resource_unreference(&res); | ||
| 719 | return ret; | 704 | return ret; |
| 720 | } | 705 | } |
| 721 | 706 | ||
| 722 | int vmw_surface_check(struct vmw_private *dev_priv, | 707 | int vmw_surface_check(struct vmw_private *dev_priv, |
| 723 | struct ttm_object_file *tfile, | 708 | struct ttm_object_file *tfile, |
| 724 | int id) | 709 | uint32_t handle, int *id) |
| 725 | { | 710 | { |
| 726 | struct vmw_resource *res; | 711 | struct ttm_base_object *base; |
| 727 | int ret = 0; | 712 | struct vmw_user_surface *user_srf; |
| 728 | 713 | ||
| 729 | read_lock(&dev_priv->resource_lock); | 714 | int ret = -EPERM; |
| 730 | res = idr_find(&dev_priv->surface_idr, id); | ||
| 731 | if (res && res->avail) { | ||
| 732 | struct vmw_surface *srf = | ||
| 733 | container_of(res, struct vmw_surface, res); | ||
| 734 | struct vmw_user_surface *usrf = | ||
| 735 | container_of(srf, struct vmw_user_surface, srf); | ||
| 736 | 715 | ||
| 737 | if (usrf->base.tfile != tfile && !usrf->base.shareable) | 716 | base = ttm_base_object_lookup(tfile, handle); |
| 738 | ret = -EPERM; | 717 | if (unlikely(base == NULL)) |
| 739 | } else | 718 | return -EINVAL; |
| 740 | ret = -EINVAL; | 719 | |
| 741 | read_unlock(&dev_priv->resource_lock); | 720 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
| 721 | goto out_bad_surface; | ||
| 742 | 722 | ||
| 723 | user_srf = container_of(base, struct vmw_user_surface, base); | ||
| 724 | *id = user_srf->srf.res.id; | ||
| 725 | ret = 0; | ||
| 726 | |||
| 727 | out_bad_surface: | ||
| 728 | /** | ||
| 729 | * FIXME: May deadlock here when called from the | ||
| 730 | * command parsing code. | ||
| 731 | */ | ||
| 732 | |||
| 733 | ttm_base_object_unref(&base); | ||
| 743 | return ret; | 734 | return ret; |
| 744 | } | 735 | } |
| 745 | 736 | ||
