diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2012-11-21 05:36:36 -0500 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2014-01-17 01:52:25 -0500 |
commit | 58a0c5f036464bd891880b30bde196320e904b81 (patch) | |
tree | 263f5d0157cbb4d23df5408881946de0f74f3f86 | |
parent | f468911feec94201b4296e3fe7480ebaf278fc4d (diff) |
drm/vmwgfx: Hook up guest-backed contexts
Contexts are managed by the kernel only, so disable access to GB
context commands from user-space
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Zack Ruzin <zackr@vmware.com>
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 222 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 5 |
2 files changed, 227 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 00ae0925aca8..308e78fdc55e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c | |||
@@ -38,6 +38,14 @@ static void vmw_user_context_free(struct vmw_resource *res); | |||
38 | static struct vmw_resource * | 38 | static struct vmw_resource * |
39 | vmw_user_context_base_to_res(struct ttm_base_object *base); | 39 | vmw_user_context_base_to_res(struct ttm_base_object *base); |
40 | 40 | ||
41 | static int vmw_gb_context_create(struct vmw_resource *res); | ||
42 | static int vmw_gb_context_bind(struct vmw_resource *res, | ||
43 | struct ttm_validate_buffer *val_buf); | ||
44 | static int vmw_gb_context_unbind(struct vmw_resource *res, | ||
45 | bool readback, | ||
46 | struct ttm_validate_buffer *val_buf); | ||
47 | static int vmw_gb_context_destroy(struct vmw_resource *res); | ||
48 | |||
41 | static uint64_t vmw_user_context_size; | 49 | static uint64_t vmw_user_context_size; |
42 | 50 | ||
43 | static const struct vmw_user_resource_conv user_context_conv = { | 51 | static const struct vmw_user_resource_conv user_context_conv = { |
@@ -62,6 +70,18 @@ static const struct vmw_res_func vmw_legacy_context_func = { | |||
62 | .unbind = NULL | 70 | .unbind = NULL |
63 | }; | 71 | }; |
64 | 72 | ||
73 | static const struct vmw_res_func vmw_gb_context_func = { | ||
74 | .res_type = vmw_res_context, | ||
75 | .needs_backup = true, | ||
76 | .may_evict = true, | ||
77 | .type_name = "guest backed contexts", | ||
78 | .backup_placement = &vmw_mob_placement, | ||
79 | .create = vmw_gb_context_create, | ||
80 | .destroy = vmw_gb_context_destroy, | ||
81 | .bind = vmw_gb_context_bind, | ||
82 | .unbind = vmw_gb_context_unbind | ||
83 | }; | ||
84 | |||
65 | /** | 85 | /** |
66 | * Context management: | 86 | * Context management: |
67 | */ | 87 | */ |
@@ -76,6 +96,16 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) | |||
76 | } *cmd; | 96 | } *cmd; |
77 | 97 | ||
78 | 98 | ||
99 | if (res->func->destroy == vmw_gb_context_destroy) { | ||
100 | mutex_lock(&dev_priv->cmdbuf_mutex); | ||
101 | (void) vmw_gb_context_destroy(res); | ||
102 | if (dev_priv->pinned_bo != NULL && | ||
103 | !dev_priv->query_cid_valid) | ||
104 | __vmw_execbuf_release_pinned_bo(dev_priv, NULL); | ||
105 | mutex_unlock(&dev_priv->cmdbuf_mutex); | ||
106 | return; | ||
107 | } | ||
108 | |||
79 | vmw_execbuf_release_pinned_bo(dev_priv); | 109 | vmw_execbuf_release_pinned_bo(dev_priv); |
80 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | 110 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
81 | if (unlikely(cmd == NULL)) { | 111 | if (unlikely(cmd == NULL)) { |
@@ -92,6 +122,28 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) | |||
92 | vmw_3d_resource_dec(dev_priv, false); | 122 | vmw_3d_resource_dec(dev_priv, false); |
93 | } | 123 | } |
94 | 124 | ||
125 | static int vmw_gb_context_init(struct vmw_private *dev_priv, | ||
126 | struct vmw_resource *res, | ||
127 | void (*res_free) (struct vmw_resource *res)) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | ret = vmw_resource_init(dev_priv, res, true, | ||
132 | res_free, &vmw_gb_context_func); | ||
133 | res->backup_size = SVGA3D_CONTEXT_DATA_SIZE; | ||
134 | |||
135 | if (unlikely(ret != 0)) { | ||
136 | if (res_free) | ||
137 | res_free(res); | ||
138 | else | ||
139 | kfree(res); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | vmw_resource_activate(res, vmw_hw_context_destroy); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
95 | static int vmw_context_init(struct vmw_private *dev_priv, | 147 | static int vmw_context_init(struct vmw_private *dev_priv, |
96 | struct vmw_resource *res, | 148 | struct vmw_resource *res, |
97 | void (*res_free) (struct vmw_resource *res)) | 149 | void (*res_free) (struct vmw_resource *res)) |
@@ -103,6 +155,9 @@ static int vmw_context_init(struct vmw_private *dev_priv, | |||
103 | SVGA3dCmdDefineContext body; | 155 | SVGA3dCmdDefineContext body; |
104 | } *cmd; | 156 | } *cmd; |
105 | 157 | ||
158 | if (dev_priv->has_mob) | ||
159 | return vmw_gb_context_init(dev_priv, res, res_free); | ||
160 | |||
106 | ret = vmw_resource_init(dev_priv, res, false, | 161 | ret = vmw_resource_init(dev_priv, res, false, |
107 | res_free, &vmw_legacy_context_func); | 162 | res_free, &vmw_legacy_context_func); |
108 | 163 | ||
@@ -154,6 +209,173 @@ struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv) | |||
154 | return (ret == 0) ? res : NULL; | 209 | return (ret == 0) ? res : NULL; |
155 | } | 210 | } |
156 | 211 | ||
212 | |||
213 | static int vmw_gb_context_create(struct vmw_resource *res) | ||
214 | { | ||
215 | struct vmw_private *dev_priv = res->dev_priv; | ||
216 | int ret; | ||
217 | struct { | ||
218 | SVGA3dCmdHeader header; | ||
219 | SVGA3dCmdDefineGBContext body; | ||
220 | } *cmd; | ||
221 | |||
222 | if (likely(res->id != -1)) | ||
223 | return 0; | ||
224 | |||
225 | ret = vmw_resource_alloc_id(res); | ||
226 | if (unlikely(ret != 0)) { | ||
227 | DRM_ERROR("Failed to allocate a context id.\n"); | ||
228 | goto out_no_id; | ||
229 | } | ||
230 | |||
231 | if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) { | ||
232 | ret = -EBUSY; | ||
233 | goto out_no_fifo; | ||
234 | } | ||
235 | |||
236 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | ||
237 | if (unlikely(cmd == NULL)) { | ||
238 | DRM_ERROR("Failed reserving FIFO space for context " | ||
239 | "creation.\n"); | ||
240 | ret = -ENOMEM; | ||
241 | goto out_no_fifo; | ||
242 | } | ||
243 | |||
244 | cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT; | ||
245 | cmd->header.size = sizeof(cmd->body); | ||
246 | cmd->body.cid = res->id; | ||
247 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | ||
248 | (void) vmw_3d_resource_inc(dev_priv, false); | ||
249 | |||
250 | return 0; | ||
251 | |||
252 | out_no_fifo: | ||
253 | vmw_resource_release_id(res); | ||
254 | out_no_id: | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int vmw_gb_context_bind(struct vmw_resource *res, | ||
259 | struct ttm_validate_buffer *val_buf) | ||
260 | { | ||
261 | struct vmw_private *dev_priv = res->dev_priv; | ||
262 | struct { | ||
263 | SVGA3dCmdHeader header; | ||
264 | SVGA3dCmdBindGBContext body; | ||
265 | } *cmd; | ||
266 | struct ttm_buffer_object *bo = val_buf->bo; | ||
267 | |||
268 | BUG_ON(bo->mem.mem_type != VMW_PL_MOB); | ||
269 | |||
270 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | ||
271 | if (unlikely(cmd == NULL)) { | ||
272 | DRM_ERROR("Failed reserving FIFO space for context " | ||
273 | "binding.\n"); | ||
274 | return -ENOMEM; | ||
275 | } | ||
276 | |||
277 | cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; | ||
278 | cmd->header.size = sizeof(cmd->body); | ||
279 | cmd->body.cid = res->id; | ||
280 | cmd->body.mobid = bo->mem.start; | ||
281 | cmd->body.validContents = res->backup_dirty; | ||
282 | res->backup_dirty = false; | ||
283 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int vmw_gb_context_unbind(struct vmw_resource *res, | ||
289 | bool readback, | ||
290 | struct ttm_validate_buffer *val_buf) | ||
291 | { | ||
292 | struct vmw_private *dev_priv = res->dev_priv; | ||
293 | struct ttm_buffer_object *bo = val_buf->bo; | ||
294 | struct vmw_fence_obj *fence; | ||
295 | |||
296 | struct { | ||
297 | SVGA3dCmdHeader header; | ||
298 | SVGA3dCmdReadbackGBContext body; | ||
299 | } *cmd1; | ||
300 | struct { | ||
301 | SVGA3dCmdHeader header; | ||
302 | SVGA3dCmdBindGBContext body; | ||
303 | } *cmd2; | ||
304 | uint32_t submit_size; | ||
305 | uint8_t *cmd; | ||
306 | |||
307 | |||
308 | BUG_ON(bo->mem.mem_type != VMW_PL_MOB); | ||
309 | |||
310 | submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0); | ||
311 | |||
312 | cmd = vmw_fifo_reserve(dev_priv, submit_size); | ||
313 | if (unlikely(cmd == NULL)) { | ||
314 | DRM_ERROR("Failed reserving FIFO space for context " | ||
315 | "unbinding.\n"); | ||
316 | return -ENOMEM; | ||
317 | } | ||
318 | |||
319 | cmd2 = (void *) cmd; | ||
320 | if (readback) { | ||
321 | cmd1 = (void *) cmd; | ||
322 | cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT; | ||
323 | cmd1->header.size = sizeof(cmd1->body); | ||
324 | cmd1->body.cid = res->id; | ||
325 | cmd2 = (void *) (&cmd1[1]); | ||
326 | } | ||
327 | cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT; | ||
328 | cmd2->header.size = sizeof(cmd2->body); | ||
329 | cmd2->body.cid = res->id; | ||
330 | cmd2->body.mobid = SVGA3D_INVALID_ID; | ||
331 | |||
332 | vmw_fifo_commit(dev_priv, submit_size); | ||
333 | |||
334 | /* | ||
335 | * Create a fence object and fence the backup buffer. | ||
336 | */ | ||
337 | |||
338 | (void) vmw_execbuf_fence_commands(NULL, dev_priv, | ||
339 | &fence, NULL); | ||
340 | |||
341 | vmw_fence_single_bo(bo, fence); | ||
342 | |||
343 | if (likely(fence != NULL)) | ||
344 | vmw_fence_obj_unreference(&fence); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int vmw_gb_context_destroy(struct vmw_resource *res) | ||
350 | { | ||
351 | struct vmw_private *dev_priv = res->dev_priv; | ||
352 | struct { | ||
353 | SVGA3dCmdHeader header; | ||
354 | SVGA3dCmdDestroyGBContext body; | ||
355 | } *cmd; | ||
356 | |||
357 | if (likely(res->id == -1)) | ||
358 | return 0; | ||
359 | |||
360 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); | ||
361 | if (unlikely(cmd == NULL)) { | ||
362 | DRM_ERROR("Failed reserving FIFO space for context " | ||
363 | "destruction.\n"); | ||
364 | return -ENOMEM; | ||
365 | } | ||
366 | |||
367 | cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT; | ||
368 | cmd->header.size = sizeof(cmd->body); | ||
369 | cmd->body.cid = res->id; | ||
370 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | ||
371 | if (dev_priv->query_cid == res->id) | ||
372 | dev_priv->query_cid_valid = false; | ||
373 | vmw_resource_release_id(res); | ||
374 | vmw_3d_resource_dec(dev_priv, false); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
157 | /** | 379 | /** |
158 | * User-space context management: | 380 | * User-space context management: |
159 | */ | 381 | */ |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 6583dd34ed18..c2a6e4832e74 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
@@ -1300,6 +1300,11 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = { | |||
1300 | VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid), | 1300 | VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid), |
1301 | VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid), | 1301 | VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid), |
1302 | VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid), | 1302 | VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid), |
1303 | VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_CONTEXT, &vmw_cmd_invalid), | ||
1304 | VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_CONTEXT, &vmw_cmd_invalid), | ||
1305 | VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_CONTEXT, &vmw_cmd_invalid), | ||
1306 | VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_CONTEXT, &vmw_cmd_invalid), | ||
1307 | VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_CONTEXT, &vmw_cmd_invalid), | ||
1303 | VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_GB_QUERY, &vmw_cmd_begin_gb_query), | 1308 | VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_GB_QUERY, &vmw_cmd_begin_gb_query), |
1304 | VMW_CMD_DEF(SVGA_3D_CMD_END_GB_QUERY, &vmw_cmd_end_gb_query), | 1309 | VMW_CMD_DEF(SVGA_3D_CMD_END_GB_QUERY, &vmw_cmd_end_gb_query), |
1305 | VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_GB_QUERY, &vmw_cmd_wait_gb_query), | 1310 | VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_GB_QUERY, &vmw_cmd_wait_gb_query), |