History

drm/vmwgfx: Initial DX support

Initial DX support. Co-authored with Sinclair Yeh, Charmaine Lee and Jakob Bornecrantz.

Thomas Hellstrom committed 11 years ago

Commit d80efd51 parent 8ce75f822 files · +5411 −839Browse files

Unified · Split

22 files
  1. drivers/gpu/drm/vmwgfx/Makefile +1 −0
  2. drivers/gpu/drm/vmwgfx/vmwgfx_binding.c +1294 −0
  3. drivers/gpu/drm/vmwgfx/vmwgfx_binding.h +209 −0
  4. drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +2 −3
  5. drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +14 −10
  6. drivers/gpu/drm/vmwgfx/vmwgfx_context.c +341 −394
  7. drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +662 −0
  8. drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +46 −8
  9. drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +86 −89
  10. drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +1292 −176
  11. drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +24 −4
  12. drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +5 −2
  13. drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +10 −5
  14. drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +105 −64
  15. drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +34 −14
  16. drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h +11 −1
  17. drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +440 −44
  18. drivers/gpu/drm/vmwgfx/vmwgfx_so.c +555 −0
  19. drivers/gpu/drm/vmwgfx/vmwgfx_so.h +160 −0
  20. drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +1 −0
  21. drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +87 −22
  22. include/uapi/drm/vmwgfx_drm.h +32 −3
drivers/gpu/drm/vmwgfx/Makefile+1−0
@@ -8,5 +8,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ · 7 unmodified lines
8 vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \8 vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \
9 vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \9 vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \
10 vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \10 vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \
11 vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o
11 12
12obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o13obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
drivers/gpu/drm/vmwgfx/vmwgfx_binding.c+1294−0
@@ -0,0 +1,1294 @@
1/**************************************************************************
2 *
3 * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27/*
28 * This file implements the vmwgfx context binding manager,
29 * The sole reason for having to use this code is that vmware guest
30 * backed contexts can be swapped out to their backing mobs by the device
31 * at any time, also swapped in at any time. At swapin time, the device
32 * validates the context bindings to make sure they point to valid resources.
33 * It's this outside-of-drawcall validation (that can happen at any time),
34 * that makes this code necessary.
35 *
36 * We therefore need to kill any context bindings pointing to a resource
37 * when the resource is swapped out. Furthermore, if the vmwgfx driver has
38 * swapped out the context we can't swap it in again to kill bindings because
39 * of backing mob reservation lockdep violations, so as part of
40 * context swapout, also kill all bindings of a context, so that they are
41 * already killed if a resource to which a binding points
42 * needs to be swapped out.
43 *
44 * Note that a resource can be pointed to by bindings from multiple contexts,
45 * Therefore we can't easily protect this data by a per context mutex
46 * (unless we use deadlock-safe WW mutexes). So we use a global binding_mutex
47 * to protect all binding manager data.
48 *
49 * Finally, any association between a context and a global resource
50 * (surface, shader or even DX query) is conceptually a context binding that
51 * needs to be tracked by this code.
52 */
53
54#include "vmwgfx_drv.h"
55#include "vmwgfx_binding.h"
56#include "device_include/svga3d_reg.h"
57
58#define VMW_BINDING_RT_BIT 0
59#define VMW_BINDING_PS_BIT 1
60#define VMW_BINDING_SO_BIT 2
61#define VMW_BINDING_VB_BIT 3
62#define VMW_BINDING_NUM_BITS 4
63
64#define VMW_BINDING_PS_SR_BIT 0
65
66/**
67 * struct vmw_ctx_binding_state - per context binding state
68 *
69 * @dev_priv: Pointer to device private structure.
70 * @list: linked list of individual active bindings.
71 * @render_targets: Render target bindings.
72 * @texture_units: Texture units bindings.
73 * @ds_view: Depth-stencil view binding.
74 * @so_targets: StreamOutput target bindings.
75 * @vertex_buffers: Vertex buffer bindings.
76 * @index_buffer: Index buffer binding.
77 * @per_shader: Per shader-type bindings.
78 * @dirty: Bitmap tracking per binding-type changes that have not yet
79 * been emitted to the device.
80 * @dirty_vb: Bitmap tracking individual vertex buffer binding changes that
81 * have not yet been emitted to the device.
82 * @bind_cmd_buffer: Scratch space used to construct binding commands.
83 * @bind_cmd_count: Number of binding command data entries in @bind_cmd_buffer
84 * @bind_first_slot: Used together with @bind_cmd_buffer to indicate the
85 * device binding slot of the first command data entry in @bind_cmd_buffer.
86 *
87 * Note that this structure also provides storage space for the individual
88 * struct vmw_ctx_binding objects, so that no dynamic allocation is needed
89 * for individual bindings.
90 *
91 */
92struct vmw_ctx_binding_state {
93 struct vmw_private *dev_priv;
94 struct list_head list;
95 struct vmw_ctx_bindinfo_view render_targets[SVGA3D_RT_MAX];
96 struct vmw_ctx_bindinfo_tex texture_units[SVGA3D_NUM_TEXTURE_UNITS];
97 struct vmw_ctx_bindinfo_view ds_view;
98 struct vmw_ctx_bindinfo_so so_targets[SVGA3D_DX_MAX_SOTARGETS];
99 struct vmw_ctx_bindinfo_vb vertex_buffers[SVGA3D_DX_MAX_VERTEXBUFFERS];
100 struct vmw_ctx_bindinfo_ib index_buffer;
101 struct vmw_dx_shader_bindings per_shader[SVGA3D_NUM_SHADERTYPE_DX10];
102
103 unsigned long dirty;
104 DECLARE_BITMAP(dirty_vb, SVGA3D_DX_MAX_VERTEXBUFFERS);
105
106 u32 bind_cmd_buffer[VMW_MAX_VIEW_BINDINGS];
107 u32 bind_cmd_count;
108 u32 bind_first_slot;
109};
110
111static int vmw_binding_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);
112static int vmw_binding_scrub_render_target(struct vmw_ctx_bindinfo *bi,
113 bool rebind);
114static int vmw_binding_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);
115static int vmw_binding_scrub_cb(struct vmw_ctx_bindinfo *bi, bool rebind);
116static int vmw_binding_scrub_dx_rt(struct vmw_ctx_bindinfo *bi, bool rebind);
117static int vmw_binding_scrub_sr(struct vmw_ctx_bindinfo *bi, bool rebind);
118static int vmw_binding_scrub_so(struct vmw_ctx_bindinfo *bi, bool rebind);
119static int vmw_binding_emit_dirty(struct vmw_ctx_binding_state *cbs);
120static int vmw_binding_scrub_dx_shader(struct vmw_ctx_bindinfo *bi,
121 bool rebind);
122static int vmw_binding_scrub_ib(struct vmw_ctx_bindinfo *bi, bool rebind);
123static int vmw_binding_scrub_vb(struct vmw_ctx_bindinfo *bi, bool rebind);
124static void vmw_binding_build_asserts(void) __attribute__ ((unused));
125
126typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);
127
128/**
129 * struct vmw_binding_info - Per binding type information for the binding
130 * manager
131 *
132 * @size: The size of the struct binding derived from a struct vmw_ctx_bindinfo.
133 * @offsets: array[shader_slot] of offsets to the array[slot]
134 * of struct bindings for the binding type.
135 * @scrub_func: Pointer to the scrub function for this binding type.
136 *
137 * Holds static information to help optimize the binding manager and avoid
138 * an excessive amount of switch statements.
139 */
140struct vmw_binding_info {
141 size_t size;
142 const size_t *offsets;
143 vmw_scrub_func scrub_func;
144};
145
146/*
147 * A number of static variables that help determine the scrub func and the
148 * location of the struct vmw_ctx_bindinfo slots for each binding type.
149 */
150static const size_t vmw_binding_shader_offsets[] = {
151 offsetof(struct vmw_ctx_binding_state, per_shader[0].shader),
152 offsetof(struct vmw_ctx_binding_state, per_shader[1].shader),
153 offsetof(struct vmw_ctx_binding_state, per_shader[2].shader),
154};
155static const size_t vmw_binding_rt_offsets[] = {
156 offsetof(struct vmw_ctx_binding_state, render_targets),
157};
158static const size_t vmw_binding_tex_offsets[] = {
159 offsetof(struct vmw_ctx_binding_state, texture_units),
160};
161static const size_t vmw_binding_cb_offsets[] = {
162 offsetof(struct vmw_ctx_binding_state, per_shader[0].const_buffers),
163 offsetof(struct vmw_ctx_binding_state, per_shader[1].const_buffers),
164 offsetof(struct vmw_ctx_binding_state, per_shader[2].const_buffers),
165};
166static const size_t vmw_binding_dx_ds_offsets[] = {
167 offsetof(struct vmw_ctx_binding_state, ds_view),
168};
169static const size_t vmw_binding_sr_offsets[] = {
170 offsetof(struct vmw_ctx_binding_state, per_shader[0].shader_res),
171 offsetof(struct vmw_ctx_binding_state, per_shader[1].shader_res),
172 offsetof(struct vmw_ctx_binding_state, per_shader[2].shader_res),
173};
174static const size_t vmw_binding_so_offsets[] = {
175 offsetof(struct vmw_ctx_binding_state, so_targets),
176};
177static const size_t vmw_binding_vb_offsets[] = {
178 offsetof(struct vmw_ctx_binding_state, vertex_buffers),
179};
180static const size_t vmw_binding_ib_offsets[] = {
181 offsetof(struct vmw_ctx_binding_state, index_buffer),
182};
183
184static const struct vmw_binding_info vmw_binding_infos[] = {
185 [vmw_ctx_binding_shader] = {
186 .size = sizeof(struct vmw_ctx_bindinfo_shader),
187 .offsets = vmw_binding_shader_offsets,
188 .scrub_func = vmw_binding_scrub_shader},
189 [vmw_ctx_binding_rt] = {
190 .size = sizeof(struct vmw_ctx_bindinfo_view),
191 .offsets = vmw_binding_rt_offsets,
192 .scrub_func = vmw_binding_scrub_render_target},
193 [vmw_ctx_binding_tex] = {
194 .size = sizeof(struct vmw_ctx_bindinfo_tex),
195 .offsets = vmw_binding_tex_offsets,
196 .scrub_func = vmw_binding_scrub_texture},
197 [vmw_ctx_binding_cb] = {
198 .size = sizeof(struct vmw_ctx_bindinfo_cb),
199 .offsets = vmw_binding_cb_offsets,
200 .scrub_func = vmw_binding_scrub_cb},
201 [vmw_ctx_binding_dx_shader] = {
202 .size = sizeof(struct vmw_ctx_bindinfo_shader),
203 .offsets = vmw_binding_shader_offsets,
204 .scrub_func = vmw_binding_scrub_dx_shader},
205 [vmw_ctx_binding_dx_rt] = {
206 .size = sizeof(struct vmw_ctx_bindinfo_view),
207 .offsets = vmw_binding_rt_offsets,
208 .scrub_func = vmw_binding_scrub_dx_rt},
209 [vmw_ctx_binding_sr] = {
210 .size = sizeof(struct vmw_ctx_bindinfo_view),
211 .offsets = vmw_binding_sr_offsets,
212 .scrub_func = vmw_binding_scrub_sr},
213 [vmw_ctx_binding_ds] = {
214 .size = sizeof(struct vmw_ctx_bindinfo_view),
215 .offsets = vmw_binding_dx_ds_offsets,
216 .scrub_func = vmw_binding_scrub_dx_rt},
217 [vmw_ctx_binding_so] = {
218 .size = sizeof(struct vmw_ctx_bindinfo_so),
219 .offsets = vmw_binding_so_offsets,
220 .scrub_func = vmw_binding_scrub_so},
221 [vmw_ctx_binding_vb] = {
222 .size = sizeof(struct vmw_ctx_bindinfo_vb),
223 .offsets = vmw_binding_vb_offsets,
224 .scrub_func = vmw_binding_scrub_vb},
225 [vmw_ctx_binding_ib] = {
226 .size = sizeof(struct vmw_ctx_bindinfo_ib),
227 .offsets = vmw_binding_ib_offsets,
228 .scrub_func = vmw_binding_scrub_ib},
229};
230
231/**
232 * vmw_cbs_context - Return a pointer to the context resource of a
233 * context binding state tracker.
234 *
235 * @cbs: The context binding state tracker.
236 *
237 * Provided there are any active bindings, this function will return an
238 * unreferenced pointer to the context resource that owns the context
239 * binding state tracker. If there are no active bindings, this function
240 * will return NULL. Note that the caller must somehow ensure that a reference
241 * is held on the context resource prior to calling this function.
242 */
243static const struct vmw_resource *
244vmw_cbs_context(const struct vmw_ctx_binding_state *cbs)
245{
246 if (list_empty(&cbs->list))
247 return NULL;
248
249 return list_first_entry(&cbs->list, struct vmw_ctx_bindinfo,
250 ctx_list)->ctx;
251}
252
253/**
254 * vmw_binding_loc - determine the struct vmw_ctx_bindinfo slot location.
255 *
256 * @cbs: Pointer to a struct vmw_ctx_binding state which holds the slot.
257 * @bt: The binding type.
258 * @shader_slot: The shader slot of the binding. If none, then set to 0.
259 * @slot: The slot of the binding.
260 */
261static struct vmw_ctx_bindinfo *
262vmw_binding_loc(struct vmw_ctx_binding_state *cbs,
263 enum vmw_ctx_binding_type bt, u32 shader_slot, u32 slot)
264{
265 const struct vmw_binding_info *b = &vmw_binding_infos[bt];
266 size_t offset = b->offsets[shader_slot] + b->size*slot;
267
268 return (struct vmw_ctx_bindinfo *)((u8 *) cbs + offset);
269}
270
271/**
272 * vmw_binding_drop: Stop tracking a context binding
273 *
274 * @bi: Pointer to binding tracker storage.
275 *
276 * Stops tracking a context binding, and re-initializes its storage.
277 * Typically used when the context binding is replaced with a binding to
278 * another (or the same, for that matter) resource.
279 */
280static void vmw_binding_drop(struct vmw_ctx_bindinfo *bi)
281{
282 list_del(&bi->ctx_list);
283 if (!list_empty(&bi->res_list))
284 list_del(&bi->res_list);
285 bi->ctx = NULL;
286}
287
288/**
289 * vmw_binding_add: Start tracking a context binding
290 *
291 * @cbs: Pointer to the context binding state tracker.
292 * @bi: Information about the binding to track.
293 *
294 * Starts tracking the binding in the context binding
295 * state structure @cbs.
296 */
297void vmw_binding_add(struct vmw_ctx_binding_state *cbs,
298 const struct vmw_ctx_bindinfo *bi,
299 u32 shader_slot, u32 slot)
300{
301 struct vmw_ctx_bindinfo *loc =
302 vmw_binding_loc(cbs, bi->bt, shader_slot, slot);
303 const struct vmw_binding_info *b = &vmw_binding_infos[bi->bt];
304
305 if (loc->ctx != NULL)
306 vmw_binding_drop(loc);
307
308 memcpy(loc, bi, b->size);
309 loc->scrubbed = false;
310 list_add(&loc->ctx_list, &cbs->list);
311 INIT_LIST_HEAD(&loc->res_list);
312}
313
314/**
315 * vmw_binding_transfer: Transfer a context binding tracking entry.
316 *
317 * @cbs: Pointer to the persistent context binding state tracker.
318 * @bi: Information about the binding to track.
319 *
320 */
321static void vmw_binding_transfer(struct vmw_ctx_binding_state *cbs,
322 const struct vmw_ctx_binding_state *from,
323 const struct vmw_ctx_bindinfo *bi)
324{
325 size_t offset = (unsigned long)bi - (unsigned long)from;
326 struct vmw_ctx_bindinfo *loc = (struct vmw_ctx_bindinfo *)
327 ((unsigned long) cbs + offset);
328
329 if (loc->ctx != NULL) {
330 WARN_ON(bi->scrubbed);
331
332 vmw_binding_drop(loc);
333 }
334
335 if (bi->res != NULL) {
336 memcpy(loc, bi, vmw_binding_infos[bi->bt].size);
337 list_add_tail(&loc->ctx_list, &cbs->list);
338 list_add_tail(&loc->res_list, &loc->res->binding_head);
339 }
340}
341
342/**
343 * vmw_binding_state_kill - Kill all bindings associated with a
344 * struct vmw_ctx_binding state structure, and re-initialize the structure.
345 *
346 * @cbs: Pointer to the context binding state tracker.
347 *
348 * Emits commands to scrub all bindings associated with the
349 * context binding state tracker. Then re-initializes the whole structure.
350 */
351void vmw_binding_state_kill(struct vmw_ctx_binding_state *cbs)
352{
353 struct vmw_ctx_bindinfo *entry, *next;
354
355 vmw_binding_state_scrub(cbs);
356 list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
357 vmw_binding_drop(entry);
358}
359
360/**
361 * vmw_binding_state_scrub - Scrub all bindings associated with a
362 * struct vmw_ctx_binding state structure.
363 *
364 * @cbs: Pointer to the context binding state tracker.
365 *
366 * Emits commands to scrub all bindings associated with the
367 * context binding state tracker.
368 */
369void vmw_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
370{
371 struct vmw_ctx_bindinfo *entry;
372
373 list_for_each_entry(entry, &cbs->list, ctx_list) {
374 if (!entry->scrubbed) {
375 (void) vmw_binding_infos[entry->bt].scrub_func
376 (entry, false);
377 entry->scrubbed = true;
378 }
379 }
380
381 (void) vmw_binding_emit_dirty(cbs);
382}
383
384/**
385 * vmw_binding_res_list_kill - Kill all bindings on a
386 * resource binding list
387 *
388 * @head: list head of resource binding list
389 *
390 * Kills all bindings associated with a specific resource. Typically
391 * called before the resource is destroyed.
392 */
393void vmw_binding_res_list_kill(struct list_head *head)
394{
395 struct vmw_ctx_bindinfo *entry, *next;
396
397 vmw_binding_res_list_scrub(head);
398 list_for_each_entry_safe(entry, next, head, res_list)
399 vmw_binding_drop(entry);
400}
401
402/**
403 * vmw_binding_res_list_scrub - Scrub all bindings on a
404 * resource binding list
405 *
406 * @head: list head of resource binding list
407 *
408 * Scrub all bindings associated with a specific resource. Typically
409 * called before the resource is evicted.
410 */
411void vmw_binding_res_list_scrub(struct list_head *head)
412{
413 struct vmw_ctx_bindinfo *entry;
414
415 list_for_each_entry(entry, head, res_list) {
416 if (!entry->scrubbed) {
417 (void) vmw_binding_infos[entry->bt].scrub_func
418 (entry, false);
419 entry->scrubbed = true;
420 }
421 }
422
423 list_for_each_entry(entry, head, res_list) {
424 struct vmw_ctx_binding_state *cbs =
425 vmw_context_binding_state(entry->ctx);
426
427 (void) vmw_binding_emit_dirty(cbs);
428 }
429}
430
431
432/**
433 * vmw_binding_state_commit - Commit staged binding info
434 *
435 * @ctx: Pointer to context to commit the staged binding info to.
436 * @from: Staged binding info built during execbuf.
437 * @scrubbed: Transfer only scrubbed bindings.
438 *
439 * Transfers binding info from a temporary structure
440 * (typically used by execbuf) to the persistent
441 * structure in the context. This can be done once commands have been
442 * submitted to hardware
443 */
444void vmw_binding_state_commit(struct vmw_ctx_binding_state *to,
445 struct vmw_ctx_binding_state *from)
446{
447 struct vmw_ctx_bindinfo *entry, *next;
448
449 list_for_each_entry_safe(entry, next, &from->list, ctx_list) {
450 vmw_binding_transfer(to, from, entry);
451 vmw_binding_drop(entry);
452 }
453}
454
455/**
456 * vmw_binding_rebind_all - Rebind all scrubbed bindings of a context
457 *
458 * @ctx: The context resource
459 *
460 * Walks through the context binding list and rebinds all scrubbed
461 * resources.
462 */
463int vmw_binding_rebind_all(struct vmw_ctx_binding_state *cbs)
464{
465 struct vmw_ctx_bindinfo *entry;
466 int ret;
467
468 list_for_each_entry(entry, &cbs->list, ctx_list) {
469 if (likely(!entry->scrubbed))
470 continue;
471
472 if ((entry->res == NULL || entry->res->id ==
473 SVGA3D_INVALID_ID))
474 continue;
475
476 ret = vmw_binding_infos[entry->bt].scrub_func(entry, true);
477 if (unlikely(ret != 0))
478 return ret;
479
480 entry->scrubbed = false;
481 }
482
483 return vmw_binding_emit_dirty(cbs);
484}
485
486/**
487 * vmw_binding_scrub_shader - scrub a shader binding from a context.
488 *
489 * @bi: single binding information.
490 * @rebind: Whether to issue a bind instead of scrub command.
491 */
492static int vmw_binding_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
493{
494 struct vmw_ctx_bindinfo_shader *binding =
495 container_of(bi, typeof(*binding), bi);
496 struct vmw_private *dev_priv = bi->ctx->dev_priv;
497 struct {
498 SVGA3dCmdHeader header;
499 SVGA3dCmdSetShader body;
500 } *cmd;
501
502 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
503 if (unlikely(cmd == NULL)) {
504 DRM_ERROR("Failed reserving FIFO space for shader "
505 "unbinding.\n");
506 return -ENOMEM;
507 }
508
509 cmd->header.id = SVGA_3D_CMD_SET_SHADER;
510 cmd->header.size = sizeof(cmd->body);
511 cmd->body.cid = bi->ctx->id;
512 cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
513 cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
514 vmw_fifo_commit(dev_priv, sizeof(*cmd));
515
516 return 0;
517}
518
519/**
520 * vmw_binding_scrub_render_target - scrub a render target binding
521 * from a context.
522 *
523 * @bi: single binding information.
524 * @rebind: Whether to issue a bind instead of scrub command.
525 */
526static int vmw_binding_scrub_render_target(struct vmw_ctx_bindinfo *bi,
527 bool rebind)
528{
529 struct vmw_ctx_bindinfo_view *binding =
530 container_of(bi, typeof(*binding), bi);
531 struct vmw_private *dev_priv = bi->ctx->dev_priv;
532 struct {
533 SVGA3dCmdHeader header;
534 SVGA3dCmdSetRenderTarget body;
535 } *cmd;
536
537 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
538 if (unlikely(cmd == NULL)) {
539 DRM_ERROR("Failed reserving FIFO space for render target "
540 "unbinding.\n");
541 return -ENOMEM;
542 }
543
544 cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
545 cmd->header.size = sizeof(cmd->body);
546 cmd->body.cid = bi->ctx->id;
547 cmd->body.type = binding->slot;
548 cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
549 cmd->body.target.face = 0;
550 cmd->body.target.mipmap = 0;
551 vmw_fifo_commit(dev_priv, sizeof(*cmd));
552
553 return 0;
554}
555
556/**
557 * vmw_binding_scrub_texture - scrub a texture binding from a context.
558 *
559 * @bi: single binding information.
560 * @rebind: Whether to issue a bind instead of scrub command.
561 *
562 * TODO: Possibly complement this function with a function that takes
563 * a list of texture bindings and combines them to a single command.
564 */
565static int vmw_binding_scrub_texture(struct vmw_ctx_bindinfo *bi,
566 bool rebind)
567{
568 struct vmw_ctx_bindinfo_tex *binding =
569 container_of(bi, typeof(*binding), bi);
570 struct vmw_private *dev_priv = bi->ctx->dev_priv;
571 struct {
572 SVGA3dCmdHeader header;
573 struct {
574 SVGA3dCmdSetTextureState c;
575 SVGA3dTextureState s1;
576 } body;
577 } *cmd;
578
579 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
580 if (unlikely(cmd == NULL)) {
581 DRM_ERROR("Failed reserving FIFO space for texture "
582 "unbinding.\n");
583 return -ENOMEM;
584 }
585
586 cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
587 cmd->header.size = sizeof(cmd->body);
588 cmd->body.c.cid = bi->ctx->id;
589 cmd->body.s1.stage = binding->texture_stage;
590 cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
591 cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
592 vmw_fifo_commit(dev_priv, sizeof(*cmd));
593
594 return 0;
595}
596
597/**
598 * vmw_binding_scrub_dx_shader - scrub a dx shader binding from a context.
599 *
600 * @bi: single binding information.
601 * @rebind: Whether to issue a bind instead of scrub command.
602 */
603static int vmw_binding_scrub_dx_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
604{
605 struct vmw_ctx_bindinfo_shader *binding =
606 container_of(bi, typeof(*binding), bi);
607 struct vmw_private *dev_priv = bi->ctx->dev_priv;
608 struct {
609 SVGA3dCmdHeader header;
610 SVGA3dCmdDXSetShader body;
611 } *cmd;
612
613 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), bi->ctx->id);
614 if (unlikely(cmd == NULL)) {
615 DRM_ERROR("Failed reserving FIFO space for DX shader "
616 "unbinding.\n");
617 return -ENOMEM;
618 }
619 cmd->header.id = SVGA_3D_CMD_DX_SET_SHADER;
620 cmd->header.size = sizeof(cmd->body);
621 cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
622 cmd->body.shaderId = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
623 vmw_fifo_commit(dev_priv, sizeof(*cmd));
624
625 return 0;
626}
627
628/**
629 * vmw_binding_scrub_cb - scrub a constant buffer binding from a context.
630 *
631 * @bi: single binding information.
632 * @rebind: Whether to issue a bind instead of scrub command.
633 */
634static int vmw_binding_scrub_cb(struct vmw_ctx_bindinfo *bi, bool rebind)
635{
636 struct vmw_ctx_bindinfo_cb *binding =
637 container_of(bi, typeof(*binding), bi);
638 struct vmw_private *dev_priv = bi->ctx->dev_priv;
639 struct {
640 SVGA3dCmdHeader header;
641 SVGA3dCmdDXSetSingleConstantBuffer body;
642 } *cmd;
643
644 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), bi->ctx->id);
645 if (unlikely(cmd == NULL)) {
646 DRM_ERROR("Failed reserving FIFO space for DX shader "
647 "unbinding.\n");
648 return -ENOMEM;
649 }
650
651 cmd->header.id = SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER;
652 cmd->header.size = sizeof(cmd->body);
653 cmd->body.slot = binding->slot;
654 cmd->body.type = binding->shader_slot + SVGA3D_SHADERTYPE_MIN;
655 if (rebind) {
656 cmd->body.offsetInBytes = binding->offset;
657 cmd->body.sizeInBytes = binding->size;
658 cmd->body.sid = bi->res->id;
659 } else {
660 cmd->body.offsetInBytes = 0;
661 cmd->body.sizeInBytes = 0;
662 cmd->body.sid = SVGA3D_INVALID_ID;
663 }
664 vmw_fifo_commit(dev_priv, sizeof(*cmd));
665
666 return 0;
667}
668
669/**
670 * vmw_collect_view_ids - Build view id data for a view binding command
671 * without checking which bindings actually need to be emitted
672 *
673 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
674 * @bi: Pointer to where the binding info array is stored in @cbs
675 * @max_num: Maximum number of entries in the @bi array.
676 *
677 * Scans the @bi array for bindings and builds a buffer of view id data.
678 * Stops at the first non-existing binding in the @bi array.
679 * On output, @cbs->bind_cmd_count contains the number of bindings to be
680 * emitted, @cbs->bind_first_slot is set to zero, and @cbs->bind_cmd_buffer
681 * contains the command data.
682 */
683static void vmw_collect_view_ids(struct vmw_ctx_binding_state *cbs,
684 const struct vmw_ctx_bindinfo *bi,
685 u32 max_num)
686{
687 const struct vmw_ctx_bindinfo_view *biv =
688 container_of(bi, struct vmw_ctx_bindinfo_view, bi);
689 unsigned long i;
690
691 cbs->bind_cmd_count = 0;
692 cbs->bind_first_slot = 0;
693
694 for (i = 0; i < max_num; ++i, ++biv) {
695 if (!biv->bi.ctx)
696 break;
697
698 cbs->bind_cmd_buffer[cbs->bind_cmd_count++] =
699 ((biv->bi.scrubbed) ?
700 SVGA3D_INVALID_ID : biv->bi.res->id);
701 }
702}
703
704/**
705 * vmw_collect_dirty_view_ids - Build view id data for a view binding command
706 *
707 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
708 * @bi: Pointer to where the binding info array is stored in @cbs
709 * @dirty: Bitmap indicating which bindings need to be emitted.
710 * @max_num: Maximum number of entries in the @bi array.
711 *
712 * Scans the @bi array for bindings that need to be emitted and
713 * builds a buffer of view id data.
714 * On output, @cbs->bind_cmd_count contains the number of bindings to be
715 * emitted, @cbs->bind_first_slot indicates the index of the first emitted
716 * binding, and @cbs->bind_cmd_buffer contains the command data.
717 */
718static void vmw_collect_dirty_view_ids(struct vmw_ctx_binding_state *cbs,
719 const struct vmw_ctx_bindinfo *bi,
720 unsigned long *dirty,
721 u32 max_num)
722{
723 const struct vmw_ctx_bindinfo_view *biv =
724 container_of(bi, struct vmw_ctx_bindinfo_view, bi);
725 unsigned long i, next_bit;
726
727 cbs->bind_cmd_count = 0;
728 i = find_first_bit(dirty, max_num);
729 next_bit = i;
730 cbs->bind_first_slot = i;
731
732 biv += i;
733 for (; i < max_num; ++i, ++biv) {
734 cbs->bind_cmd_buffer[cbs->bind_cmd_count++] =
735 ((!biv->bi.ctx || biv->bi.scrubbed) ?
736 SVGA3D_INVALID_ID : biv->bi.res->id);
737
738 if (next_bit == i) {
739 next_bit = find_next_bit(dirty, max_num, i + 1);
740 if (next_bit >= max_num)
741 break;
742 }
743 }
744}
745
746/**
747 * vmw_binding_emit_set_sr - Issue delayed DX shader resource binding commands
748 *
749 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
750 */
751static int vmw_emit_set_sr(struct vmw_ctx_binding_state *cbs,
752 int shader_slot)
753{
754 const struct vmw_ctx_bindinfo *loc =
755 &cbs->per_shader[shader_slot].shader_res[0].bi;
756 struct {
757 SVGA3dCmdHeader header;
758 SVGA3dCmdDXSetShaderResources body;
759 } *cmd;
760 size_t cmd_size, view_id_size;
761 const struct vmw_resource *ctx = vmw_cbs_context(cbs);
762
763 vmw_collect_dirty_view_ids(cbs, loc,
764 cbs->per_shader[shader_slot].dirty_sr,
765 SVGA3D_DX_MAX_SRVIEWS);
766 if (cbs->bind_cmd_count == 0)
767 return 0;
768
769 view_id_size = cbs->bind_cmd_count*sizeof(uint32);
770 cmd_size = sizeof(*cmd) + view_id_size;
771 cmd = vmw_fifo_reserve_dx(ctx->dev_priv, cmd_size, ctx->id);
772 if (unlikely(cmd == NULL)) {
773 DRM_ERROR("Failed reserving FIFO space for DX shader"
774 " resource binding.\n");
775 return -ENOMEM;
776 }
777
778 cmd->header.id = SVGA_3D_CMD_DX_SET_SHADER_RESOURCES;
779 cmd->header.size = sizeof(cmd->body) + view_id_size;
780 cmd->body.type = shader_slot + SVGA3D_SHADERTYPE_MIN;
781 cmd->body.startView = cbs->bind_first_slot;
782
783 memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
784
785 vmw_fifo_commit(ctx->dev_priv, cmd_size);
786 bitmap_clear(cbs->per_shader[shader_slot].dirty_sr,
787 cbs->bind_first_slot, cbs->bind_cmd_count);
788
789 return 0;
790}
791
792/**
793 * vmw_binding_emit_set_rt - Issue delayed DX rendertarget binding commands
794 *
795 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
796 */
797static int vmw_emit_set_rt(struct vmw_ctx_binding_state *cbs)
798{
799 const struct vmw_ctx_bindinfo *loc = &cbs->render_targets[0].bi;
800 struct {
801 SVGA3dCmdHeader header;
802 SVGA3dCmdDXSetRenderTargets body;
803 } *cmd;
804 size_t cmd_size, view_id_size;
805 const struct vmw_resource *ctx = vmw_cbs_context(cbs);
806
807 vmw_collect_view_ids(cbs, loc, SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS);
808 view_id_size = cbs->bind_cmd_count*sizeof(uint32);
809 cmd_size = sizeof(*cmd) + view_id_size;
810 cmd = vmw_fifo_reserve_dx(ctx->dev_priv, cmd_size, ctx->id);
811 if (unlikely(cmd == NULL)) {
812 DRM_ERROR("Failed reserving FIFO space for DX render-target"
813 " binding.\n");
814 return -ENOMEM;
815 }
816
817 cmd->header.id = SVGA_3D_CMD_DX_SET_RENDERTARGETS;
818 cmd->header.size = sizeof(cmd->body) + view_id_size;
819
820 if (cbs->ds_view.bi.ctx && !cbs->ds_view.bi.scrubbed)
821 cmd->body.depthStencilViewId = cbs->ds_view.bi.res->id;
822 else
823 cmd->body.depthStencilViewId = SVGA3D_INVALID_ID;
824
825 memcpy(&cmd[1], cbs->bind_cmd_buffer, view_id_size);
826
827 vmw_fifo_commit(ctx->dev_priv, cmd_size);
828
829 return 0;
830
831}
832
833/**
834 * vmw_collect_so_targets - Build SVGA3dSoTarget data for a binding command
835 * without checking which bindings actually need to be emitted
836 *
837 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
838 * @bi: Pointer to where the binding info array is stored in @cbs
839 * @max_num: Maximum number of entries in the @bi array.
840 *
841 * Scans the @bi array for bindings and builds a buffer of SVGA3dSoTarget data.
842 * Stops at the first non-existing binding in the @bi array.
843 * On output, @cbs->bind_cmd_count contains the number of bindings to be
844 * emitted, @cbs->bind_first_slot is set to zero, and @cbs->bind_cmd_buffer
845 * contains the command data.
846 */
847static void vmw_collect_so_targets(struct vmw_ctx_binding_state *cbs,
848 const struct vmw_ctx_bindinfo *bi,
849 u32 max_num)
850{
851 const struct vmw_ctx_bindinfo_so *biso =
852 container_of(bi, struct vmw_ctx_bindinfo_so, bi);
853 unsigned long i;
854 SVGA3dSoTarget *so_buffer = (SVGA3dSoTarget *) cbs->bind_cmd_buffer;
855
856 cbs->bind_cmd_count = 0;
857 cbs->bind_first_slot = 0;
858
859 for (i = 0; i < max_num; ++i, ++biso, ++so_buffer,
860 ++cbs->bind_cmd_count) {
861 if (!biso->bi.ctx)
862 break;
863
864 if (!biso->bi.scrubbed) {
865 so_buffer->sid = biso->bi.res->id;
866 so_buffer->offset = biso->offset;
867 so_buffer->sizeInBytes = biso->size;
868 } else {
869 so_buffer->sid = SVGA3D_INVALID_ID;
870 so_buffer->offset = 0;
871 so_buffer->sizeInBytes = 0;
872 }
873 }
874}
875
876/**
877 * vmw_binding_emit_set_so - Issue delayed streamout binding commands
878 *
879 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
880 */
881static int vmw_emit_set_so(struct vmw_ctx_binding_state *cbs)
882{
883 const struct vmw_ctx_bindinfo *loc = &cbs->so_targets[0].bi;
884 struct {
885 SVGA3dCmdHeader header;
886 SVGA3dCmdDXSetSOTargets body;
887 } *cmd;
888 size_t cmd_size, so_target_size;
889 const struct vmw_resource *ctx = vmw_cbs_context(cbs);
890
891 vmw_collect_so_targets(cbs, loc, SVGA3D_DX_MAX_SOTARGETS);
892 if (cbs->bind_cmd_count == 0)
893 return 0;
894
895 so_target_size = cbs->bind_cmd_count*sizeof(SVGA3dSoTarget);
896 cmd_size = sizeof(*cmd) + so_target_size;
897 cmd = vmw_fifo_reserve_dx(ctx->dev_priv, cmd_size, ctx->id);
898 if (unlikely(cmd == NULL)) {
899 DRM_ERROR("Failed reserving FIFO space for DX SO target"
900 " binding.\n");
901 return -ENOMEM;
902 }
903
904 cmd->header.id = SVGA_3D_CMD_DX_SET_SOTARGETS;
905 cmd->header.size = sizeof(cmd->body) + so_target_size;
906 memcpy(&cmd[1], cbs->bind_cmd_buffer, so_target_size);
907
908 vmw_fifo_commit(ctx->dev_priv, cmd_size);
909
910 return 0;
911
912}
913
914/**
915 * vmw_binding_emit_dirty_ps - Issue delayed per shader binding commands
916 *
917 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
918 *
919 */
920static int vmw_binding_emit_dirty_ps(struct vmw_ctx_binding_state *cbs)
921{
922 struct vmw_dx_shader_bindings *sb = &cbs->per_shader[0];
923 u32 i;
924 int ret;
925
926 for (i = 0; i < SVGA3D_NUM_SHADERTYPE_DX10; ++i, ++sb) {
927 if (!test_bit(VMW_BINDING_PS_SR_BIT, &sb->dirty))
928 continue;
929
930 ret = vmw_emit_set_sr(cbs, i);
931 if (ret)
932 break;
933
934 __clear_bit(VMW_BINDING_PS_SR_BIT, &sb->dirty);
935 }
936
937 return 0;
938}
939
940/**
941 * vmw_collect_dirty_vbs - Build SVGA3dVertexBuffer data for a
942 * SVGA3dCmdDXSetVertexBuffers command
943 *
944 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
945 * @bi: Pointer to where the binding info array is stored in @cbs
946 * @dirty: Bitmap indicating which bindings need to be emitted.
947 * @max_num: Maximum number of entries in the @bi array.
948 *
949 * Scans the @bi array for bindings that need to be emitted and
950 * builds a buffer of SVGA3dVertexBuffer data.
951 * On output, @cbs->bind_cmd_count contains the number of bindings to be
952 * emitted, @cbs->bind_first_slot indicates the index of the first emitted
953 * binding, and @cbs->bind_cmd_buffer contains the command data.
954 */
955static void vmw_collect_dirty_vbs(struct vmw_ctx_binding_state *cbs,
956 const struct vmw_ctx_bindinfo *bi,
957 unsigned long *dirty,
958 u32 max_num)
959{
960 const struct vmw_ctx_bindinfo_vb *biv =
961 container_of(bi, struct vmw_ctx_bindinfo_vb, bi);
962 unsigned long i, next_bit;
963 SVGA3dVertexBuffer *vbs = (SVGA3dVertexBuffer *) &cbs->bind_cmd_buffer;
964
965 cbs->bind_cmd_count = 0;
966 i = find_first_bit(dirty, max_num);
967 next_bit = i;
968 cbs->bind_first_slot = i;
969
970 biv += i;
971 for (; i < max_num; ++i, ++biv, ++vbs) {
972 if (!biv->bi.ctx || biv->bi.scrubbed) {
973 vbs->sid = SVGA3D_INVALID_ID;
974 vbs->stride = 0;
975 vbs->offset = 0;
976 } else {
977 vbs->sid = biv->bi.res->id;
978 vbs->stride = biv->stride;
979 vbs->offset = biv->offset;
980 }
981 cbs->bind_cmd_count++;
982 if (next_bit == i) {
983 next_bit = find_next_bit(dirty, max_num, i + 1);
984 if (next_bit >= max_num)
985 break;
986 }
987 }
988}
989
990/**
991 * vmw_binding_emit_set_vb - Issue delayed vertex buffer binding commands
992 *
993 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
994 *
995 */
996static int vmw_emit_set_vb(struct vmw_ctx_binding_state *cbs)
997{
998 const struct vmw_ctx_bindinfo *loc =
999 &cbs->vertex_buffers[0].bi;
1000 struct {
1001 SVGA3dCmdHeader header;
1002 SVGA3dCmdDXSetVertexBuffers body;
1003 } *cmd;
1004 size_t cmd_size, set_vb_size;
1005 const struct vmw_resource *ctx = vmw_cbs_context(cbs);
1006
1007 vmw_collect_dirty_vbs(cbs, loc, cbs->dirty_vb,
1008 SVGA3D_DX_MAX_VERTEXBUFFERS);
1009 if (cbs->bind_cmd_count == 0)
1010 return 0;
1011
1012 set_vb_size = cbs->bind_cmd_count*sizeof(SVGA3dVertexBuffer);
1013 cmd_size = sizeof(*cmd) + set_vb_size;
1014 cmd = vmw_fifo_reserve_dx(ctx->dev_priv, cmd_size, ctx->id);
1015 if (unlikely(cmd == NULL)) {
1016 DRM_ERROR("Failed reserving FIFO space for DX vertex buffer"
1017 " binding.\n");
1018 return -ENOMEM;
1019 }
1020
1021 cmd->header.id = SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS;
1022 cmd->header.size = sizeof(cmd->body) + set_vb_size;
1023 cmd->body.startBuffer = cbs->bind_first_slot;
1024
1025 memcpy(&cmd[1], cbs->bind_cmd_buffer, set_vb_size);
1026
1027 vmw_fifo_commit(ctx->dev_priv, cmd_size);
1028 bitmap_clear(cbs->dirty_vb,
1029 cbs->bind_first_slot, cbs->bind_cmd_count);
1030
1031 return 0;
1032}
1033
1034/**
1035 * vmw_binding_emit_dirty - Issue delayed binding commands
1036 *
1037 * @cbs: Pointer to the context's struct vmw_ctx_binding_state
1038 *
1039 * This function issues the delayed binding commands that arise from
1040 * previous scrub / unscrub calls. These binding commands are typically
1041 * commands that batch a number of bindings and therefore it makes sense
1042 * to delay them.
1043 */
1044static int vmw_binding_emit_dirty(struct vmw_ctx_binding_state *cbs)
1045{
1046 int ret = 0;
1047 unsigned long hit = 0;
1048
1049 while ((hit = find_next_bit(&cbs->dirty, VMW_BINDING_NUM_BITS, hit))
1050 < VMW_BINDING_NUM_BITS) {
1051
1052 switch (hit) {
1053 case VMW_BINDING_RT_BIT:
1054 ret = vmw_emit_set_rt(cbs);
1055 break;
1056 case VMW_BINDING_PS_BIT:
1057 ret = vmw_binding_emit_dirty_ps(cbs);
1058 break;
1059 case VMW_BINDING_SO_BIT:
1060 ret = vmw_emit_set_so(cbs);
1061 break;
1062 case VMW_BINDING_VB_BIT:
1063 ret = vmw_emit_set_vb(cbs);
1064 break;
1065 default:
1066 BUG();
1067 }
1068 if (ret)
1069 return ret;
1070
1071 __clear_bit(hit, &cbs->dirty);
1072 hit++;
1073 }
1074
1075 return 0;
1076}
1077
1078/**
1079 * vmw_binding_scrub_sr - Schedule a dx shaderresource binding
1080 * scrub from a context
1081 *
1082 * @bi: single binding information.
1083 * @rebind: Whether to issue a bind instead of scrub command.
1084 */
1085static int vmw_binding_scrub_sr(struct vmw_ctx_bindinfo *bi, bool rebind)
1086{
1087 struct vmw_ctx_bindinfo_view *biv =
1088 container_of(bi, struct vmw_ctx_bindinfo_view, bi);
1089 struct vmw_ctx_binding_state *cbs =
1090 vmw_context_binding_state(bi->ctx);
1091
1092 __set_bit(biv->slot, cbs->per_shader[biv->shader_slot].dirty_sr);
1093 __set_bit(VMW_BINDING_PS_SR_BIT,
1094 &cbs->per_shader[biv->shader_slot].dirty);
1095 __set_bit(VMW_BINDING_PS_BIT, &cbs->dirty);
1096
1097 return 0;
1098}
1099
1100/**
1101 * vmw_binding_scrub_dx_rt - Schedule a dx rendertarget binding
1102 * scrub from a context
1103 *
1104 * @bi: single binding information.
1105 * @rebind: Whether to issue a bind instead of scrub command.
1106 */
1107static int vmw_binding_scrub_dx_rt(struct vmw_ctx_bindinfo *bi, bool rebind)
1108{
1109 struct vmw_ctx_binding_state *cbs =
1110 vmw_context_binding_state(bi->ctx);
1111
1112 __set_bit(VMW_BINDING_RT_BIT, &cbs->dirty);
1113
1114 return 0;
1115}
1116
1117/**
1118 * vmw_binding_scrub_so - Schedule a dx streamoutput buffer binding
1119 * scrub from a context
1120 *
1121 * @bi: single binding information.
1122 * @rebind: Whether to issue a bind instead of scrub command.
1123 */
1124static int vmw_binding_scrub_so(struct vmw_ctx_bindinfo *bi, bool rebind)
1125{
1126 struct vmw_ctx_binding_state *cbs =
1127 vmw_context_binding_state(bi->ctx);
1128
1129 __set_bit(VMW_BINDING_SO_BIT, &cbs->dirty);
1130
1131 return 0;
1132}
1133
1134/**
1135 * vmw_binding_scrub_vb - Schedule a dx vertex buffer binding
1136 * scrub from a context
1137 *
1138 * @bi: single binding information.
1139 * @rebind: Whether to issue a bind instead of scrub command.
1140 */
1141static int vmw_binding_scrub_vb(struct vmw_ctx_bindinfo *bi, bool rebind)
1142{
1143 struct vmw_ctx_bindinfo_vb *bivb =
1144 container_of(bi, struct vmw_ctx_bindinfo_vb, bi);
1145 struct vmw_ctx_binding_state *cbs =
1146 vmw_context_binding_state(bi->ctx);
1147
1148 __set_bit(bivb->slot, cbs->dirty_vb);
1149 __set_bit(VMW_BINDING_VB_BIT, &cbs->dirty);
1150
1151 return 0;
1152}
1153
1154/**
1155 * vmw_binding_scrub_ib - scrub a dx index buffer binding from a context
1156 *
1157 * @bi: single binding information.
1158 * @rebind: Whether to issue a bind instead of scrub command.
1159 */
1160static int vmw_binding_scrub_ib(struct vmw_ctx_bindinfo *bi, bool rebind)
1161{
1162 struct vmw_ctx_bindinfo_ib *binding =
1163 container_of(bi, typeof(*binding), bi);
1164 struct vmw_private *dev_priv = bi->ctx->dev_priv;
1165 struct {
1166 SVGA3dCmdHeader header;
1167 SVGA3dCmdDXSetIndexBuffer body;
1168 } *cmd;
1169
1170 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), bi->ctx->id);
1171 if (unlikely(cmd == NULL)) {
1172 DRM_ERROR("Failed reserving FIFO space for DX index buffer "
1173 "binding.\n");
1174 return -ENOMEM;
1175 }
1176 cmd->header.id = SVGA_3D_CMD_DX_SET_INDEX_BUFFER;
1177 cmd->header.size = sizeof(cmd->body);
1178 if (rebind) {
1179 cmd->body.sid = bi->res->id;
1180 cmd->body.format = binding->format;
1181 cmd->body.offset = binding->offset;
1182 } else {
1183 cmd->body.sid = SVGA3D_INVALID_ID;
1184 cmd->body.format = 0;
1185 cmd->body.offset = 0;
1186 }
1187
1188 vmw_fifo_commit(dev_priv, sizeof(*cmd));
1189
1190 return 0;
1191}
1192
1193/**
1194 * vmw_binding_state_alloc - Allocate a struct vmw_ctx_binding_state with
1195 * memory accounting.
1196 *
1197 * @dev_priv: Pointer to a device private structure.
1198 *
1199 * Returns a pointer to a newly allocated struct or an error pointer on error.
1200 */
1201struct vmw_ctx_binding_state *
1202vmw_binding_state_alloc(struct vmw_private *dev_priv)
1203{
1204 struct vmw_ctx_binding_state *cbs;
1205 int ret;
1206
1207 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), sizeof(*cbs),
1208 false, false);
1209 if (ret)
1210 return ERR_PTR(ret);
1211
1212 cbs = vzalloc(sizeof(*cbs));
1213 if (!cbs) {
1214 ttm_mem_global_free(vmw_mem_glob(dev_priv), sizeof(*cbs));
1215 return ERR_PTR(-ENOMEM);
1216 }
1217
1218 cbs->dev_priv = dev_priv;
1219 INIT_LIST_HEAD(&cbs->list);
1220
1221 return cbs;
1222}
1223
1224/**
1225 * vmw_binding_state_free - Free a struct vmw_ctx_binding_state and its
1226 * memory accounting info.
1227 *
1228 * @cbs: Pointer to the struct vmw_ctx_binding_state to be freed.
1229 */
1230void vmw_binding_state_free(struct vmw_ctx_binding_state *cbs)
1231{
1232 struct vmw_private *dev_priv = cbs->dev_priv;
1233
1234 vfree(cbs);
1235 ttm_mem_global_free(vmw_mem_glob(dev_priv), sizeof(*cbs));
1236}
1237
1238/**
1239 * vmw_binding_state_list - Get the binding list of a
1240 * struct vmw_ctx_binding_state
1241 *
1242 * @cbs: Pointer to the struct vmw_ctx_binding_state
1243 *
1244 * Returns the binding list which can be used to traverse through the bindings
1245 * and access the resource information of all bindings.
1246 */
1247struct list_head *vmw_binding_state_list(struct vmw_ctx_binding_state *cbs)
1248{
1249 return &cbs->list;
1250}
1251
1252/**
1253 * vmwgfx_binding_state_reset - clear a struct vmw_ctx_binding_state
1254 *
1255 * @cbs: Pointer to the struct vmw_ctx_binding_state to be cleared
1256 *
1257 * Drops all bindings registered in @cbs. No device binding actions are
1258 * performed.
1259 */
1260void vmw_binding_state_reset(struct vmw_ctx_binding_state *cbs)
1261{
1262 struct vmw_ctx_bindinfo *entry, *next;
1263
1264 list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
1265 vmw_binding_drop(entry);
1266}
1267
1268/*
1269 * This function is unused at run-time, and only used to hold various build
1270 * asserts important for code optimization assumptions.
1271 */
1272static void vmw_binding_build_asserts(void)
1273{
1274 BUILD_BUG_ON(SVGA3D_NUM_SHADERTYPE_DX10 != 3);
1275 BUILD_BUG_ON(SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS > SVGA3D_RT_MAX);
1276 BUILD_BUG_ON(sizeof(uint32) != sizeof(u32));
1277
1278 /*
1279 * struct vmw_ctx_binding_state::bind_cmd_buffer is used for various
1280 * view id arrays.
1281 */
1282 BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_RT_MAX);
1283 BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_DX_MAX_SRVIEWS);
1284 BUILD_BUG_ON(VMW_MAX_VIEW_BINDINGS < SVGA3D_DX_MAX_CONSTBUFFERS);
1285
1286 /*
1287 * struct vmw_ctx_binding_state::bind_cmd_buffer is used for
1288 * u32 view ids, SVGA3dSoTargets and SVGA3dVertexBuffers
1289 */
1290 BUILD_BUG_ON(SVGA3D_DX_MAX_SOTARGETS*sizeof(SVGA3dSoTarget) >
1291 VMW_MAX_VIEW_BINDINGS*sizeof(u32));
1292 BUILD_BUG_ON(SVGA3D_DX_MAX_VERTEXBUFFERS*sizeof(SVGA3dVertexBuffer) >
1293 VMW_MAX_VIEW_BINDINGS*sizeof(u32));
1294}
drivers/gpu/drm/vmwgfx/vmwgfx_binding.h+209−0
@@ -0,0 +1,209 @@
1/**************************************************************************
2 *
3 * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27#ifndef _VMWGFX_BINDING_H_
28#define _VMWGFX_BINDING_H_
29
30#include "device_include/svga3d_reg.h"
31#include <linux/list.h>
32
33#define VMW_MAX_VIEW_BINDINGS 128
34
35struct vmw_private;
36struct vmw_ctx_binding_state;
37
38/*
39 * enum vmw_ctx_binding_type - abstract resource to context binding types
40 */
41enum vmw_ctx_binding_type {
42 vmw_ctx_binding_shader,
43 vmw_ctx_binding_rt,
44 vmw_ctx_binding_tex,
45 vmw_ctx_binding_cb,
46 vmw_ctx_binding_dx_shader,
47 vmw_ctx_binding_dx_rt,
48 vmw_ctx_binding_sr,
49 vmw_ctx_binding_ds,
50 vmw_ctx_binding_so,
51 vmw_ctx_binding_vb,
52 vmw_ctx_binding_ib,
53 vmw_ctx_binding_max
54};
55
56/**
57 * struct vmw_ctx_bindinfo - single binding metadata
58 *
59 * @ctx_list: List head for the context's list of bindings.
60 * @res_list: List head for a resource's list of bindings.
61 * @ctx: Non-refcounted pointer to the context that owns the binding. NULL
62 * indicates no binding present.
63 * @res: Non-refcounted pointer to the resource the binding points to. This
64 * is typically a surface or a view.
65 * @bt: Binding type.
66 * @scrubbed: Whether the binding has been scrubbed from the context.
67 */
68struct vmw_ctx_bindinfo {
69 struct list_head ctx_list;
70 struct list_head res_list;
71 struct vmw_resource *ctx;
72 struct vmw_resource *res;
73 enum vmw_ctx_binding_type bt;
74 bool scrubbed;
75};
76
77/**
78 * struct vmw_ctx_bindinfo_tex - texture stage binding metadata
79 *
80 * @bi: struct vmw_ctx_bindinfo we derive from.
81 * @texture_stage: Device data used to reconstruct binding command.
82 */
83struct vmw_ctx_bindinfo_tex {
84 struct vmw_ctx_bindinfo bi;
85 uint32 texture_stage;
86};
87
88/**
89 * struct vmw_ctx_bindinfo_shader - Shader binding metadata
90 *
91 * @bi: struct vmw_ctx_bindinfo we derive from.
92 * @shader_slot: Device data used to reconstruct binding command.
93 */
94struct vmw_ctx_bindinfo_shader {
95 struct vmw_ctx_bindinfo bi;
96 SVGA3dShaderType shader_slot;
97};
98
99/**
100 * struct vmw_ctx_bindinfo_cb - Constant buffer binding metadata
101 *
102 * @bi: struct vmw_ctx_bindinfo we derive from.
103 * @shader_slot: Device data used to reconstruct binding command.
104 * @offset: Device data used to reconstruct binding command.
105 * @size: Device data used to reconstruct binding command.
106 * @slot: Device data used to reconstruct binding command.
107 */
108struct vmw_ctx_bindinfo_cb {
109 struct vmw_ctx_bindinfo bi;
110 SVGA3dShaderType shader_slot;
111 uint32 offset;
112 uint32 size;
113 uint32 slot;
114};
115
116/**
117 * struct vmw_ctx_bindinfo_view - View binding metadata
118 *
119 * @bi: struct vmw_ctx_bindinfo we derive from.
120 * @shader_slot: Device data used to reconstruct binding command.
121 * @slot: Device data used to reconstruct binding command.
122 */
123struct vmw_ctx_bindinfo_view {
124 struct vmw_ctx_bindinfo bi;
125 SVGA3dShaderType shader_slot;
126 uint32 slot;
127};
128
129/**
130 * struct vmw_ctx_bindinfo_so - StreamOutput binding metadata
131 *
132 * @bi: struct vmw_ctx_bindinfo we derive from.
133 * @offset: Device data used to reconstruct binding command.
134 * @size: Device data used to reconstruct binding command.
135 * @slot: Device data used to reconstruct binding command.
136 */
137struct vmw_ctx_bindinfo_so {
138 struct vmw_ctx_bindinfo bi;
139 uint32 offset;
140 uint32 size;
141 uint32 slot;
142};
143
144/**
145 * struct vmw_ctx_bindinfo_vb - Vertex buffer binding metadata
146 *
147 * @bi: struct vmw_ctx_bindinfo we derive from.
148 * @offset: Device data used to reconstruct binding command.
149 * @stride: Device data used to reconstruct binding command.
150 * @slot: Device data used to reconstruct binding command.
151 */
152struct vmw_ctx_bindinfo_vb {
153 struct vmw_ctx_bindinfo bi;
154 uint32 offset;
155 uint32 stride;
156 uint32 slot;
157};
158
159/**
160 * struct vmw_ctx_bindinfo_ib - StreamOutput binding metadata
161 *
162 * @bi: struct vmw_ctx_bindinfo we derive from.
163 * @offset: Device data used to reconstruct binding command.
164 * @format: Device data used to reconstruct binding command.
165 */
166struct vmw_ctx_bindinfo_ib {
167 struct vmw_ctx_bindinfo bi;
168 uint32 offset;
169 uint32 format;
170};
171
172/**
173 * struct vmw_dx_shader_bindings - per shader type context binding state
174 *
175 * @shader: The shader binding for this shader type
176 * @const_buffer: Const buffer bindings for this shader type.
177 * @shader_res: Shader resource view bindings for this shader type.
178 * @dirty_sr: Bitmap tracking individual shader resource bindings changes
179 * that have not yet been emitted to the device.
180 * @dirty: Bitmap tracking per-binding type binding changes that have not
181 * yet been emitted to the device.
182 */
183struct vmw_dx_shader_bindings {
184 struct vmw_ctx_bindinfo_shader shader;
185 struct vmw_ctx_bindinfo_cb const_buffers[SVGA3D_DX_MAX_CONSTBUFFERS];
186 struct vmw_ctx_bindinfo_view shader_res[SVGA3D_DX_MAX_SRVIEWS];
187 DECLARE_BITMAP(dirty_sr, SVGA3D_DX_MAX_SRVIEWS);
188 unsigned long dirty;
189};
190
191extern void vmw_binding_add(struct vmw_ctx_binding_state *cbs,
192 const struct vmw_ctx_bindinfo *ci,
193 u32 shader_slot, u32 slot);
194extern void
195vmw_binding_state_commit(struct vmw_ctx_binding_state *to,
196 struct vmw_ctx_binding_state *from);
197extern void vmw_binding_res_list_kill(struct list_head *head);
198extern void vmw_binding_res_list_scrub(struct list_head *head);
199extern int vmw_binding_rebind_all(struct vmw_ctx_binding_state *cbs);
200extern void vmw_binding_state_kill(struct vmw_ctx_binding_state *cbs);
201extern void vmw_binding_state_scrub(struct vmw_ctx_binding_state *cbs);
202extern struct vmw_ctx_binding_state *
203vmw_binding_state_alloc(struct vmw_private *dev_priv);
204extern void vmw_binding_state_free(struct vmw_ctx_binding_state *cbs);
205extern struct list_head *
206vmw_binding_state_list(struct vmw_ctx_binding_state *cbs);
207extern void vmw_binding_state_reset(struct vmw_ctx_binding_state *cbs);
208
209#endif
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c+2−3
@@ -916,9 +916,8 @@ static void *vmw_cmdbuf_reserve_cur(struct vmw_cmdbuf_man *man, · 915 unmodified lines
916 916
917 cur = man->cur;917 cur = man->cur;
918 if (cur && (size + man->cur_pos > cur->size ||918 if (cur && (size + man->cur_pos > cur->size ||
919 (ctx_id != SVGA3D_INVALID_ID &&919 ((cur->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT) &&
920 (cur->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT) &&920 ctx_id != cur->cb_header->dxContext)))
921 ctx_id != cur->cb_header->dxContext)))
922 __vmw_cmdbuf_cur_flush(man);921 __vmw_cmdbuf_cur_flush(man);
923 922
924 if (!man->cur) {923 if (!man->cur) {
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c+14−10
@@ -26,15 +26,10 @@ · 25 unmodified lines
26 **************************************************************************/26 **************************************************************************/
27 27
28#include "vmwgfx_drv.h"28#include "vmwgfx_drv.h"
29#include "vmwgfx_resource_priv.h"
29 30
30#define VMW_CMDBUF_RES_MAN_HT_ORDER 1231#define VMW_CMDBUF_RES_MAN_HT_ORDER 12
31 32
32enum vmw_cmdbuf_res_state {
33 VMW_CMDBUF_RES_COMMITED,
34 VMW_CMDBUF_RES_ADD,
35 VMW_CMDBUF_RES_DEL
36};
37
38/**33/**
39 * struct vmw_cmdbuf_res - Command buffer managed resource entry.34 * struct vmw_cmdbuf_res - Command buffer managed resource entry.
40 *35 *
@@ -132,9 +127,12 @@ void vmw_cmdbuf_res_commit(struct list_head *list) · 91 unmodified lines
132 127
133 list_for_each_entry_safe(entry, next, list, head) {128 list_for_each_entry_safe(entry, next, list, head) {
134 list_del(&entry->head);129 list_del(&entry->head);
130 if (entry->res->func->commit_notify)
131 entry->res->func->commit_notify(entry->res,
132 entry->state);
135 switch (entry->state) {133 switch (entry->state) {
136 case VMW_CMDBUF_RES_ADD:134 case VMW_CMDBUF_RES_ADD:
137 entry->state = VMW_CMDBUF_RES_COMMITED;135 entry->state = VMW_CMDBUF_RES_COMMITTED;
138 list_add_tail(&entry->head, &entry->man->list);136 list_add_tail(&entry->head, &entry->man->list);
139 break;137 break;
140 case VMW_CMDBUF_RES_DEL:138 case VMW_CMDBUF_RES_DEL:
@@ -175,7 +173,7 @@ void vmw_cmdbuf_res_revert(struct list_head *list) · 34 unmodified lines
175 &entry->hash);173 &entry->hash);
176 list_del(&entry->head);174 list_del(&entry->head);
177 list_add_tail(&entry->head, &entry->man->list);175 list_add_tail(&entry->head, &entry->man->list);
178 entry->state = VMW_CMDBUF_RES_COMMITED;176 entry->state = VMW_CMDBUF_RES_COMMITTED;
179 break;177 break;
180 default:178 default:
181 BUG();179 BUG();
@@ -231,6 +229,9 @@ out_invalid_key: · 49 unmodified lines
231 * @res_type: The resource type.229 * @res_type: The resource type.
232 * @user_key: The user-space id of the resource.230 * @user_key: The user-space id of the resource.
233 * @list: The staging list.231 * @list: The staging list.
232 * @res_p: If the resource is in an already committed state, points to the
233 * struct vmw_resource on successful return. The pointer will be
234 * non ref-counted.
234 *235 *
235 * This function looks up the struct vmw_cmdbuf_res entry from the manager236 * This function looks up the struct vmw_cmdbuf_res entry from the manager
236 * hash table and, if it exists, removes it. Depending on its current staging237 * hash table and, if it exists, removes it. Depending on its current staging
@@ -240,7 +241,8 @@ out_invalid_key: · 3 unmodified lines
240int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,241int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
241 enum vmw_cmdbuf_res_type res_type,242 enum vmw_cmdbuf_res_type res_type,
242 u32 user_key,243 u32 user_key,
243 struct list_head *list)244 struct list_head *list,
245 struct vmw_resource **res_p)
244{246{
245 struct vmw_cmdbuf_res *entry;247 struct vmw_cmdbuf_res *entry;
246 struct drm_hash_item *hash;248 struct drm_hash_item *hash;
@@ -256,12 +258,14 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, · 9 unmodified lines
256 switch (entry->state) {258 switch (entry->state) {
257 case VMW_CMDBUF_RES_ADD:259 case VMW_CMDBUF_RES_ADD:
258 vmw_cmdbuf_res_free(man, entry);260 vmw_cmdbuf_res_free(man, entry);
261 *res_p = NULL;
259 break;262 break;
260 case VMW_CMDBUF_RES_COMMITED:263 case VMW_CMDBUF_RES_COMMITTED:
261 (void) drm_ht_remove_item(&man->resources, &entry->hash);264 (void) drm_ht_remove_item(&man->resources, &entry->hash);
262 list_del(&entry->head);265 list_del(&entry->head);
263 entry->state = VMW_CMDBUF_RES_DEL;266 entry->state = VMW_CMDBUF_RES_DEL;
264 list_add_tail(&entry->head, list);267 list_add_tail(&entry->head, list);
268 *res_p = entry->res;
265 break;269 break;
266 default:270 default:
267 BUG();271 BUG();
drivers/gpu/drm/vmwgfx/vmwgfx_context.c+341−394
@@ -27,19 +27,18 @@ · 26 unmodified lines
27 27
28#include "vmwgfx_drv.h"28#include "vmwgfx_drv.h"
29#include "vmwgfx_resource_priv.h"29#include "vmwgfx_resource_priv.h"
30#include "vmwgfx_binding.h"
30#include "ttm/ttm_placement.h"31#include "ttm/ttm_placement.h"
31 32
32struct vmw_user_context {33struct vmw_user_context {
33 struct ttm_base_object base;34 struct ttm_base_object base;
34 struct vmw_resource res;35 struct vmw_resource res;
35 struct vmw_ctx_binding_state cbs;36 struct vmw_ctx_binding_state *cbs;
36 struct vmw_cmdbuf_res_manager *man;37 struct vmw_cmdbuf_res_manager *man;
38 struct vmw_resource *cotables[SVGA_COTABLE_DX10_MAX];
39 spinlock_t cotable_lock;
37};40};
38 41
39
40
41typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);
42
43static void vmw_user_context_free(struct vmw_resource *res);42static void vmw_user_context_free(struct vmw_resource *res);
44static struct vmw_resource *43static struct vmw_resource *
45vmw_user_context_base_to_res(struct ttm_base_object *base);44vmw_user_context_base_to_res(struct ttm_base_object *base);
@@ -51,12 +50,14 @@ static int vmw_gb_context_unbind(struct vmw_resource *res, · 5 unmodified lines
51 bool readback,50 bool readback,
52 struct ttm_validate_buffer *val_buf);51 struct ttm_validate_buffer *val_buf);
53static int vmw_gb_context_destroy(struct vmw_resource *res);52static int vmw_gb_context_destroy(struct vmw_resource *res);
54static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);53static int vmw_dx_context_create(struct vmw_resource *res);
55static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,54static int vmw_dx_context_bind(struct vmw_resource *res,
56 bool rebind);55 struct ttm_validate_buffer *val_buf);
57static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);56static int vmw_dx_context_unbind(struct vmw_resource *res,
58static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs);57 bool readback,
59static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs);58 struct ttm_validate_buffer *val_buf);
59static int vmw_dx_context_destroy(struct vmw_resource *res);
60
60static uint64_t vmw_user_context_size;61static uint64_t vmw_user_context_size;
61 62
62static const struct vmw_user_resource_conv user_context_conv = {63static const struct vmw_user_resource_conv user_context_conv = {
@@ -93,15 +94,36 @@ static const struct vmw_res_func vmw_gb_context_func = { · 30 unmodified lines
93 .unbind = vmw_gb_context_unbind94 .unbind = vmw_gb_context_unbind
94};95};
95 96
96static const vmw_scrub_func vmw_scrub_funcs[vmw_ctx_binding_max] = {97static const struct vmw_res_func vmw_dx_context_func = {
97 [vmw_ctx_binding_shader] = vmw_context_scrub_shader,98 .res_type = vmw_res_dx_context,
98 [vmw_ctx_binding_rt] = vmw_context_scrub_render_target,99 .needs_backup = true,
99 [vmw_ctx_binding_tex] = vmw_context_scrub_texture };100 .may_evict = true,
101 .type_name = "dx contexts",
102 .backup_placement = &vmw_mob_placement,
103 .create = vmw_dx_context_create,
104 .destroy = vmw_dx_context_destroy,
105 .bind = vmw_dx_context_bind,
106 .unbind = vmw_dx_context_unbind
107};
100 108
101/**109/**
102 * Context management:110 * Context management:
103 */111 */
104 112
113static void vmw_context_cotables_unref(struct vmw_user_context *uctx)
114{
115 struct vmw_resource *res;
116 int i;
117
118 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
119 spin_lock(&uctx->cotable_lock);
120 res = uctx->cotables[i];
121 uctx->cotables[i] = NULL;
122 spin_unlock(&uctx->cotable_lock);
123 vmw_resource_unreference(&res);
124 }
125}
126
105static void vmw_hw_context_destroy(struct vmw_resource *res)127static void vmw_hw_context_destroy(struct vmw_resource *res)
106{128{
107 struct vmw_user_context *uctx =129 struct vmw_user_context *uctx =
@@ -113,17 +135,19 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) · 5 unmodified lines
113 } *cmd;135 } *cmd;
114 136
115 137
116 if (res->func->destroy == vmw_gb_context_destroy) {138 if (res->func->destroy == vmw_gb_context_destroy ||
139 res->func->destroy == vmw_dx_context_destroy) {
117 mutex_lock(&dev_priv->cmdbuf_mutex);140 mutex_lock(&dev_priv->cmdbuf_mutex);
118 vmw_cmdbuf_res_man_destroy(uctx->man);141 vmw_cmdbuf_res_man_destroy(uctx->man);
119 mutex_lock(&dev_priv->binding_mutex);142 mutex_lock(&dev_priv->binding_mutex);
120 (void) vmw_context_binding_state_kill(&uctx->cbs);143 vmw_binding_state_kill(uctx->cbs);
121 (void) vmw_gb_context_destroy(res);144 (void) res->func->destroy(res);
122 mutex_unlock(&dev_priv->binding_mutex);145 mutex_unlock(&dev_priv->binding_mutex);
123 if (dev_priv->pinned_bo != NULL &&146 if (dev_priv->pinned_bo != NULL &&
124 !dev_priv->query_cid_valid)147 !dev_priv->query_cid_valid)
125 __vmw_execbuf_release_pinned_bo(dev_priv, NULL);148 __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
126 mutex_unlock(&dev_priv->cmdbuf_mutex);149 mutex_unlock(&dev_priv->cmdbuf_mutex);
150 vmw_context_cotables_unref(uctx);
127 return;151 return;
128 }152 }
129 153
@@ -144,16 +168,20 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) · 14 unmodified lines
144}168}
145 169
146static int vmw_gb_context_init(struct vmw_private *dev_priv,170static int vmw_gb_context_init(struct vmw_private *dev_priv,
171 bool dx,
147 struct vmw_resource *res,172 struct vmw_resource *res,
148 void (*res_free) (struct vmw_resource *res))173 void (*res_free)(struct vmw_resource *res))
149{174{
150 int ret;175 int ret, i;
151 struct vmw_user_context *uctx =176 struct vmw_user_context *uctx =
152 container_of(res, struct vmw_user_context, res);177 container_of(res, struct vmw_user_context, res);
153 178
179 res->backup_size = (dx ? sizeof(SVGADXContextMobFormat) :
180 SVGA3D_CONTEXT_DATA_SIZE);
154 ret = vmw_resource_init(dev_priv, res, true,181 ret = vmw_resource_init(dev_priv, res, true,
155 res_free, &vmw_gb_context_func);182 res_free,
156 res->backup_size = SVGA3D_CONTEXT_DATA_SIZE;183 dx ? &vmw_dx_context_func :
184 &vmw_gb_context_func);
157 if (unlikely(ret != 0))185 if (unlikely(ret != 0))
158 goto out_err;186 goto out_err;
159 187
@@ -166,12 +194,32 @@ static int vmw_gb_context_init(struct vmw_private *dev_priv, · 6 unmodified lines
166 }194 }
167 }195 }
168 196
169 memset(&uctx->cbs, 0, sizeof(uctx->cbs));197 uctx->cbs = vmw_binding_state_alloc(dev_priv);
170 INIT_LIST_HEAD(&uctx->cbs.list);198 if (IS_ERR(uctx->cbs)) {
199 ret = PTR_ERR(uctx->cbs);
200 goto out_err;
201 }
202
203 spin_lock_init(&uctx->cotable_lock);
204
205 if (dx) {
206 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
207 uctx->cotables[i] = vmw_cotable_alloc(dev_priv,
208 &uctx->res, i);
209 if (unlikely(uctx->cotables[i] == NULL)) {
210 ret = -ENOMEM;
211 goto out_cotables;
212 }
213 }
214 }
215
216
171 217
172 vmw_resource_activate(res, vmw_hw_context_destroy);218 vmw_resource_activate(res, vmw_hw_context_destroy);
173 return 0;219 return 0;
174 220
221out_cotables:
222 vmw_context_cotables_unref(uctx);
175out_err:223out_err:
176 if (res_free)224 if (res_free)
177 res_free(res);225 res_free(res);
@@ -182,7 +230,8 @@ out_err: · 4 unmodified lines
182 230
183static int vmw_context_init(struct vmw_private *dev_priv,231static int vmw_context_init(struct vmw_private *dev_priv,
184 struct vmw_resource *res,232 struct vmw_resource *res,
185 void (*res_free) (struct vmw_resource *res))233 void (*res_free)(struct vmw_resource *res),
234 bool dx)
186{235{
187 int ret;236 int ret;
188 237
@@ -192,7 +241,7 @@ static int vmw_context_init(struct vmw_private *dev_priv, · 3 unmodified lines
192 } *cmd;241 } *cmd;
193 242
194 if (dev_priv->has_mob)243 if (dev_priv->has_mob)
195 return vmw_gb_context_init(dev_priv, res, res_free);244 return vmw_gb_context_init(dev_priv, dx, res, res_free);
196 245
197 ret = vmw_resource_init(dev_priv, res, false,246 ret = vmw_resource_init(dev_priv, res, false,
198 res_free, &vmw_legacy_context_func);247 res_free, &vmw_legacy_context_func);
@@ -232,19 +281,10 @@ out_early: · 33 unmodified lines
232 return ret;281 return ret;
233}282}
234 283
235struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
236{
237 struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
238 int ret;
239
240 if (unlikely(res == NULL))
241 return NULL;
242
243 ret = vmw_context_init(dev_priv, res, NULL);
244
245 return (ret == 0) ? res : NULL;
246}
247 284
285/*
286 * GB context.
287 */
248 288
249static int vmw_gb_context_create(struct vmw_resource *res)289static int vmw_gb_context_create(struct vmw_resource *res)
250{290{
@@ -309,7 +349,6 @@ static int vmw_gb_context_bind(struct vmw_resource *res, · 58 unmodified lines
309 "binding.\n");349 "binding.\n");
310 return -ENOMEM;350 return -ENOMEM;
311 }351 }
312
313 cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;352 cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
314 cmd->header.size = sizeof(cmd->body);353 cmd->header.size = sizeof(cmd->body);
315 cmd->body.cid = res->id;354 cmd->body.cid = res->id;
@@ -346,7 +385,7 @@ static int vmw_gb_context_unbind(struct vmw_resource *res, · 30 unmodified lines
346 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);385 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
347 386
348 mutex_lock(&dev_priv->binding_mutex);387 mutex_lock(&dev_priv->binding_mutex);
349 vmw_context_binding_state_scrub(&uctx->cbs);388 vmw_binding_state_scrub(uctx->cbs);
350 389
351 submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);390 submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
352 391
@@ -419,6 +458,221 @@ static int vmw_gb_context_destroy(struct vmw_resource *res) · 66 unmodified lines
419 return 0;458 return 0;
420}459}
421 460
461/*
462 * DX context.
463 */
464
465static int vmw_dx_context_create(struct vmw_resource *res)
466{
467 struct vmw_private *dev_priv = res->dev_priv;
468 int ret;
469 struct {
470 SVGA3dCmdHeader header;
471 SVGA3dCmdDXDefineContext body;
472 } *cmd;
473
474 if (likely(res->id != -1))
475 return 0;
476
477 ret = vmw_resource_alloc_id(res);
478 if (unlikely(ret != 0)) {
479 DRM_ERROR("Failed to allocate a context id.\n");
480 goto out_no_id;
481 }
482
483 if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) {
484 ret = -EBUSY;
485 goto out_no_fifo;
486 }
487
488 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
489 if (unlikely(cmd == NULL)) {
490 DRM_ERROR("Failed reserving FIFO space for context "
491 "creation.\n");
492 ret = -ENOMEM;
493 goto out_no_fifo;
494 }
495
496 cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT;
497 cmd->header.size = sizeof(cmd->body);
498 cmd->body.cid = res->id;
499 vmw_fifo_commit(dev_priv, sizeof(*cmd));
500 vmw_fifo_resource_inc(dev_priv);
501
502 return 0;
503
504out_no_fifo:
505 vmw_resource_release_id(res);
506out_no_id:
507 return ret;
508}
509
510static int vmw_dx_context_bind(struct vmw_resource *res,
511 struct ttm_validate_buffer *val_buf)
512{
513 struct vmw_private *dev_priv = res->dev_priv;
514 struct {
515 SVGA3dCmdHeader header;
516 SVGA3dCmdDXBindContext body;
517 } *cmd;
518 struct ttm_buffer_object *bo = val_buf->bo;
519
520 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
521
522 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
523 if (unlikely(cmd == NULL)) {
524 DRM_ERROR("Failed reserving FIFO space for context "
525 "binding.\n");
526 return -ENOMEM;
527 }
528
529 cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
530 cmd->header.size = sizeof(cmd->body);
531 cmd->body.cid = res->id;
532 cmd->body.mobid = bo->mem.start;
533 cmd->body.validContents = res->backup_dirty;
534 res->backup_dirty = false;
535 vmw_fifo_commit(dev_priv, sizeof(*cmd));
536
537
538 return 0;
539}
540
541/**
542 * vmw_dx_context_scrub_cotables - Scrub all bindings and
543 * cotables from a context
544 *
545 * @ctx: Pointer to the context resource
546 * @readback: Whether to save the otable contents on scrubbing.
547 *
548 * COtables must be unbound before their context, but unbinding requires
549 * the backup buffer being reserved, whereas scrubbing does not.
550 * This function scrubs all cotables of a context, potentially reading back
551 * the contents into their backup buffers. However, scrubbing cotables
552 * also makes the device context invalid, so scrub all bindings first so
553 * that doesn't have to be done later with an invalid context.
554 */
555void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
556 bool readback)
557{
558 struct vmw_user_context *uctx =
559 container_of(ctx, struct vmw_user_context, res);
560 int i;
561
562 vmw_binding_state_scrub(uctx->cbs);
563 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
564 struct vmw_resource *res;
565
566 /* Avoid racing with ongoing cotable destruction. */
567 spin_lock(&uctx->cotable_lock);
568 res = uctx->cotables[vmw_cotable_scrub_order[i]];
569 if (res)
570 res = vmw_resource_reference_unless_doomed(res);
571 spin_unlock(&uctx->cotable_lock);
572 if (!res)
573 continue;
574
575 WARN_ON(vmw_cotable_scrub(res, readback));
576 vmw_resource_unreference(&res);
577 }
578}
579
580static int vmw_dx_context_unbind(struct vmw_resource *res,
581 bool readback,
582 struct ttm_validate_buffer *val_buf)
583{
584 struct vmw_private *dev_priv = res->dev_priv;
585 struct ttm_buffer_object *bo = val_buf->bo;
586 struct vmw_fence_obj *fence;
587
588 struct {
589 SVGA3dCmdHeader header;
590 SVGA3dCmdDXReadbackContext body;
591 } *cmd1;
592 struct {
593 SVGA3dCmdHeader header;
594 SVGA3dCmdDXBindContext body;
595 } *cmd2;
596 uint32_t submit_size;
597 uint8_t *cmd;
598
599
600 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
601
602 mutex_lock(&dev_priv->binding_mutex);
603 vmw_dx_context_scrub_cotables(res, readback);
604
605 submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
606
607 cmd = vmw_fifo_reserve(dev_priv, submit_size);
608 if (unlikely(cmd == NULL)) {
609 DRM_ERROR("Failed reserving FIFO space for context "
610 "unbinding.\n");
611 mutex_unlock(&dev_priv->binding_mutex);
612 return -ENOMEM;
613 }
614
615 cmd2 = (void *) cmd;
616 if (readback) {
617 cmd1 = (void *) cmd;
618 cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT;
619 cmd1->header.size = sizeof(cmd1->body);
620 cmd1->body.cid = res->id;
621 cmd2 = (void *) (&cmd1[1]);
622 }
623 cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
624 cmd2->header.size = sizeof(cmd2->body);
625 cmd2->body.cid = res->id;
626 cmd2->body.mobid = SVGA3D_INVALID_ID;
627
628 vmw_fifo_commit(dev_priv, submit_size);
629 mutex_unlock(&dev_priv->binding_mutex);
630
631 /*
632 * Create a fence object and fence the backup buffer.
633 */
634
635 (void) vmw_execbuf_fence_commands(NULL, dev_priv,
636 &fence, NULL);
637
638 vmw_fence_single_bo(bo, fence);
639
640 if (likely(fence != NULL))
641 vmw_fence_obj_unreference(&fence);
642
643 return 0;
644}
645
646static int vmw_dx_context_destroy(struct vmw_resource *res)
647{
648 struct vmw_private *dev_priv = res->dev_priv;
649 struct {
650 SVGA3dCmdHeader header;
651 SVGA3dCmdDXDestroyContext body;
652 } *cmd;
653
654 if (likely(res->id == -1))
655 return 0;
656
657 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
658 if (unlikely(cmd == NULL)) {
659 DRM_ERROR("Failed reserving FIFO space for context "
660 "destruction.\n");
661 return -ENOMEM;
662 }
663
664 cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT;
665 cmd->header.size = sizeof(cmd->body);
666 cmd->body.cid = res->id;
667 vmw_fifo_commit(dev_priv, sizeof(*cmd));
668 if (dev_priv->query_cid == res->id)
669 dev_priv->query_cid_valid = false;
670 vmw_resource_release_id(res);
671 vmw_fifo_resource_dec(dev_priv);
672
673 return 0;
674}
675
422/**676/**
423 * User-space context management:677 * User-space context management:
424 */678 */
@@ -435,6 +689,8 @@ static void vmw_user_context_free(struct vmw_resource *res) · 10 unmodified lines
435 container_of(res, struct vmw_user_context, res);689 container_of(res, struct vmw_user_context, res);
436 struct vmw_private *dev_priv = res->dev_priv;690 struct vmw_private *dev_priv = res->dev_priv;
437 691
692 if (ctx->cbs)
693 vmw_binding_state_free(ctx->cbs);
438 ttm_base_object_kfree(ctx, base);694 ttm_base_object_kfree(ctx, base);
439 ttm_mem_global_free(vmw_mem_glob(dev_priv),695 ttm_mem_global_free(vmw_mem_glob(dev_priv),
440 vmw_user_context_size);696 vmw_user_context_size);
@@ -465,8 +721,8 @@ int vmw_context_destroy_ioctl(struct drm_device *dev, void *data, · 24 unmodified lines
465 return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);721 return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
466}722}
467 723
468int vmw_context_define_ioctl(struct drm_device *dev, void *data,724static int vmw_context_define(struct drm_device *dev, void *data,
469 struct drm_file *file_priv)725 struct drm_file *file_priv, bool dx)
470{726{
471 struct vmw_private *dev_priv = vmw_priv(dev);727 struct vmw_private *dev_priv = vmw_priv(dev);
472 struct vmw_user_context *ctx;728 struct vmw_user_context *ctx;
@@ -476,6 +732,10 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data, · 3 unmodified lines
476 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;732 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
477 int ret;733 int ret;
478 734
735 if (!dev_priv->has_dx && dx) {
736 DRM_ERROR("DX contexts not supported by device.\n");
737 return -EINVAL;
738 }
479 739
480 /*740 /*
481 * Approximate idr memory usage with 128 bytes. It will be limited741 * Approximate idr memory usage with 128 bytes. It will be limited
@@ -516,7 +776,7 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data, · 34 unmodified lines
516 * From here on, the destructor takes over resource freeing.776 * From here on, the destructor takes over resource freeing.
517 */777 */
518 778
519 ret = vmw_context_init(dev_priv, res, vmw_user_context_free);779 ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx);
520 if (unlikely(ret != 0))780 if (unlikely(ret != 0))
521 goto out_unlock;781 goto out_unlock;
522 782
@@ -535,387 +795,74 @@ out_err: · 12 unmodified lines
535out_unlock:795out_unlock:
536 ttm_read_unlock(&dev_priv->reservation_sem);796 ttm_read_unlock(&dev_priv->reservation_sem);
537 return ret;797 return ret;
538
539}
540
541/**
542 * vmw_context_scrub_shader - scrub a shader binding from a context.
543 *
544 * @bi: single binding information.
545 * @rebind: Whether to issue a bind instead of scrub command.
546 */
547static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
548{
549 struct vmw_private *dev_priv = bi->ctx->dev_priv;
550 struct {
551 SVGA3dCmdHeader header;
552 SVGA3dCmdSetShader body;
553 } *cmd;
554
555 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
556 if (unlikely(cmd == NULL)) {
557 DRM_ERROR("Failed reserving FIFO space for shader "
558 "unbinding.\n");
559 return -ENOMEM;
560 }
561
562 cmd->header.id = SVGA_3D_CMD_SET_SHADER;
563 cmd->header.size = sizeof(cmd->body);
564 cmd->body.cid = bi->ctx->id;
565 cmd->body.type = bi->i1.shader_type;
566 cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
567 vmw_fifo_commit(dev_priv, sizeof(*cmd));
568
569 return 0;
570}
571
572/**
573 * vmw_context_scrub_render_target - scrub a render target binding
574 * from a context.
575 *
576 * @bi: single binding information.
577 * @rebind: Whether to issue a bind instead of scrub command.
578 */
579static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
580 bool rebind)
581{
582 struct vmw_private *dev_priv = bi->ctx->dev_priv;
583 struct {
584 SVGA3dCmdHeader header;
585 SVGA3dCmdSetRenderTarget body;
586 } *cmd;
587
588 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
589 if (unlikely(cmd == NULL)) {
590 DRM_ERROR("Failed reserving FIFO space for render target "
591 "unbinding.\n");
592 return -ENOMEM;
593 }
594
595 cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
596 cmd->header.size = sizeof(cmd->body);
597 cmd->body.cid = bi->ctx->id;
598 cmd->body.type = bi->i1.rt_type;
599 cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
600 cmd->body.target.face = 0;
601 cmd->body.target.mipmap = 0;
602 vmw_fifo_commit(dev_priv, sizeof(*cmd));
603
604 return 0;
605}
606
607/**
608 * vmw_context_scrub_texture - scrub a texture binding from a context.
609 *
610 * @bi: single binding information.
611 * @rebind: Whether to issue a bind instead of scrub command.
612 *
613 * TODO: Possibly complement this function with a function that takes
614 * a list of texture bindings and combines them to a single command.
615 */
616static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
617 bool rebind)
618{
619 struct vmw_private *dev_priv = bi->ctx->dev_priv;
620 struct {
621 SVGA3dCmdHeader header;
622 struct {
623 SVGA3dCmdSetTextureState c;
624 SVGA3dTextureState s1;
625 } body;
626 } *cmd;
627
628 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
629 if (unlikely(cmd == NULL)) {
630 DRM_ERROR("Failed reserving FIFO space for texture "
631 "unbinding.\n");
632 return -ENOMEM;
633 }
634
635
636 cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
637 cmd->header.size = sizeof(cmd->body);
638 cmd->body.c.cid = bi->ctx->id;
639 cmd->body.s1.stage = bi->i1.texture_stage;
640 cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
641 cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
642 vmw_fifo_commit(dev_priv, sizeof(*cmd));
643
644 return 0;
645}798}
646 799
647/**800int vmw_context_define_ioctl(struct drm_device *dev, void *data,
648 * vmw_context_binding_drop: Stop tracking a context binding801 struct drm_file *file_priv)
649 *
650 * @cb: Pointer to binding tracker storage.
651 *
652 * Stops tracking a context binding, and re-initializes its storage.
653 * Typically used when the context binding is replaced with a binding to
654 * another (or the same, for that matter) resource.
655 */
656static void vmw_context_binding_drop(struct vmw_ctx_binding *cb)
657{802{
658 list_del(&cb->ctx_list);803 return vmw_context_define(dev, data, file_priv, false);
659 if (!list_empty(&cb->res_list))
660 list_del(&cb->res_list);
661 cb->bi.ctx = NULL;
662}804}
663 805
664/**806int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
665 * vmw_context_binding_add: Start tracking a context binding807 struct drm_file *file_priv)
666 *
667 * @cbs: Pointer to the context binding state tracker.
668 * @bi: Information about the binding to track.
669 *
670 * Performs basic checks on the binding to make sure arguments are within
671 * bounds and then starts tracking the binding in the context binding
672 * state structure @cbs.
673 */
674int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
675 const struct vmw_ctx_bindinfo *bi)
676{808{
677 struct vmw_ctx_binding *loc;809 union drm_vmw_extended_context_arg *arg = (typeof(arg)) data;
678 810 struct drm_vmw_context_arg *rep = &arg->rep;
679 switch (bi->bt) {811
680 case vmw_ctx_binding_rt:812 switch (arg->req) {
681 if (unlikely((unsigned)bi->i1.rt_type >= SVGA3D_RT_MAX)) {813 case drm_vmw_context_legacy:
682 DRM_ERROR("Illegal render target type %u.\n",814 return vmw_context_define(dev, rep, file_priv, false);
683 (unsigned) bi->i1.rt_type);815 case drm_vmw_context_dx:
684 return -EINVAL;816 return vmw_context_define(dev, rep, file_priv, true);
685 }
686 loc = &cbs->render_targets[bi->i1.rt_type];
687 break;
688 case vmw_ctx_binding_tex:
689 if (unlikely((unsigned)bi->i1.texture_stage >=
690 SVGA3D_NUM_TEXTURE_UNITS)) {
691 DRM_ERROR("Illegal texture/sampler unit %u.\n",
692 (unsigned) bi->i1.texture_stage);
693 return -EINVAL;
694 }
695 loc = &cbs->texture_units[bi->i1.texture_stage];
696 break;
697 case vmw_ctx_binding_shader:
698 if (unlikely((unsigned)bi->i1.shader_type >=
699 SVGA3D_SHADERTYPE_PREDX_MAX)) {
700 DRM_ERROR("Illegal shader type %u.\n",
701 (unsigned) bi->i1.shader_type);
702 return -EINVAL;
703 }
704 loc = &cbs->shaders[bi->i1.shader_type];
705 break;
706 default:817 default:
707 BUG();
708 }
709
710 if (loc->bi.ctx != NULL)
711 vmw_context_binding_drop(loc);
712
713 loc->bi = *bi;
714 loc->bi.scrubbed = false;
715 list_add_tail(&loc->ctx_list, &cbs->list);
716 INIT_LIST_HEAD(&loc->res_list);
717
718 return 0;
719}
720
721/**
722 * vmw_context_binding_transfer: Transfer a context binding tracking entry.
723 *
724 * @cbs: Pointer to the persistent context binding state tracker.
725 * @bi: Information about the binding to track.
726 *
727 */
728static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
729 const struct vmw_ctx_bindinfo *bi)
730{
731 struct vmw_ctx_binding *loc;
732
733 switch (bi->bt) {
734 case vmw_ctx_binding_rt:
735 loc = &cbs->render_targets[bi->i1.rt_type];
736 break;
737 case vmw_ctx_binding_tex:
738 loc = &cbs->texture_units[bi->i1.texture_stage];
739 break;
740 case vmw_ctx_binding_shader:
741 loc = &cbs->shaders[bi->i1.shader_type];
742 break;818 break;
743 default:
744 BUG();
745 }
746
747 if (loc->bi.ctx != NULL)
748 vmw_context_binding_drop(loc);
749
750 if (bi->res != NULL) {
751 loc->bi = *bi;
752 list_add_tail(&loc->ctx_list, &cbs->list);
753 list_add_tail(&loc->res_list, &bi->res->binding_head);
754 }
755}
756
757/**
758 * vmw_context_binding_kill - Kill a binding on the device
759 * and stop tracking it.
760 *
761 * @cb: Pointer to binding tracker storage.
762 *
763 * Emits FIFO commands to scrub a binding represented by @cb.
764 * Then stops tracking the binding and re-initializes its storage.
765 */
766static void vmw_context_binding_kill(struct vmw_ctx_binding *cb)
767{
768 if (!cb->bi.scrubbed) {
769 (void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false);
770 cb->bi.scrubbed = true;
771 }
772 vmw_context_binding_drop(cb);
773}
774
775/**
776 * vmw_context_binding_state_kill - Kill all bindings associated with a
777 * struct vmw_ctx_binding state structure, and re-initialize the structure.
778 *
779 * @cbs: Pointer to the context binding state tracker.
780 *
781 * Emits commands to scrub all bindings associated with the
782 * context binding state tracker. Then re-initializes the whole structure.
783 */
784static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs)
785{
786 struct vmw_ctx_binding *entry, *next;
787
788 list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
789 vmw_context_binding_kill(entry);
790}
791
792/**
793 * vmw_context_binding_state_scrub - Scrub all bindings associated with a
794 * struct vmw_ctx_binding state structure.
795 *
796 * @cbs: Pointer to the context binding state tracker.
797 *
798 * Emits commands to scrub all bindings associated with the
799 * context binding state tracker.
800 */
801static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
802{
803 struct vmw_ctx_binding *entry;
804
805 list_for_each_entry(entry, &cbs->list, ctx_list) {
806 if (!entry->bi.scrubbed) {
807 (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
808 entry->bi.scrubbed = true;
809 }
810 }
811}
812
813/**
814 * vmw_context_binding_res_list_kill - Kill all bindings on a
815 * resource binding list
816 *
817 * @head: list head of resource binding list
818 *
819 * Kills all bindings associated with a specific resource. Typically
820 * called before the resource is destroyed.
821 */
822void vmw_context_binding_res_list_kill(struct list_head *head)
823{
824 struct vmw_ctx_binding *entry, *next;
825
826 list_for_each_entry_safe(entry, next, head, res_list)
827 vmw_context_binding_kill(entry);
828}
829
830/**
831 * vmw_context_binding_res_list_scrub - Scrub all bindings on a
832 * resource binding list
833 *
834 * @head: list head of resource binding list
835 *
836 * Scrub all bindings associated with a specific resource. Typically
837 * called before the resource is evicted.
838 */
839void vmw_context_binding_res_list_scrub(struct list_head *head)
840{
841 struct vmw_ctx_binding *entry;
842
843 list_for_each_entry(entry, head, res_list) {
844 if (!entry->bi.scrubbed) {
845 (void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
846 entry->bi.scrubbed = true;
847 }
848 }819 }
820 return -EINVAL;
849}821}
850 822
851/**823/**
852 * vmw_context_binding_state_transfer - Commit staged binding info824 * vmw_context_binding_list - Return a list of context bindings
853 *825 *
854 * @ctx: Pointer to context to commit the staged binding info to.826 * @ctx: The context resource
855 * @from: Staged binding info built during execbuf.
856 *827 *
857 * Transfers binding info from a temporary structure to the persistent828 * Returns the current list of bindings of the given context. Note that
858 * structure in the context. This can be done once commands829 * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
859 */830 */
860void vmw_context_binding_state_transfer(struct vmw_resource *ctx,831struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
861 struct vmw_ctx_binding_state *from)
862{832{
863 struct vmw_user_context *uctx =833 struct vmw_user_context *uctx =
864 container_of(ctx, struct vmw_user_context, res);834 container_of(ctx, struct vmw_user_context, res);
865 struct vmw_ctx_binding *entry, *next;
866 835
867 list_for_each_entry_safe(entry, next, &from->list, ctx_list)836 return vmw_binding_state_list(uctx->cbs);
868 vmw_context_binding_transfer(&uctx->cbs, &entry->bi);
869}837}
870 838
871/**839struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
872 * vmw_context_rebind_all - Rebind all scrubbed bindings of a context
873 *
874 * @ctx: The context resource
875 *
876 * Walks through the context binding list and rebinds all scrubbed
877 * resources.
878 */
879int vmw_context_rebind_all(struct vmw_resource *ctx)
880{840{
881 struct vmw_ctx_binding *entry;841 return container_of(ctx, struct vmw_user_context, res)->man;
882 struct vmw_user_context *uctx =842}
883 container_of(ctx, struct vmw_user_context, res);
884 struct vmw_ctx_binding_state *cbs = &uctx->cbs;
885 int ret;
886
887 list_for_each_entry(entry, &cbs->list, ctx_list) {
888 if (likely(!entry->bi.scrubbed))
889 continue;
890
891 if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id ==
892 SVGA3D_INVALID_ID))
893 continue;
894
895 ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true);
896 if (unlikely(ret != 0))
897 return ret;
898 843
899 entry->bi.scrubbed = false;844struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
900 }845 SVGACOTableType cotable_type)
846{
847 if (cotable_type >= SVGA_COTABLE_DX10_MAX)
848 return ERR_PTR(-EINVAL);
901 849
902 return 0;850 return vmw_resource_reference
851 (container_of(ctx, struct vmw_user_context, res)->
852 cotables[cotable_type]);
903}853}
904 854
905/**855/**
906 * vmw_context_binding_list - Return a list of context bindings856 * vmw_context_binding_state -
857 * Return a pointer to a context binding state structure
907 *858 *
908 * @ctx: The context resource859 * @ctx: The context resource
909 *860 *
910 * Returns the current list of bindings of the given context. Note that861 * Returns the current state of bindings of the given context. Note that
911 * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.862 * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked.
912 */863 */
913struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)864struct vmw_ctx_binding_state *
914{865vmw_context_binding_state(struct vmw_resource *ctx)
915 return &(container_of(ctx, struct vmw_user_context, res)->cbs.list);
916}
917
918struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
919{866{
920 return container_of(ctx, struct vmw_user_context, res)->man;867 return container_of(ctx, struct vmw_user_context, res)->cbs;
921}868}
drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c+662−0
@@ -0,0 +1,662 @@
1/**************************************************************************
2 *
3 * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27/*
28 * Treat context OTables as resources to make use of the resource
29 * backing MOB eviction mechanism, that is used to read back the COTable
30 * whenever the backing MOB is evicted.
31 */
32
33#include "vmwgfx_drv.h"
34#include "vmwgfx_resource_priv.h"
35#include <ttm/ttm_placement.h>
36#include "vmwgfx_so.h"
37
38/**
39 * struct vmw_cotable - Context Object Table resource
40 *
41 * @res: struct vmw_resource we are deriving from.
42 * @ctx: non-refcounted pointer to the owning context.
43 * @size_read_back: Size of data read back during eviction.
44 * @seen_entries: Seen entries in command stream for this cotable.
45 * @type: The cotable type.
46 * @scrubbed: Whether the cotable has been scrubbed.
47 * @resource_list: List of resources in the cotable.
48 */
49struct vmw_cotable {
50 struct vmw_resource res;
51 struct vmw_resource *ctx;
52 size_t size_read_back;
53 int seen_entries;
54 u32 type;
55 bool scrubbed;
56 struct list_head resource_list;
57};
58
59/**
60 * struct vmw_cotable_info - Static info about cotable types
61 *
62 * @min_initial_entries: Min number of initial intries at cotable allocation
63 * for this cotable type.
64 * @size: Size of each entry.
65 */
66struct vmw_cotable_info {
67 u32 min_initial_entries;
68 u32 size;
69 void (*unbind_func)(struct vmw_private *, struct list_head *,
70 bool);
71};
72
73static const struct vmw_cotable_info co_info[] = {
74 {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
75 {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
76 {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
77 {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
78 {1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
79 {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
80 {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
81 {1, sizeof(SVGACOTableDXSamplerEntry), NULL},
82 {1, sizeof(SVGACOTableDXStreamOutputEntry), NULL},
83 {1, sizeof(SVGACOTableDXQueryEntry), NULL},
84 {1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub}
85};
86
87/*
88 * Cotables with bindings that we remove must be scrubbed first,
89 * otherwise, the device will swap in an invalid context when we remove
90 * bindings before scrubbing a cotable...
91 */
92const SVGACOTableType vmw_cotable_scrub_order[] = {
93 SVGA_COTABLE_RTVIEW,
94 SVGA_COTABLE_DSVIEW,
95 SVGA_COTABLE_SRVIEW,
96 SVGA_COTABLE_DXSHADER,
97 SVGA_COTABLE_ELEMENTLAYOUT,
98 SVGA_COTABLE_BLENDSTATE,
99 SVGA_COTABLE_DEPTHSTENCIL,
100 SVGA_COTABLE_RASTERIZERSTATE,
101 SVGA_COTABLE_SAMPLER,
102 SVGA_COTABLE_STREAMOUTPUT,
103 SVGA_COTABLE_DXQUERY,
104};
105
106static int vmw_cotable_bind(struct vmw_resource *res,
107 struct ttm_validate_buffer *val_buf);
108static int vmw_cotable_unbind(struct vmw_resource *res,
109 bool readback,
110 struct ttm_validate_buffer *val_buf);
111static int vmw_cotable_create(struct vmw_resource *res);
112static int vmw_cotable_destroy(struct vmw_resource *res);
113
114static const struct vmw_res_func vmw_cotable_func = {
115 .res_type = vmw_res_cotable,
116 .needs_backup = true,
117 .may_evict = true,
118 .type_name = "context guest backed object tables",
119 .backup_placement = &vmw_mob_placement,
120 .create = vmw_cotable_create,
121 .destroy = vmw_cotable_destroy,
122 .bind = vmw_cotable_bind,
123 .unbind = vmw_cotable_unbind,
124};
125
126/**
127 * vmw_cotable - Convert a struct vmw_resource pointer to a struct
128 * vmw_cotable pointer
129 *
130 * @res: Pointer to the resource.
131 */
132static struct vmw_cotable *vmw_cotable(struct vmw_resource *res)
133{
134 return container_of(res, struct vmw_cotable, res);
135}
136
137/**
138 * vmw_cotable_destroy - Cotable resource destroy callback
139 *
140 * @res: Pointer to the cotable resource.
141 *
142 * There is no device cotable destroy command, so this function only
143 * makes sure that the resource id is set to invalid.
144 */
145static int vmw_cotable_destroy(struct vmw_resource *res)
146{
147 res->id = -1;
148 return 0;
149}
150
151/**
152 * vmw_cotable_unscrub - Undo a cotable unscrub operation
153 *
154 * @res: Pointer to the cotable resource
155 *
156 * This function issues commands to (re)bind the cotable to
157 * its backing mob, which needs to be validated and reserved at this point.
158 * This is identical to bind() except the function interface looks different.
159 */
160static int vmw_cotable_unscrub(struct vmw_resource *res)
161{
162 struct vmw_cotable *vcotbl = vmw_cotable(res);
163 struct vmw_private *dev_priv = res->dev_priv;
164 struct ttm_buffer_object *bo = &res->backup->base;
165 struct {
166 SVGA3dCmdHeader header;
167 SVGA3dCmdDXSetCOTable body;
168 } *cmd;
169
170 WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
171 lockdep_assert_held(&bo->resv->lock.base);
172
173 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), SVGA3D_INVALID_ID);
174 if (!cmd) {
175 DRM_ERROR("Failed reserving FIFO space for cotable "
176 "binding.\n");
177 return -ENOMEM;
178 }
179
180 WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID);
181 WARN_ON(bo->mem.mem_type != VMW_PL_MOB);
182 cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
183 cmd->header.size = sizeof(cmd->body);
184 cmd->body.cid = vcotbl->ctx->id;
185 cmd->body.type = vcotbl->type;
186 cmd->body.mobid = bo->mem.start;
187 cmd->body.validSizeInBytes = vcotbl->size_read_back;
188
189 vmw_fifo_commit_flush(dev_priv, sizeof(*cmd));
190 vcotbl->scrubbed = false;
191
192 return 0;
193}
194
195/**
196 * vmw_cotable_bind - Undo a cotable unscrub operation
197 *
198 * @res: Pointer to the cotable resource
199 * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
200 * for convenience / fencing.
201 *
202 * This function issues commands to (re)bind the cotable to
203 * its backing mob, which needs to be validated and reserved at this point.
204 */
205static int vmw_cotable_bind(struct vmw_resource *res,
206 struct ttm_validate_buffer *val_buf)
207{
208 /*
209 * The create() callback may have changed @res->backup without
210 * the caller noticing, and with val_buf->bo still pointing to
211 * the old backup buffer. Although hackish, and not used currently,
212 * take the opportunity to correct the value here so that it's not
213 * misused in the future.
214 */
215 val_buf->bo = &res->backup->base;
216
217 return vmw_cotable_unscrub(res);
218}
219
220/**
221 * vmw_cotable_scrub - Scrub the cotable from the device.
222 *
223 * @res: Pointer to the cotable resource.
224 * @readback: Whether initiate a readback of the cotable data to the backup
225 * buffer.
226 *
227 * In some situations (context swapouts) it might be desirable to make the
228 * device forget about the cotable without performing a full unbind. A full
229 * unbind requires reserved backup buffers and it might not be possible to
230 * reserve them due to locking order violation issues. The vmw_cotable_scrub
231 * function implements a partial unbind() without that requirement but with the
232 * following restrictions.
233 * 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must
234 * be called.
235 * 2) Before the cotable backing buffer is used by the CPU, or during the
236 * resource destruction, vmw_cotable_unbind() must be called.
237 */
238int vmw_cotable_scrub(struct vmw_resource *res, bool readback)
239{
240 struct vmw_cotable *vcotbl = vmw_cotable(res);
241 struct vmw_private *dev_priv = res->dev_priv;
242 size_t submit_size;
243
244 struct {
245 SVGA3dCmdHeader header;
246 SVGA3dCmdDXReadbackCOTable body;
247 } *cmd0;
248 struct {
249 SVGA3dCmdHeader header;
250 SVGA3dCmdDXSetCOTable body;
251 } *cmd1;
252
253 if (vcotbl->scrubbed)
254 return 0;
255
256 if (co_info[vcotbl->type].unbind_func)
257 co_info[vcotbl->type].unbind_func(dev_priv,
258 &vcotbl->resource_list,
259 readback);
260 submit_size = sizeof(*cmd1);
261 if (readback)
262 submit_size += sizeof(*cmd0);
263
264 cmd1 = vmw_fifo_reserve_dx(dev_priv, submit_size, SVGA3D_INVALID_ID);
265 if (!cmd1) {
266 DRM_ERROR("Failed reserving FIFO space for cotable "
267 "unbinding.\n");
268 return -ENOMEM;
269 }
270
271 vcotbl->size_read_back = 0;
272 if (readback) {
273 cmd0 = (void *) cmd1;
274 cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
275 cmd0->header.size = sizeof(cmd0->body);
276 cmd0->body.cid = vcotbl->ctx->id;
277 cmd0->body.type = vcotbl->type;
278 cmd1 = (void *) &cmd0[1];
279 vcotbl->size_read_back = res->backup_size;
280 }
281 cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
282 cmd1->header.size = sizeof(cmd1->body);
283 cmd1->body.cid = vcotbl->ctx->id;
284 cmd1->body.type = vcotbl->type;
285 cmd1->body.mobid = SVGA3D_INVALID_ID;
286 cmd1->body.validSizeInBytes = 0;
287 vmw_fifo_commit_flush(dev_priv, submit_size);
288 vcotbl->scrubbed = true;
289
290 /* Trigger a create() on next validate. */
291 res->id = -1;
292
293 return 0;
294}
295
296/**
297 * vmw_cotable_unbind - Cotable resource unbind callback
298 *
299 * @res: Pointer to the cotable resource.
300 * @readback: Whether to read back cotable data to the backup buffer.
301 * val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
302 * for convenience / fencing.
303 *
304 * Unbinds the cotable from the device and fences the backup buffer.
305 */
306static int vmw_cotable_unbind(struct vmw_resource *res,
307 bool readback,
308 struct ttm_validate_buffer *val_buf)
309{
310 struct vmw_cotable *vcotbl = vmw_cotable(res);
311 struct vmw_private *dev_priv = res->dev_priv;
312 struct ttm_buffer_object *bo = val_buf->bo;
313 struct vmw_fence_obj *fence;
314 int ret;
315
316 if (list_empty(&res->mob_head))
317 return 0;
318
319 WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB);
320 lockdep_assert_held(&bo->resv->lock.base);
321
322 mutex_lock(&dev_priv->binding_mutex);
323 if (!vcotbl->scrubbed)
324 vmw_dx_context_scrub_cotables(vcotbl->ctx, readback);
325 mutex_unlock(&dev_priv->binding_mutex);
326 (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
327 vmw_fence_single_bo(bo, fence);
328 if (likely(fence != NULL))
329 vmw_fence_obj_unreference(&fence);
330
331 return ret;
332}
333
334/**
335 * vmw_cotable_readback - Read back a cotable without unbinding.
336 *
337 * @res: The cotable resource.
338 *
339 * Reads back a cotable to its backing mob without scrubbing the MOB from
340 * the cotable. The MOB is fenced for subsequent CPU access.
341 */
342static int vmw_cotable_readback(struct vmw_resource *res)
343{
344 struct vmw_cotable *vcotbl = vmw_cotable(res);
345 struct vmw_private *dev_priv = res->dev_priv;
346
347 struct {
348 SVGA3dCmdHeader header;
349 SVGA3dCmdDXReadbackCOTable body;
350 } *cmd;
351 struct vmw_fence_obj *fence;
352
353 if (!vcotbl->scrubbed) {
354 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd),
355 SVGA3D_INVALID_ID);
356 if (!cmd) {
357 DRM_ERROR("Failed reserving FIFO space for cotable "
358 "readback.\n");
359 return -ENOMEM;
360 }
361 cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
362 cmd->header.size = sizeof(cmd->body);
363 cmd->body.cid = vcotbl->ctx->id;
364 cmd->body.type = vcotbl->type;
365 vcotbl->size_read_back = res->backup_size;
366 vmw_fifo_commit(dev_priv, sizeof(*cmd));
367 }
368
369 (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
370 vmw_fence_single_bo(&res->backup->base, fence);
371 vmw_fence_obj_unreference(&fence);
372
373 return 0;
374}
375
376/**
377 * vmw_cotable_resize - Resize a cotable.
378 *
379 * @res: The cotable resource.
380 * @new_size: The new size.
381 *
382 * Resizes a cotable and binds the new backup buffer.
383 * On failure the cotable is left intact.
384 * Important! This function may not fail once the MOB switch has been
385 * committed to hardware. That would put the device context in an
386 * invalid state which we can't currently recover from.
387 */
388static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
389{
390 struct vmw_private *dev_priv = res->dev_priv;
391 struct vmw_cotable *vcotbl = vmw_cotable(res);
392 struct vmw_dma_buffer *buf, *old_buf = res->backup;
393 struct ttm_buffer_object *bo, *old_bo = &res->backup->base;
394 size_t old_size = res->backup_size;
395 size_t old_size_read_back = vcotbl->size_read_back;
396 size_t cur_size_read_back;
397 struct ttm_bo_kmap_obj old_map, new_map;
398 int ret;
399 size_t i;
400
401 ret = vmw_cotable_readback(res);
402 if (ret)
403 return ret;
404
405 cur_size_read_back = vcotbl->size_read_back;
406 vcotbl->size_read_back = old_size_read_back;
407
408 /*
409 * While device is processing, Allocate and reserve a buffer object
410 * for the new COTable. Initially pin the buffer object to make sure
411 * we can use tryreserve without failure.
412 */
413 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
414 if (!buf)
415 return -ENOMEM;
416
417 ret = vmw_dmabuf_init(dev_priv, buf, new_size, &vmw_mob_ne_placement,
418 true, vmw_dmabuf_bo_free);
419 if (ret) {
420 DRM_ERROR("Failed initializing new cotable MOB.\n");
421 return ret;
422 }
423
424 bo = &buf->base;
425 WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, false, NULL));
426
427 ret = ttm_bo_wait(old_bo, false, false, false);
428 if (unlikely(ret != 0)) {
429 DRM_ERROR("Failed waiting for cotable unbind.\n");
430 goto out_wait;
431 }
432
433 /*
434 * Do a page by page copy of COTables. This eliminates slow vmap()s.
435 * This should really be a TTM utility.
436 */
437 for (i = 0; i < old_bo->num_pages; ++i) {
438 bool dummy;
439
440 ret = ttm_bo_kmap(old_bo, i, 1, &old_map);
441 if (unlikely(ret != 0)) {
442 DRM_ERROR("Failed mapping old COTable on resize.\n");
443 goto out_wait;
444 }
445 ret = ttm_bo_kmap(bo, i, 1, &new_map);
446 if (unlikely(ret != 0)) {
447 DRM_ERROR("Failed mapping new COTable on resize.\n");
448 goto out_map_new;
449 }
450 memcpy(ttm_kmap_obj_virtual(&new_map, &dummy),
451 ttm_kmap_obj_virtual(&old_map, &dummy),
452 PAGE_SIZE);
453 ttm_bo_kunmap(&new_map);
454 ttm_bo_kunmap(&old_map);
455 }
456
457 /* Unpin new buffer, and switch backup buffers. */
458 ret = ttm_bo_validate(bo, &vmw_mob_placement, false, false);
459 if (unlikely(ret != 0)) {
460 DRM_ERROR("Failed validating new COTable backup buffer.\n");
461 goto out_wait;
462 }
463
464 res->backup = buf;
465 res->backup_size = new_size;
466 vcotbl->size_read_back = cur_size_read_back;
467
468 /*
469 * Now tell the device to switch. If this fails, then we need to
470 * revert the full resize.
471 */
472 ret = vmw_cotable_unscrub(res);
473 if (ret) {
474 DRM_ERROR("Failed switching COTable backup buffer.\n");
475 res->backup = old_buf;
476 res->backup_size = old_size;
477 vcotbl->size_read_back = old_size_read_back;
478 goto out_wait;
479 }
480
481 /* Let go of the old mob. */
482 list_del(&res->mob_head);
483 list_add_tail(&res->mob_head, &buf->res_list);
484 vmw_dmabuf_unreference(&old_buf);
485 res->id = vcotbl->type;
486
487 return 0;
488
489out_map_new:
490 ttm_bo_kunmap(&old_map);
491out_wait:
492 ttm_bo_unreserve(bo);
493 vmw_dmabuf_unreference(&buf);
494
495 return ret;
496}
497
498/**
499 * vmw_cotable_create - Cotable resource create callback
500 *
501 * @res: Pointer to a cotable resource.
502 *
503 * There is no separate create command for cotables, so this callback, which
504 * is called before bind() in the validation sequence is instead used for two
505 * things.
506 * 1) Unscrub the cotable if it is scrubbed and still attached to a backup
507 * buffer, that is, if @res->mob_head is non-empty.
508 * 2) Resize the cotable if needed.
509 */
510static int vmw_cotable_create(struct vmw_resource *res)
511{
512 struct vmw_cotable *vcotbl = vmw_cotable(res);
513 size_t new_size = res->backup_size;
514 size_t needed_size;
515 int ret;
516
517 /* Check whether we need to resize the cotable */
518 needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size;
519 while (needed_size > new_size)
520 new_size *= 2;
521
522 if (likely(new_size <= res->backup_size)) {
523 if (vcotbl->scrubbed && !list_empty(&res->mob_head)) {
524 ret = vmw_cotable_unscrub(res);
525 if (ret)
526 return ret;
527 }
528 res->id = vcotbl->type;
529 return 0;
530 }
531
532 return vmw_cotable_resize(res, new_size);
533}
534
535/**
536 * vmw_hw_cotable_destroy - Cotable hw_destroy callback
537 *
538 * @res: Pointer to a cotable resource.
539 *
540 * The final (part of resource destruction) destroy callback.
541 */
542static void vmw_hw_cotable_destroy(struct vmw_resource *res)
543{
544 (void) vmw_cotable_destroy(res);
545}
546
547static size_t cotable_acc_size;
548
549/**
550 * vmw_cotable_free - Cotable resource destructor
551 *
552 * @res: Pointer to a cotable resource.
553 */
554static void vmw_cotable_free(struct vmw_resource *res)
555{
556 struct vmw_private *dev_priv = res->dev_priv;
557
558 kfree(res);
559 ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size);
560}
561
562/**
563 * vmw_cotable_alloc - Create a cotable resource
564 *
565 * @dev_priv: Pointer to a device private struct.
566 * @ctx: Pointer to the context resource.
567 * The cotable resource will not add a refcount.
568 * @type: The cotable type.
569 */
570struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
571 struct vmw_resource *ctx,
572 u32 type)
573{
574 struct vmw_cotable *vcotbl;
575 int ret;
576 u32 num_entries;
577
578 if (unlikely(cotable_acc_size == 0))
579 cotable_acc_size = ttm_round_pot(sizeof(struct vmw_cotable));
580
581 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
582 cotable_acc_size, false, true);
583 if (unlikely(ret))
584 return ERR_PTR(ret);
585
586 vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL);
587 if (unlikely(vcotbl == NULL)) {
588 ret = -ENOMEM;
589 goto out_no_alloc;
590 }
591
592 ret = vmw_resource_init(dev_priv, &vcotbl->res, true,
593 vmw_cotable_free, &vmw_cotable_func);
594 if (unlikely(ret != 0))
595 goto out_no_init;
596
597 INIT_LIST_HEAD(&vcotbl->resource_list);
598 vcotbl->res.id = type;
599 vcotbl->res.backup_size = PAGE_SIZE;
600 num_entries = PAGE_SIZE / co_info[type].size;
601 if (num_entries < co_info[type].min_initial_entries) {
602 vcotbl->res.backup_size = co_info[type].min_initial_entries *
603 co_info[type].size;
604 vcotbl->res.backup_size =
605 (vcotbl->res.backup_size + PAGE_SIZE - 1) & PAGE_MASK;
606 }
607
608 vcotbl->scrubbed = true;
609 vcotbl->seen_entries = -1;
610 vcotbl->type = type;
611 vcotbl->ctx = ctx;
612
613 vmw_resource_activate(&vcotbl->res, vmw_hw_cotable_destroy);
614
615 return &vcotbl->res;
616
617out_no_init:
618 kfree(vcotbl);
619out_no_alloc:
620 ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size);
621 return ERR_PTR(ret);
622}
623
624/**
625 * vmw_cotable_notify - Notify the cotable about an item creation
626 *
627 * @res: Pointer to a cotable resource.
628 * @id: Item id.
629 */
630int vmw_cotable_notify(struct vmw_resource *res, int id)
631{
632 struct vmw_cotable *vcotbl = vmw_cotable(res);
633
634 if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) {
635 DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n",
636 (unsigned) vcotbl->type, id);
637 return -EINVAL;
638 }
639
640 if (vcotbl->seen_entries < id) {
641 /* Trigger a call to create() on next validate */
642 res->id = -1;
643 vcotbl->seen_entries = id;
644 }
645
646 return 0;
647}
648
649/**
650 * vmw_cotable_add_view - add a view to the cotable's list of active views.
651 *
652 * @res: pointer struct vmw_resource representing the cotable.
653 * @head: pointer to the struct list_head member of the resource, dedicated
654 * to the cotable active resource list.
655 */
656void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head)
657{
658 struct vmw_cotable *vcotbl =
659 container_of(res, struct vmw_cotable, res);
660
661 list_add_tail(head, &vcotbl->resource_list);
662}
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c+46−8
@@ -28,6 +28,7 @@ · 27 unmodified lines
28 28
29#include <drm/drmP.h>29#include <drm/drmP.h>
30#include "vmwgfx_drv.h"30#include "vmwgfx_drv.h"
31#include "vmwgfx_binding.h"
31#include <drm/ttm/ttm_placement.h>32#include <drm/ttm/ttm_placement.h>
32#include <drm/ttm/ttm_bo_driver.h>33#include <drm/ttm/ttm_bo_driver.h>
33#include <drm/ttm/ttm_object.h>34#include <drm/ttm/ttm_object.h>
@@ -127,6 +128,9 @@ · 93 unmodified lines
127#define DRM_IOCTL_VMW_SYNCCPU \128#define DRM_IOCTL_VMW_SYNCCPU \
128 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU, \129 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU, \
129 struct drm_vmw_synccpu_arg)130 struct drm_vmw_synccpu_arg)
131#define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \
132 DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \
133 struct drm_vmw_context_arg)
130 134
131/**135/**
132 * The core DRM version of this macro doesn't account for136 * The core DRM version of this macro doesn't account for
@@ -168,8 +172,8 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { · 35 unmodified lines
168 DRM_UNLOCKED | DRM_RENDER_ALLOW),172 DRM_UNLOCKED | DRM_RENDER_ALLOW),
169 VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl,173 VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl,
170 DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),174 DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
171 VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,175 VMW_IOCTL_DEF(VMW_EXECBUF, NULL, DRM_AUTH | DRM_UNLOCKED |
172 DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),176 DRM_RENDER_ALLOW),
173 VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,177 VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,
174 DRM_UNLOCKED | DRM_RENDER_ALLOW),178 DRM_UNLOCKED | DRM_RENDER_ALLOW),
175 VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,179 VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,
@@ -206,6 +210,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { · 30 unmodified lines
206 VMW_IOCTL_DEF(VMW_SYNCCPU,210 VMW_IOCTL_DEF(VMW_SYNCCPU,
207 vmw_user_dmabuf_synccpu_ioctl,211 vmw_user_dmabuf_synccpu_ioctl,
208 DRM_UNLOCKED | DRM_RENDER_ALLOW),212 DRM_UNLOCKED | DRM_RENDER_ALLOW),
213 VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT,
214 vmw_extended_context_define_ioctl,
215 DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
209};216};
210 217
211static struct pci_device_id vmw_pci_id_list[] = {218static struct pci_device_id vmw_pci_id_list[] = {
@@ -390,8 +397,10 @@ static int vmw_request_device(struct vmw_private *dev_priv) · 178 unmodified lines
390 }397 }
391 vmw_fence_fifo_up(dev_priv->fman);398 vmw_fence_fifo_up(dev_priv->fman);
392 dev_priv->cman = vmw_cmdbuf_man_create(dev_priv);399 dev_priv->cman = vmw_cmdbuf_man_create(dev_priv);
393 if (IS_ERR(dev_priv->cman))400 if (IS_ERR(dev_priv->cman)) {
394 dev_priv->cman = NULL;401 dev_priv->cman = NULL;
402 dev_priv->has_dx = false;
403 }
395 404
396 ret = vmw_request_device_late(dev_priv);405 ret = vmw_request_device_late(dev_priv);
397 if (ret)406 if (ret)
@@ -848,6 +857,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) · 450 unmodified lines
848 }857 }
849 }858 }
850 859
860 if (dev_priv->has_mob) {
861 spin_lock(&dev_priv->cap_lock);
862 vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX);
863 dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP);
864 spin_unlock(&dev_priv->cap_lock);
865 }
866
867
851 ret = vmw_kms_init(dev_priv);868 ret = vmw_kms_init(dev_priv);
852 if (unlikely(ret != 0))869 if (unlikely(ret != 0))
853 goto out_no_kms;870 goto out_no_kms;
@@ -857,6 +874,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) · 3 unmodified lines
857 if (ret)874 if (ret)
858 goto out_no_fifo;875 goto out_no_fifo;
859 876
877 DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no.");
878
860 if (dev_priv->enable_fb) {879 if (dev_priv->enable_fb) {
861 vmw_fifo_resource_inc(dev_priv);880 vmw_fifo_resource_inc(dev_priv);
862 vmw_svga_enable(dev_priv);881 vmw_svga_enable(dev_priv);
@@ -900,6 +919,8 @@ out_err0: · 37 unmodified lines
900 for (i = vmw_res_context; i < vmw_res_max; ++i)919 for (i = vmw_res_context; i < vmw_res_max; ++i)
901 idr_destroy(&dev_priv->res_idr[i]);920 idr_destroy(&dev_priv->res_idr[i]);
902 921
922 if (dev_priv->ctx.staged_bindings)
923 vmw_binding_state_free(dev_priv->ctx.staged_bindings);
903 kfree(dev_priv);924 kfree(dev_priv);
904 return ret;925 return ret;
905}926}
@@ -945,6 +966,8 @@ static int vmw_driver_unload(struct drm_device *dev) · 39 unmodified lines
945 iounmap(dev_priv->mmio_virt);966 iounmap(dev_priv->mmio_virt);
946 arch_phys_wc_del(dev_priv->mmio_mtrr);967 arch_phys_wc_del(dev_priv->mmio_mtrr);
947 (void)ttm_bo_device_release(&dev_priv->bdev);968 (void)ttm_bo_device_release(&dev_priv->bdev);
969 if (dev_priv->ctx.staged_bindings)
970 vmw_binding_state_free(dev_priv->ctx.staged_bindings);
948 vmw_ttm_global_release(dev_priv);971 vmw_ttm_global_release(dev_priv);
949 972
950 for (i = vmw_res_context; i < vmw_res_max; ++i)973 for (i = vmw_res_context; i < vmw_res_max; ++i)
@@ -1082,11 +1105,21 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, · 131 unmodified lines
1082 const struct drm_ioctl_desc *ioctl =1105 const struct drm_ioctl_desc *ioctl =
1083 &vmw_ioctls[nr - DRM_COMMAND_BASE];1106 &vmw_ioctls[nr - DRM_COMMAND_BASE];
1084 1107
1085 if (unlikely(ioctl->cmd != cmd)) {1108 if (nr == DRM_COMMAND_BASE + DRM_VMW_EXECBUF) {
1086 DRM_ERROR("Invalid command format, ioctl %d\n",1109 ret = (long) drm_ioctl_permit(ioctl->flags, file_priv);
1087 nr - DRM_COMMAND_BASE);1110 if (unlikely(ret != 0))
1088 return -EINVAL;1111 return ret;
1112
1113 if (unlikely((cmd & (IOC_IN | IOC_OUT)) != IOC_IN))
1114 goto out_io_encoding;
1115
1116 return (long) vmw_execbuf_ioctl(dev, arg, file_priv,
1117 _IOC_SIZE(cmd));
1089 }1118 }
1119
1120 if (unlikely(ioctl->cmd != cmd))
1121 goto out_io_encoding;
1122
1090 flags = ioctl->flags;1123 flags = ioctl->flags;
1091 } else if (!drm_ioctl_flags(nr, &flags))1124 } else if (!drm_ioctl_flags(nr, &flags))
1092 return -EINVAL;1125 return -EINVAL;
@@ -1106,6 +1139,12 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, · 13 unmodified lines
1106 ttm_read_unlock(&vmaster->lock);1139 ttm_read_unlock(&vmaster->lock);
1107 1140
1108 return ret;1141 return ret;
1142
1143out_io_encoding:
1144 DRM_ERROR("Invalid command format, ioctl %d\n",
1145 nr - DRM_COMMAND_BASE);
1146
1147 return -EINVAL;
1109}1148}
1110 1149
1111static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,1150static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
@@ -1156,7 +1195,6 @@ static void vmw_master_destroy(struct drm_device *dev, · 44 unmodified lines
1156 kfree(vmaster);1195 kfree(vmaster);
1157}1196}
1158 1197
1159
1160static int vmw_master_set(struct drm_device *dev,1198static int vmw_master_set(struct drm_device *dev,
1161 struct drm_file *file_priv,1199 struct drm_file *file_priv,
1162 bool from_open)1200 bool from_open)
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h+86−89
@@ -59,6 +59,8 @@ · 58 unmodified lines
59#define VMWGFX_NUM_GB_SHADER 2000059#define VMWGFX_NUM_GB_SHADER 20000
60#define VMWGFX_NUM_GB_SURFACE 3276860#define VMWGFX_NUM_GB_SURFACE 32768
61#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS61#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS
62#define VMWGFX_NUM_DXCONTEXT 256
63#define VMWGFX_NUM_DXQUERY 512
62#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\64#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\
63 VMWGFX_NUM_GB_SHADER +\65 VMWGFX_NUM_GB_SHADER +\
64 VMWGFX_NUM_GB_SURFACE +\66 VMWGFX_NUM_GB_SURFACE +\
@@ -132,6 +134,9 @@ enum vmw_res_type { · 67 unmodified lines
132 vmw_res_surface,134 vmw_res_surface,
133 vmw_res_stream,135 vmw_res_stream,
134 vmw_res_shader,136 vmw_res_shader,
137 vmw_res_dx_context,
138 vmw_res_cotable,
139 vmw_res_view,
135 vmw_res_max140 vmw_res_max
136};141};
137 142
@@ -139,7 +144,8 @@ enum vmw_res_type { · 1 unmodified line
139 * Resources that are managed using command streams.144 * Resources that are managed using command streams.
140 */145 */
141enum vmw_cmdbuf_res_type {146enum vmw_cmdbuf_res_type {
142 vmw_cmdbuf_res_compat_shader147 vmw_cmdbuf_res_shader,
148 vmw_cmdbuf_res_view
143};149};
144 150
145struct vmw_cmdbuf_res_manager;151struct vmw_cmdbuf_res_manager;
@@ -162,11 +168,13 @@ struct vmw_surface { · 16 unmodified lines
162 struct drm_vmw_size *sizes;168 struct drm_vmw_size *sizes;
163 uint32_t num_sizes;169 uint32_t num_sizes;
164 bool scanout;170 bool scanout;
171 uint32_t array_size;
165 /* TODO so far just a extra pointer */172 /* TODO so far just a extra pointer */
166 struct vmw_cursor_snooper snooper;173 struct vmw_cursor_snooper snooper;
167 struct vmw_surface_offset *offsets;174 struct vmw_surface_offset *offsets;
168 SVGA3dTextureFilter autogen_filter;175 SVGA3dTextureFilter autogen_filter;
169 uint32_t multisample_count;176 uint32_t multisample_count;
177 struct list_head view_list;
170};178};
171 179
172struct vmw_marker_queue {180struct vmw_marker_queue {
@@ -186,6 +194,7 @@ struct vmw_fifo_state { · 13 unmodified lines
186 struct mutex fifo_mutex;194 struct mutex fifo_mutex;
187 struct rw_semaphore rwsem;195 struct rw_semaphore rwsem;
188 struct vmw_marker_queue marker_queue;196 struct vmw_marker_queue marker_queue;
197 bool dx;
189};198};
190 199
191struct vmw_relocation {200struct vmw_relocation {
@@ -265,73 +274,6 @@ struct vmw_piter { · 73 unmodified lines
265 struct page *(*page)(struct vmw_piter *);274 struct page *(*page)(struct vmw_piter *);
266};275};
267 276
268/*
269 * enum vmw_ctx_binding_type - abstract resource to context binding types
270 */
271enum vmw_ctx_binding_type {
272 vmw_ctx_binding_shader,
273 vmw_ctx_binding_rt,
274 vmw_ctx_binding_tex,
275 vmw_ctx_binding_max
276};
277
278/**
279 * struct vmw_ctx_bindinfo - structure representing a single context binding
280 *
281 * @ctx: Pointer to the context structure. NULL means the binding is not
282 * active.
283 * @res: Non ref-counted pointer to the bound resource.
284 * @bt: The binding type.
285 * @i1: Union of information needed to unbind.
286 */
287struct vmw_ctx_bindinfo {
288 struct vmw_resource *ctx;
289 struct vmw_resource *res;
290 enum vmw_ctx_binding_type bt;
291 bool scrubbed;
292 union {
293 SVGA3dShaderType shader_type;
294 SVGA3dRenderTargetType rt_type;
295 uint32 texture_stage;
296 } i1;
297};
298
299/**
300 * struct vmw_ctx_binding - structure representing a single context binding
301 * - suitable for tracking in a context
302 *
303 * @ctx_list: List head for context.
304 * @res_list: List head for bound resource.
305 * @bi: Binding info
306 */
307struct vmw_ctx_binding {
308 struct list_head ctx_list;
309 struct list_head res_list;
310 struct vmw_ctx_bindinfo bi;
311};
312
313
314/**
315 * struct vmw_ctx_binding_state - context binding state
316 *
317 * @list: linked list of individual bindings.
318 * @render_targets: Render target bindings.
319 * @texture_units: Texture units/samplers bindings.
320 * @shaders: Shader bindings.
321 *
322 * Note that this structure also provides storage space for the individual
323 * struct vmw_ctx_binding objects, so that no dynamic allocation is needed
324 * for individual bindings.
325 *
326 */
327struct vmw_ctx_binding_state {
328 struct list_head list;
329 struct vmw_ctx_binding render_targets[SVGA3D_RT_MAX];
330 struct vmw_ctx_binding texture_units[SVGA3D_NUM_TEXTURE_UNITS];
331 struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_PREDX_MAX];
332};
333
334
335/*277/*
336 * enum vmw_display_unit_type - Describes the display unit278 * enum vmw_display_unit_type - Describes the display unit
337 */279 */
@@ -356,6 +298,7 @@ struct vmw_sw_context{ · 18 unmodified lines
356 uint32_t *cmd_bounce;298 uint32_t *cmd_bounce;
357 uint32_t cmd_bounce_size;299 uint32_t cmd_bounce_size;
358 struct list_head resource_list;300 struct list_head resource_list;
301 struct list_head ctx_resource_list; /* For contexts and cotables */
359 struct vmw_dma_buffer *cur_query_bo;302 struct vmw_dma_buffer *cur_query_bo;
360 struct list_head res_relocations;303 struct list_head res_relocations;
361 uint32_t *buf_start;304 uint32_t *buf_start;
@@ -363,8 +306,13 @@ struct vmw_sw_context{ · 1 unmodified line
363 struct vmw_resource *last_query_ctx;306 struct vmw_resource *last_query_ctx;
364 bool needs_post_query_barrier;307 bool needs_post_query_barrier;
365 struct vmw_resource *error_resource;308 struct vmw_resource *error_resource;
366 struct vmw_ctx_binding_state staged_bindings;309 struct vmw_ctx_binding_state *staged_bindings;
310 bool staged_bindings_inuse;
367 struct list_head staged_cmd_res;311 struct list_head staged_cmd_res;
312 struct vmw_resource_val_node *dx_ctx_node;
313 struct vmw_dma_buffer *dx_query_mob;
314 struct vmw_resource *dx_query_ctx;
315 struct vmw_cmdbuf_res_manager *man;
368};316};
369 317
370struct vmw_legacy_display;318struct vmw_legacy_display;
@@ -382,6 +330,26 @@ struct vmw_vga_topology_state { · 11 unmodified lines
382 uint32_t pos_y;330 uint32_t pos_y;
383};331};
384 332
333
334/*
335 * struct vmw_otable - Guest Memory OBject table metadata
336 *
337 * @size: Size of the table (page-aligned).
338 * @page_table: Pointer to a struct vmw_mob holding the page table.
339 */
340struct vmw_otable {
341 unsigned long size;
342 struct vmw_mob *page_table;
343 bool enabled;
344};
345
346struct vmw_otable_batch {
347 unsigned num_otables;
348 struct vmw_otable *otables;
349 struct vmw_resource *context;
350 struct ttm_buffer_object *otable_bo;
351};
352
385struct vmw_private {353struct vmw_private {
386 struct ttm_bo_device bdev;354 struct ttm_bo_device bdev;
387 struct ttm_bo_global_ref bo_global_ref;355 struct ttm_bo_global_ref bo_global_ref;
@@ -417,6 +385,7 @@ struct vmw_private { · 29 unmodified lines
417 bool has_mob;385 bool has_mob;
418 spinlock_t hw_lock;386 spinlock_t hw_lock;
419 spinlock_t cap_lock;387 spinlock_t cap_lock;
388 bool has_dx;
420 389
421 /*390 /*
422 * VGA registers.391 * VGA registers.
@@ -552,8 +521,7 @@ struct vmw_private { · 129 unmodified lines
552 /*521 /*
553 * Guest Backed stuff522 * Guest Backed stuff
554 */523 */
555 struct ttm_buffer_object *otable_bo;524 struct vmw_otable_batch otable_batch;
556 struct vmw_otable *otables;
557 525
558 struct vmw_cmdbuf_man *cman;526 struct vmw_cmdbuf_man *cman;
559};527};
@@ -685,6 +653,7 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv, · 125 unmodified lines
685 uint32_t *inout_id,653 uint32_t *inout_id,
686 struct vmw_resource **out);654 struct vmw_resource **out);
687extern void vmw_resource_unreserve(struct vmw_resource *res,655extern void vmw_resource_unreserve(struct vmw_resource *res,
656 bool switch_backup,
688 struct vmw_dma_buffer *new_backup,657 struct vmw_dma_buffer *new_backup,
689 unsigned long new_backup_offset);658 unsigned long new_backup_offset);
690extern void vmw_resource_move_notify(struct ttm_buffer_object *bo,659extern void vmw_resource_move_notify(struct ttm_buffer_object *bo,
@@ -742,7 +711,10 @@ extern int vmw_fifo_init(struct vmw_private *dev_priv, · 51 unmodified lines
742extern void vmw_fifo_release(struct vmw_private *dev_priv,711extern void vmw_fifo_release(struct vmw_private *dev_priv,
743 struct vmw_fifo_state *fifo);712 struct vmw_fifo_state *fifo);
744extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes);713extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes);
714extern void *
715vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes, int ctx_id);
745extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);716extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);
717extern void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes);
746extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,718extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
747 uint32_t *seqno);719 uint32_t *seqno);
748extern void vmw_fifo_ping_host_locked(struct vmw_private *, uint32_t reason);720extern void vmw_fifo_ping_host_locked(struct vmw_private *, uint32_t reason);
@@ -828,14 +800,15 @@ static inline struct page *vmw_piter_page(struct vmw_piter *viter) · 79 unmodified lines
828 * Command submission - vmwgfx_execbuf.c800 * Command submission - vmwgfx_execbuf.c
829 */801 */
830 802
831extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,803extern int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data,
832 struct drm_file *file_priv);804 struct drm_file *file_priv, size_t size);
833extern int vmw_execbuf_process(struct drm_file *file_priv,805extern int vmw_execbuf_process(struct drm_file *file_priv,
834 struct vmw_private *dev_priv,806 struct vmw_private *dev_priv,
835 void __user *user_commands,807 void __user *user_commands,
836 void *kernel_commands,808 void *kernel_commands,
837 uint32_t command_size,809 uint32_t command_size,
838 uint64_t throttle_us,810 uint64_t throttle_us,
811 uint32_t dx_context_handle,
839 struct drm_vmw_fence_rep __user812 struct drm_vmw_fence_rep __user
840 *user_fence_rep,813 *user_fence_rep,
841 struct vmw_fence_obj **out_fence);814 struct vmw_fence_obj **out_fence);
@@ -960,6 +933,7 @@ int vmw_dumb_destroy(struct drm_file *file_priv, · 118 unmodified lines
960 uint32_t handle);933 uint32_t handle);
961extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);934extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
962extern void vmw_resource_unpin(struct vmw_resource *res);935extern void vmw_resource_unpin(struct vmw_resource *res);
936extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
963 937
964/**938/**
965 * Overlay control - vmwgfx_overlay.c939 * Overlay control - vmwgfx_overlay.c
@@ -1016,27 +990,28 @@ extern void vmw_otables_takedown(struct vmw_private *dev_priv); · 50 unmodified lines
1016 990
1017extern const struct vmw_user_resource_conv *user_context_converter;991extern const struct vmw_user_resource_conv *user_context_converter;
1018 992
1019extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
1020
1021extern int vmw_context_check(struct vmw_private *dev_priv,993extern int vmw_context_check(struct vmw_private *dev_priv,
1022 struct ttm_object_file *tfile,994 struct ttm_object_file *tfile,
1023 int id,995 int id,
1024 struct vmw_resource **p_res);996 struct vmw_resource **p_res);
1025extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,997extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
1026 struct drm_file *file_priv);998 struct drm_file *file_priv);
999extern int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
1000 struct drm_file *file_priv);
1027extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,1001extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
1028 struct drm_file *file_priv);1002 struct drm_file *file_priv);
1029extern int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
1030 const struct vmw_ctx_bindinfo *ci);
1031extern void
1032vmw_context_binding_state_transfer(struct vmw_resource *res,
1033 struct vmw_ctx_binding_state *cbs);
1034extern void vmw_context_binding_res_list_kill(struct list_head *head);
1035extern void vmw_context_binding_res_list_scrub(struct list_head *head);
1036extern int vmw_context_rebind_all(struct vmw_resource *ctx);
1037extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);1003extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);
1038extern struct vmw_cmdbuf_res_manager *1004extern struct vmw_cmdbuf_res_manager *
1039vmw_context_res_man(struct vmw_resource *ctx);1005vmw_context_res_man(struct vmw_resource *ctx);
1006extern struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
1007 SVGACOTableType cotable_type);
1008extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);
1009struct vmw_ctx_binding_state;
1010extern struct vmw_ctx_binding_state *
1011vmw_context_binding_state(struct vmw_resource *ctx);
1012extern void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
1013 bool readback);
1014
1040/*1015/*
1041 * Surface management - vmwgfx_surface.c1016 * Surface management - vmwgfx_surface.c
1042 */1017 */
@@ -1066,6 +1041,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, · 23 unmodified lines
1066 bool for_scanout,1041 bool for_scanout,
1067 uint32_t num_mip_levels,1042 uint32_t num_mip_levels,
1068 uint32_t multisample_count,1043 uint32_t multisample_count,
1044 uint32_t array_size,
1069 struct drm_vmw_size size,1045 struct drm_vmw_size size,
1070 struct vmw_surface **srf_out);1046 struct vmw_surface **srf_out);
1071 1047
@@ -1085,12 +1061,21 @@ extern int vmw_compat_shader_add(struct vmw_private *dev_priv, · 13 unmodified lines
1085 SVGA3dShaderType shader_type,1061 SVGA3dShaderType shader_type,
1086 size_t size,1062 size_t size,
1087 struct list_head *list);1063 struct list_head *list);
1088extern int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man,1064extern int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
1089 u32 user_key, SVGA3dShaderType shader_type,1065 u32 user_key, SVGA3dShaderType shader_type,
1090 struct list_head *list);1066 struct list_head *list);
1067extern int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
1068 struct vmw_resource *ctx,
1069 u32 user_key,
1070 SVGA3dShaderType shader_type,
1071 struct list_head *list);
1072extern void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
1073 struct list_head *list,
1074 bool readback);
1075
1091extern struct vmw_resource *1076extern struct vmw_resource *
1092vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man,1077vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
1093 u32 user_key, SVGA3dShaderType shader_type);1078 u32 user_key, SVGA3dShaderType shader_type);
1094 1079
1095/*1080/*
1096 * Command buffer managed resources - vmwgfx_cmdbuf_res.c1081 * Command buffer managed resources - vmwgfx_cmdbuf_res.c
@@ -1114,8 +1099,20 @@ extern int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, · 17 unmodified lines
1114extern int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,1099extern int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
1115 enum vmw_cmdbuf_res_type res_type,1100 enum vmw_cmdbuf_res_type res_type,
1116 u32 user_key,1101 u32 user_key,
1117 struct list_head *list);1102 struct list_head *list,
1103 struct vmw_resource **res);
1118 1104
1105/*
1106 * COTable management - vmwgfx_cotable.c
1107 */
1108extern const SVGACOTableType vmw_cotable_scrub_order[];
1109extern struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
1110 struct vmw_resource *ctx,
1111 u32 type);
1112extern int vmw_cotable_notify(struct vmw_resource *res, int id);
1113extern int vmw_cotable_scrub(struct vmw_resource *res, bool readback);
1114extern void vmw_cotable_add_resource(struct vmw_resource *ctx,
1115 struct list_head *head);
1119 1116
1120/*1117/*
1121 * Command buffer managerment vmwgfx_cmdbuf.c1118 * Command buffer managerment vmwgfx_cmdbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c+1292−176
@@ -29,6 +29,8 @@ · 28 unmodified lines
29#include "vmwgfx_reg.h"29#include "vmwgfx_reg.h"
30#include <drm/ttm/ttm_bo_api.h>30#include <drm/ttm/ttm_bo_api.h>
31#include <drm/ttm/ttm_placement.h>31#include <drm/ttm/ttm_placement.h>
32#include "vmwgfx_so.h"
33#include "vmwgfx_binding.h"
32 34
33#define VMW_RES_HT_ORDER 1235#define VMW_RES_HT_ORDER 12
34 36
@@ -59,8 +61,11 @@ struct vmw_resource_relocation { · 24 unmodified lines
59 * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.61 * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.
60 * @first_usage: Set to true the first time the resource is referenced in62 * @first_usage: Set to true the first time the resource is referenced in
61 * the command stream.63 * the command stream.
62 * @no_buffer_needed: Resources do not need to allocate buffer backup on64 * @switching_backup: The command stream provides a new backup buffer for a
63 * reservation. The command stream will provide one.65 * resource.
66 * @no_buffer_needed: This means @switching_backup is true on first buffer
67 * reference. So resource reservation does not need to allocate a backup
68 * buffer for the resource.
64 */69 */
65struct vmw_resource_val_node {70struct vmw_resource_val_node {
66 struct list_head head;71 struct list_head head;
@@ -69,8 +74,9 @@ struct vmw_resource_val_node { · 2 unmodified lines
69 struct vmw_dma_buffer *new_backup;74 struct vmw_dma_buffer *new_backup;
70 struct vmw_ctx_binding_state *staged_bindings;75 struct vmw_ctx_binding_state *staged_bindings;
71 unsigned long new_backup_offset;76 unsigned long new_backup_offset;
72 bool first_usage;77 u32 first_usage : 1;
73 bool no_buffer_needed;78 u32 switching_backup : 1;
79 u32 no_buffer_needed : 1;
74};80};
75 81
76/**82/**
@@ -92,6 +98,10 @@ struct vmw_cmd_entry { · 15 unmodified lines
92 [(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\98 [(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\
93 (_gb_disable), (_gb_enable)}99 (_gb_disable), (_gb_enable)}
94 100
101static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
102 struct vmw_sw_context *sw_context,
103 struct vmw_resource *ctx);
104
95/**105/**
96 * vmw_resource_unreserve - unreserve resources previously reserved for106 * vmw_resource_unreserve - unreserve resources previously reserved for
97 * command submission.107 * command submission.
@@ -99,15 +109,16 @@ struct vmw_cmd_entry { · 1 unmodified line
99 * @list_head: list of resources to unreserve.109 * @list_head: list of resources to unreserve.
100 * @backoff: Whether command submission failed.110 * @backoff: Whether command submission failed.
101 */111 */
102static void vmw_resource_list_unreserve(struct list_head *list,112static void vmw_resource_list_unreserve(struct vmw_sw_context *sw_context,
113 struct list_head *list,
103 bool backoff)114 bool backoff)
104{115{
105 struct vmw_resource_val_node *val;116 struct vmw_resource_val_node *val;
106 117
107 list_for_each_entry(val, list, head) {118 list_for_each_entry(val, list, head) {
108 struct vmw_resource *res = val->res;119 struct vmw_resource *res = val->res;
109 struct vmw_dma_buffer *new_backup =120 bool switch_backup =
110 backoff ? NULL : val->new_backup;121 (backoff) ? false : val->switching_backup;
111 122
112 /*123 /*
113 * Transfer staged context bindings to the124 * Transfer staged context bindings to the
@@ -115,18 +126,71 @@ static void vmw_resource_list_unreserve(struct list_head *list, · 1 unmodified line
115 */126 */
116 if (unlikely(val->staged_bindings)) {127 if (unlikely(val->staged_bindings)) {
117 if (!backoff) {128 if (!backoff) {
118 vmw_context_binding_state_transfer129 vmw_binding_state_commit
119 (val->res, val->staged_bindings);130 (vmw_context_binding_state(val->res),
131 val->staged_bindings);
120 }132 }
121 kfree(val->staged_bindings);133
134 if (val->staged_bindings != sw_context->staged_bindings)
135 vmw_binding_state_free(val->staged_bindings);
136 else
137 sw_context->staged_bindings_inuse = false;
122 val->staged_bindings = NULL;138 val->staged_bindings = NULL;
123 }139 }
124 vmw_resource_unreserve(res, new_backup,140 vmw_resource_unreserve(res, switch_backup, val->new_backup,
125 val->new_backup_offset);141 val->new_backup_offset);
126 vmw_dmabuf_unreference(&val->new_backup);142 vmw_dmabuf_unreference(&val->new_backup);
127 }143 }
128}144}
129 145
146/**
147 * vmw_cmd_ctx_first_setup - Perform the setup needed when a context is
148 * added to the validate list.
149 *
150 * @dev_priv: Pointer to the device private:
151 * @sw_context: The validation context:
152 * @node: The validation node holding this context.
153 */
154static int vmw_cmd_ctx_first_setup(struct vmw_private *dev_priv,
155 struct vmw_sw_context *sw_context,
156 struct vmw_resource_val_node *node)
157{
158 int ret;
159
160 ret = vmw_resource_context_res_add(dev_priv, sw_context, node->res);
161 if (unlikely(ret != 0))
162 goto out_err;
163
164 if (!sw_context->staged_bindings) {
165 sw_context->staged_bindings =
166 vmw_binding_state_alloc(dev_priv);
167 if (IS_ERR(sw_context->staged_bindings)) {
168 DRM_ERROR("Failed to allocate context binding "
169 "information.\n");
170 ret = PTR_ERR(sw_context->staged_bindings);
171 sw_context->staged_bindings = NULL;
172 goto out_err;
173 }
174 }
175
176 if (sw_context->staged_bindings_inuse) {
177 node->staged_bindings = vmw_binding_state_alloc(dev_priv);
178 if (IS_ERR(node->staged_bindings)) {
179 DRM_ERROR("Failed to allocate context binding "
180 "information.\n");
181 ret = PTR_ERR(node->staged_bindings);
182 node->staged_bindings = NULL;
183 goto out_err;
184 }
185 } else {
186 node->staged_bindings = sw_context->staged_bindings;
187 sw_context->staged_bindings_inuse = true;
188 }
189
190 return 0;
191out_err:
192 return ret;
193}
130 194
131/**195/**
132 * vmw_resource_val_add - Add a resource to the software context's196 * vmw_resource_val_add - Add a resource to the software context's
@@ -141,6 +205,7 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context, · 8 unmodified lines
141 struct vmw_resource *res,205 struct vmw_resource *res,
142 struct vmw_resource_val_node **p_node)206 struct vmw_resource_val_node **p_node)
143{207{
208 struct vmw_private *dev_priv = res->dev_priv;
144 struct vmw_resource_val_node *node;209 struct vmw_resource_val_node *node;
145 struct drm_hash_item *hash;210 struct drm_hash_item *hash;
146 int ret;211 int ret;
@@ -169,14 +234,90 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context, · 22 unmodified lines
169 kfree(node);234 kfree(node);
170 return ret;235 return ret;
171 }236 }
172 list_add_tail(&node->head, &sw_context->resource_list);
173 node->res = vmw_resource_reference(res);237 node->res = vmw_resource_reference(res);
174 node->first_usage = true;238 node->first_usage = true;
175
176 if (unlikely(p_node != NULL))239 if (unlikely(p_node != NULL))
177 *p_node = node;240 *p_node = node;
178 241
179 return 0;242 if (!dev_priv->has_mob) {
243 list_add_tail(&node->head, &sw_context->resource_list);
244 return 0;
245 }
246
247 switch (vmw_res_type(res)) {
248 case vmw_res_context:
249 case vmw_res_dx_context:
250 list_add(&node->head, &sw_context->ctx_resource_list);
251 ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, node);
252 break;
253 case vmw_res_cotable:
254 list_add_tail(&node->head, &sw_context->ctx_resource_list);
255 break;
256 default:
257 list_add_tail(&node->head, &sw_context->resource_list);
258 break;
259 }
260
261 return ret;
262}
263
264/**
265 * vmw_view_res_val_add - Add a view and the surface it's pointing to
266 * to the validation list
267 *
268 * @sw_context: The software context holding the validation list.
269 * @view: Pointer to the view resource.
270 *
271 * Returns 0 if success, negative error code otherwise.
272 */
273static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
274 struct vmw_resource *view)
275{
276 int ret;
277
278 /*
279 * First add the resource the view is pointing to, otherwise
280 * it may be swapped out when the view is validated.
281 */
282 ret = vmw_resource_val_add(sw_context, vmw_view_srf(view), NULL);
283 if (ret)
284 return ret;
285
286 return vmw_resource_val_add(sw_context, view, NULL);
287}
288
289/**
290 * vmw_view_id_val_add - Look up a view and add it and the surface it's
291 * pointing to to the validation list.
292 *
293 * @sw_context: The software context holding the validation list.
294 * @view_type: The view type to look up.
295 * @id: view id of the view.
296 *
297 * The view is represented by a view id and the DX context it's created on,
298 * or scheduled for creation on. If there is no DX context set, the function
299 * will return -EINVAL. Otherwise returns 0 on success and -EINVAL on failure.
300 */
301static int vmw_view_id_val_add(struct vmw_sw_context *sw_context,
302 enum vmw_view_type view_type, u32 id)
303{
304 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
305 struct vmw_resource *view;
306 int ret;
307
308 if (!ctx_node) {
309 DRM_ERROR("DX Context not set.\n");
310 return -EINVAL;
311 }
312
313 view = vmw_view_lookup(sw_context->man, view_type, id);
314 if (IS_ERR(view))
315 return PTR_ERR(view);
316
317 ret = vmw_view_res_val_add(sw_context, view);
318 vmw_resource_unreference(&view);
319
320 return ret;
180}321}
181 322
182/**323/**
@@ -195,19 +336,41 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, · 12 unmodified lines
195 struct vmw_resource *ctx)336 struct vmw_resource *ctx)
196{337{
197 struct list_head *binding_list;338 struct list_head *binding_list;
198 struct vmw_ctx_binding *entry;339 struct vmw_ctx_bindinfo *entry;
199 int ret = 0;340 int ret = 0;
200 struct vmw_resource *res;341 struct vmw_resource *res;
342 u32 i;
343
344 /* Add all cotables to the validation list. */
345 if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) {
346 for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
347 res = vmw_context_cotable(ctx, i);
348 if (IS_ERR(res))
349 continue;
350
351 ret = vmw_resource_val_add(sw_context, res, NULL);
352 vmw_resource_unreference(&res);
353 if (unlikely(ret != 0))
354 return ret;
355 }
356 }
357
201 358
359 /* Add all resources bound to the context to the validation list */
202 mutex_lock(&dev_priv->binding_mutex);360 mutex_lock(&dev_priv->binding_mutex);
203 binding_list = vmw_context_binding_list(ctx);361 binding_list = vmw_context_binding_list(ctx);
204 362
205 list_for_each_entry(entry, binding_list, ctx_list) {363 list_for_each_entry(entry, binding_list, ctx_list) {
206 res = vmw_resource_reference_unless_doomed(entry->bi.res);364 /* entry->res is not refcounted */
365 res = vmw_resource_reference_unless_doomed(entry->res);
207 if (unlikely(res == NULL))366 if (unlikely(res == NULL))
208 continue;367 continue;
209 368
210 ret = vmw_resource_val_add(sw_context, entry->bi.res, NULL);369 if (vmw_res_type(entry->res) == vmw_res_view)
370 ret = vmw_view_res_val_add(sw_context, entry->res);
371 else
372 ret = vmw_resource_val_add(sw_context, entry->res,
373 NULL);
211 vmw_resource_unreference(&res);374 vmw_resource_unreference(&res);
212 if (unlikely(ret != 0))375 if (unlikely(ret != 0))
213 break;376 break;
@@ -409,6 +572,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) · 195 unmodified lines
409 572
410 list_for_each_entry(val, &sw_context->resource_list, head) {573 list_for_each_entry(val, &sw_context->resource_list, head) {
411 struct vmw_resource *res = val->res;574 struct vmw_resource *res = val->res;
575 struct vmw_dma_buffer *backup = res->backup;
412 576
413 ret = vmw_resource_validate(res);577 ret = vmw_resource_validate(res);
414 if (unlikely(ret != 0)) {578 if (unlikely(ret != 0)) {
@@ -416,18 +580,29 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) · 1 unmodified line
416 DRM_ERROR("Failed to validate resource.\n");580 DRM_ERROR("Failed to validate resource.\n");
417 return ret;581 return ret;
418 }582 }
583
584 /* Check if the resource switched backup buffer */
585 if (backup && res->backup && (backup != res->backup)) {
586 struct vmw_dma_buffer *vbo = res->backup;
587
588 ret = vmw_bo_to_validate_list
589 (sw_context, vbo,
590 vmw_resource_needs_backup(res), NULL);
591 if (ret) {
592 ttm_bo_unreserve(&vbo->base);
593 return ret;
594 }
595 }
419 }596 }
420 return 0;597 return 0;
421}598}
422 599
423
424/**600/**
425 * vmw_cmd_res_reloc_add - Add a resource to a software context's601 * vmw_cmd_res_reloc_add - Add a resource to a software context's
426 * relocation- and validation lists.602 * relocation- and validation lists.
427 *603 *
428 * @dev_priv: Pointer to a struct vmw_private identifying the device.604 * @dev_priv: Pointer to a struct vmw_private identifying the device.
429 * @sw_context: Pointer to the software context.605 * @sw_context: Pointer to the software context.
430 * @res_type: Resource type.
431 * @id_loc: Pointer to where the id that needs translation is located.606 * @id_loc: Pointer to where the id that needs translation is located.
432 * @res: Valid pointer to a struct vmw_resource.607 * @res: Valid pointer to a struct vmw_resource.
433 * @p_val: If non null, a pointer to the struct vmw_resource_validate_node608 * @p_val: If non null, a pointer to the struct vmw_resource_validate_node
@@ -435,7 +610,6 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) · 1 unmodified line
435 */610 */
436static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,611static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
437 struct vmw_sw_context *sw_context,612 struct vmw_sw_context *sw_context,
438 enum vmw_res_type res_type,
439 uint32_t *id_loc,613 uint32_t *id_loc,
440 struct vmw_resource *res,614 struct vmw_resource *res,
441 struct vmw_resource_val_node **p_val)615 struct vmw_resource_val_node **p_val)
@@ -454,29 +628,6 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv, · 12 unmodified lines
454 if (unlikely(ret != 0))628 if (unlikely(ret != 0))
455 return ret;629 return ret;
456 630
457 if (res_type == vmw_res_context && dev_priv->has_mob &&
458 node->first_usage) {
459
460 /*
461 * Put contexts first on the list to be able to exit
462 * list traversal for contexts early.
463 */
464 list_del(&node->head);
465 list_add(&node->head, &sw_context->resource_list);
466
467 ret = vmw_resource_context_res_add(dev_priv, sw_context, res);
468 if (unlikely(ret != 0))
469 return ret;
470 node->staged_bindings =
471 kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL);
472 if (node->staged_bindings == NULL) {
473 DRM_ERROR("Failed to allocate context binding "
474 "information.\n");
475 return -ENOMEM;
476 }
477 INIT_LIST_HEAD(&node->staged_bindings->list);
478 }
479
480 if (p_val)631 if (p_val)
481 *p_val = node;632 *p_val = node;
482 633
@@ -554,7 +705,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, · 71 unmodified lines
554 rcache->res = res;705 rcache->res = res;
555 rcache->handle = *id_loc;706 rcache->handle = *id_loc;
556 707
557 ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, res_type, id_loc,708 ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, id_loc,
558 res, &node);709 res, &node);
559 if (unlikely(ret != 0))710 if (unlikely(ret != 0))
560 goto out_no_reloc;711 goto out_no_reloc;
@@ -589,7 +740,8 @@ static int vmw_rebind_contexts(struct vmw_sw_context *sw_context) · 28 unmodified lines
589 if (unlikely(!val->staged_bindings))740 if (unlikely(!val->staged_bindings))
590 break;741 break;
591 742
592 ret = vmw_context_rebind_all(val->res);743 ret = vmw_binding_rebind_all
744 (vmw_context_binding_state(val->res));
593 if (unlikely(ret != 0)) {745 if (unlikely(ret != 0)) {
594 if (ret != -ERESTARTSYS)746 if (ret != -ERESTARTSYS)
595 DRM_ERROR("Failed to rebind context.\n");747 DRM_ERROR("Failed to rebind context.\n");
@@ -600,6 +752,69 @@ static int vmw_rebind_contexts(struct vmw_sw_context *sw_context) · 4 unmodified lines
600 return 0;752 return 0;
601}753}
602 754
755/**
756 * vmw_view_bindings_add - Add an array of view bindings to a context
757 * binding state tracker.
758 *
759 * @sw_context: The execbuf state used for this command.
760 * @view_type: View type for the bindings.
761 * @binding_type: Binding type for the bindings.
762 * @shader_slot: The shader slot to user for the bindings.
763 * @view_ids: Array of view ids to be bound.
764 * @num_views: Number of view ids in @view_ids.
765 * @first_slot: The binding slot to be used for the first view id in @view_ids.
766 */
767static int vmw_view_bindings_add(struct vmw_sw_context *sw_context,
768 enum vmw_view_type view_type,
769 enum vmw_ctx_binding_type binding_type,
770 uint32 shader_slot,
771 uint32 view_ids[], u32 num_views,
772 u32 first_slot)
773{
774 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
775 struct vmw_cmdbuf_res_manager *man;
776 u32 i;
777 int ret;
778
779 if (!ctx_node) {
780 DRM_ERROR("DX Context not set.\n");
781 return -EINVAL;
782 }
783
784 man = sw_context->man;
785 for (i = 0; i < num_views; ++i) {
786 struct vmw_ctx_bindinfo_view binding;
787 struct vmw_resource *view = NULL;
788
789 if (view_ids[i] != SVGA3D_INVALID_ID) {
790 view = vmw_view_lookup(man, view_type, view_ids[i]);
791 if (IS_ERR(view)) {
792 DRM_ERROR("View not found.\n");
793 return PTR_ERR(view);
794 }
795
796 ret = vmw_view_res_val_add(sw_context, view);
797 if (ret) {
798 DRM_ERROR("Could not add view to "
799 "validation list.\n");
800 vmw_resource_unreference(&view);
801 return ret;
802 }
803 }
804 binding.bi.ctx = ctx_node->res;
805 binding.bi.res = view;
806 binding.bi.bt = binding_type;
807 binding.shader_slot = shader_slot;
808 binding.slot = first_slot + i;
809 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
810 shader_slot, binding.slot);
811 if (view)
812 vmw_resource_unreference(&view);
813 }
814
815 return 0;
816}
817
603/**818/**
604 * vmw_cmd_cid_check - Check a command header for valid context information.819 * vmw_cmd_cid_check - Check a command header for valid context information.
605 *820 *
@@ -638,6 +853,12 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv, · 32 unmodified lines
638 853
639 cmd = container_of(header, struct vmw_sid_cmd, header);854 cmd = container_of(header, struct vmw_sid_cmd, header);
640 855
856 if (cmd->body.type >= SVGA3D_RT_MAX) {
857 DRM_ERROR("Illegal render target type %u.\n",
858 (unsigned) cmd->body.type);
859 return -EINVAL;
860 }
861
641 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,862 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
642 user_context_converter, &cmd->body.cid,863 user_context_converter, &cmd->body.cid,
643 &ctx_node);864 &ctx_node);
@@ -651,13 +872,14 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv, · 7 unmodified lines
651 return ret;872 return ret;
652 873
653 if (dev_priv->has_mob) {874 if (dev_priv->has_mob) {
654 struct vmw_ctx_bindinfo bi;875 struct vmw_ctx_bindinfo_view binding;
655 876
656 bi.ctx = ctx_node->res;877 binding.bi.ctx = ctx_node->res;
657 bi.res = res_node ? res_node->res : NULL;878 binding.bi.res = res_node ? res_node->res : NULL;
658 bi.bt = vmw_ctx_binding_rt;879 binding.bi.bt = vmw_ctx_binding_rt;
659 bi.i1.rt_type = cmd->body.type;880 binding.slot = cmd->body.type;
660 return vmw_context_binding_add(ctx_node->staged_bindings, &bi);881 vmw_binding_add(ctx_node->staged_bindings,
882 &binding.bi, 0, binding.slot);
661 }883 }
662 884
663 return 0;885 return 0;
@@ -1364,6 +1586,12 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv, · 700 unmodified lines
1364 if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))1586 if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
1365 continue;1587 continue;
1366 1588
1589 if (cur_state->stage >= SVGA3D_NUM_TEXTURE_UNITS) {
1590 DRM_ERROR("Illegal texture/sampler unit %u.\n",
1591 (unsigned) cur_state->stage);
1592 return -EINVAL;
1593 }
1594
1367 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,1595 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
1368 user_surface_converter,1596 user_surface_converter,
1369 &cur_state->value, &res_node);1597 &cur_state->value, &res_node);
@@ -1371,14 +1599,14 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv, · 1 unmodified line
1371 return ret;1599 return ret;
1372 1600
1373 if (dev_priv->has_mob) {1601 if (dev_priv->has_mob) {
1374 struct vmw_ctx_bindinfo bi;1602 struct vmw_ctx_bindinfo_tex binding;
1375 1603
1376 bi.ctx = ctx_node->res;1604 binding.bi.ctx = ctx_node->res;
1377 bi.res = res_node ? res_node->res : NULL;1605 binding.bi.res = res_node ? res_node->res : NULL;
1378 bi.bt = vmw_ctx_binding_tex;1606 binding.bi.bt = vmw_ctx_binding_tex;
1379 bi.i1.texture_stage = cur_state->stage;1607 binding.texture_stage = cur_state->stage;
1380 vmw_context_binding_add(ctx_node->staged_bindings,1608 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
1381 &bi);1609 0, binding.texture_stage);
1382 }1610 }
1383 }1611 }
1384 1612
@@ -1408,6 +1636,47 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, · 23 unmodified lines
1408 return ret;1636 return ret;
1409}1637}
1410 1638
1639
1640/**
1641 * vmw_cmd_res_switch_backup - Utility function to handle backup buffer
1642 * switching
1643 *
1644 * @dev_priv: Pointer to a device private struct.
1645 * @sw_context: The software context being used for this batch.
1646 * @val_node: The validation node representing the resource.
1647 * @buf_id: Pointer to the user-space backup buffer handle in the command
1648 * stream.
1649 * @backup_offset: Offset of backup into MOB.
1650 *
1651 * This function prepares for registering a switch of backup buffers
1652 * in the resource metadata just prior to unreserving. It's basically a wrapper
1653 * around vmw_cmd_res_switch_backup with a different interface.
1654 */
1655static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv,
1656 struct vmw_sw_context *sw_context,
1657 struct vmw_resource_val_node *val_node,
1658 uint32_t *buf_id,
1659 unsigned long backup_offset)
1660{
1661 struct vmw_dma_buffer *dma_buf;
1662 int ret;
1663
1664 ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
1665 if (ret)
1666 return ret;
1667
1668 val_node->switching_backup = true;
1669 if (val_node->first_usage)
1670 val_node->no_buffer_needed = true;
1671
1672 vmw_dmabuf_unreference(&val_node->new_backup);
1673 val_node->new_backup = dma_buf;
1674 val_node->new_backup_offset = backup_offset;
1675
1676 return 0;
1677}
1678
1679
1411/**1680/**
1412 * vmw_cmd_switch_backup - Utility function to handle backup buffer switching1681 * vmw_cmd_switch_backup - Utility function to handle backup buffer switching
1413 *1682 *
@@ -1421,7 +1690,8 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, · 7 unmodified lines
1421 * @backup_offset: Offset of backup into MOB.1690 * @backup_offset: Offset of backup into MOB.
1422 *1691 *
1423 * This function prepares for registering a switch of backup buffers1692 * This function prepares for registering a switch of backup buffers
1424 * in the resource metadata just prior to unreserving.1693 * in the resource metadata just prior to unreserving. It's basically a wrapper
1694 * around vmw_cmd_res_switch_backup with a different interface.
1425 */1695 */
1426static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,1696static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,
1427 struct vmw_sw_context *sw_context,1697 struct vmw_sw_context *sw_context,
@@ -1432,27 +1702,16 @@ static int vmw_cmd_switch_backup(struct vmw_private *dev_priv, · 4 unmodified lines
1432 uint32_t *buf_id,1702 uint32_t *buf_id,
1433 unsigned long backup_offset)1703 unsigned long backup_offset)
1434{1704{
1435 int ret;
1436 struct vmw_dma_buffer *dma_buf;
1437 struct vmw_resource_val_node *val_node;1705 struct vmw_resource_val_node *val_node;
1706 int ret;
1438 1707
1439 ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,1708 ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,
1440 converter, res_id, &val_node);1709 converter, res_id, &val_node);
1441 if (unlikely(ret != 0))1710 if (ret)
1442 return ret;
1443
1444 ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
1445 if (unlikely(ret != 0))
1446 return ret;1711 return ret;
1447 1712
1448 if (val_node->first_usage)1713 return vmw_cmd_res_switch_backup(dev_priv, sw_context, val_node,
1449 val_node->no_buffer_needed = true;1714 buf_id, backup_offset);
1450
1451 vmw_dmabuf_unreference(&val_node->new_backup);
1452 val_node->new_backup = dma_buf;
1453 val_node->new_backup_offset = backup_offset;
1454
1455 return 0;
1456}1715}
1457 1716
1458/**1717/**
@@ -1704,10 +1963,10 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv, · 245 unmodified lines
1704 if (unlikely(!dev_priv->has_mob))1963 if (unlikely(!dev_priv->has_mob))
1705 return 0;1964 return 0;
1706 1965
1707 ret = vmw_compat_shader_remove(vmw_context_res_man(val->res),1966 ret = vmw_shader_remove(vmw_context_res_man(val->res),
1708 cmd->body.shid,1967 cmd->body.shid,
1709 cmd->body.type,1968 cmd->body.type,
1710 &sw_context->staged_cmd_res);1969 &sw_context->staged_cmd_res);
1711 if (unlikely(ret != 0))1970 if (unlikely(ret != 0))
1712 return ret;1971 return ret;
1713 1972
@@ -1735,13 +1994,19 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv, · 21 unmodified lines
1735 SVGA3dCmdSetShader body;1994 SVGA3dCmdSetShader body;
1736 } *cmd;1995 } *cmd;
1737 struct vmw_resource_val_node *ctx_node, *res_node = NULL;1996 struct vmw_resource_val_node *ctx_node, *res_node = NULL;
1738 struct vmw_ctx_bindinfo bi;1997 struct vmw_ctx_bindinfo_shader binding;
1739 struct vmw_resource *res = NULL;1998 struct vmw_resource *res = NULL;
1740 int ret;1999 int ret;
1741 2000
1742 cmd = container_of(header, struct vmw_set_shader_cmd,2001 cmd = container_of(header, struct vmw_set_shader_cmd,
1743 header);2002 header);
1744 2003
2004 if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) {
2005 DRM_ERROR("Illegal shader type %u.\n",
2006 (unsigned) cmd->body.type);
2007 return -EINVAL;
2008 }
2009
1745 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,2010 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
1746 user_context_converter, &cmd->body.cid,2011 user_context_converter, &cmd->body.cid,
1747 &ctx_node);2012 &ctx_node);
@@ -1752,14 +2017,12 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv, · 4 unmodified lines
1752 return 0;2017 return 0;
1753 2018
1754 if (cmd->body.shid != SVGA3D_INVALID_ID) {2019 if (cmd->body.shid != SVGA3D_INVALID_ID) {
1755 res = vmw_compat_shader_lookup2020 res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res),
1756 (vmw_context_res_man(ctx_node->res),2021 cmd->body.shid,
1757 cmd->body.shid,2022 cmd->body.type);
1758 cmd->body.type);
1759 2023
1760 if (!IS_ERR(res)) {2024 if (!IS_ERR(res)) {
1761 ret = vmw_cmd_res_reloc_add(dev_priv, sw_context,2025 ret = vmw_cmd_res_reloc_add(dev_priv, sw_context,
1762 vmw_res_shader,
1763 &cmd->body.shid, res,2026 &cmd->body.shid, res,
1764 &res_node);2027 &res_node);
1765 vmw_resource_unreference(&res);2028 vmw_resource_unreference(&res);
@@ -1777,11 +2040,13 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv, · 11 unmodified lines
1777 return ret;2040 return ret;
1778 }2041 }
1779 2042
1780 bi.ctx = ctx_node->res;2043 binding.bi.ctx = ctx_node->res;
1781 bi.res = res_node ? res_node->res : NULL;2044 binding.bi.res = res_node ? res_node->res : NULL;
1782 bi.bt = vmw_ctx_binding_shader;2045 binding.bi.bt = vmw_ctx_binding_shader;
1783 bi.i1.shader_type = cmd->body.type;2046 binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
1784 return vmw_context_binding_add(ctx_node->staged_bindings, &bi);2047 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
2048 binding.shader_slot, 0);
2049 return 0;
1785}2050}
1786 2051
1787/**2052/**
@@ -1843,78 +2108,705 @@ static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv, · 55 unmodified lines
1843 cmd->body.offsetInBytes);2108 cmd->body.offsetInBytes);
1844}2109}
1845 2110
1846static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,2111/**
1847 struct vmw_sw_context *sw_context,2112 * vmw_cmd_dx_set_single_constant_buffer - Validate an
1848 void *buf, uint32_t *size)2113 * SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER command.
2114 *
2115 * @dev_priv: Pointer to a device private struct.
2116 * @sw_context: The software context being used for this batch.
2117 * @header: Pointer to the command header in the command stream.
2118 */
2119static int
2120vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
2121 struct vmw_sw_context *sw_context,
2122 SVGA3dCmdHeader *header)
1849{2123{
1850 uint32_t size_remaining = *size;2124 struct {
1851 uint32_t cmd_id;2125 SVGA3dCmdHeader header;
2126 SVGA3dCmdDXSetSingleConstantBuffer body;
2127 } *cmd;
2128 struct vmw_resource_val_node *res_node = NULL;
2129 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2130 struct vmw_ctx_bindinfo_cb binding;
2131 int ret;
1852 2132
1853 cmd_id = ((uint32_t *)buf)[0];2133 if (unlikely(ctx_node == NULL)) {
1854 switch (cmd_id) {2134 DRM_ERROR("DX Context not set.\n");
1855 case SVGA_CMD_UPDATE:
1856 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate);
1857 break;
1858 case SVGA_CMD_DEFINE_GMRFB:
1859 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdDefineGMRFB);
1860 break;
1861 case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
1862 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
1863 break;
1864 case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
1865 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
1866 break;
1867 default:
1868 DRM_ERROR("Unsupported SVGA command: %u.\n", cmd_id);
1869 return -EINVAL;2135 return -EINVAL;
1870 }2136 }
1871 2137
1872 if (*size > size_remaining) {2138 cmd = container_of(header, typeof(*cmd), header);
1873 DRM_ERROR("Invalid SVGA command (size mismatch):"2139 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
1874 " %u.\n", cmd_id);2140 user_surface_converter,
1875 return -EINVAL;2141 &cmd->body.sid, &res_node);
1876 }2142 if (unlikely(ret != 0))
2143 return ret;
1877 2144
1878 if (unlikely(!sw_context->kernel)) {2145 binding.bi.ctx = ctx_node->res;
1879 DRM_ERROR("Kernel only SVGA command: %u.\n", cmd_id);2146 binding.bi.res = res_node ? res_node->res : NULL;
1880 return -EPERM;2147 binding.bi.bt = vmw_ctx_binding_cb;
2148 binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
2149 binding.offset = cmd->body.offsetInBytes;
2150 binding.size = cmd->body.sizeInBytes;
2151 binding.slot = cmd->body.slot;
2152
2153 if (binding.shader_slot >= SVGA3D_NUM_SHADERTYPE_DX10 ||
2154 binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
2155 DRM_ERROR("Illegal const buffer shader %u slot %u.\n",
2156 (unsigned) cmd->body.type,
2157 (unsigned) binding.slot);
2158 return -EINVAL;
1881 }2159 }
1882 2160
1883 if (cmd_id == SVGA_CMD_DEFINE_GMRFB)2161 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
1884 return vmw_cmd_check_define_gmrfb(dev_priv, sw_context, buf);2162 binding.shader_slot, binding.slot);
1885 2163
1886 return 0;2164 return 0;
1887}2165}
1888 2166
1889static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {2167/**
1890 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,2168 * vmw_cmd_dx_set_shader_res - Validate an
1891 false, false, false),2169 * SVGA_3D_CMD_DX_SET_SHADER_RESOURCES command
1892 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,2170 *
1893 false, false, false),2171 * @dev_priv: Pointer to a device private struct.
1894 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check,2172 * @sw_context: The software context being used for this batch.
1895 true, false, false),2173 * @header: Pointer to the command header in the command stream.
1896 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check,2174 */
1897 true, false, false),2175static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv,
1898 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma,2176 struct vmw_sw_context *sw_context,
1899 true, false, false),2177 SVGA3dCmdHeader *header)
1900 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid,2178{
1901 false, false, false),2179 struct {
1902 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid,2180 SVGA3dCmdHeader header;
1903 false, false, false),2181 SVGA3dCmdDXSetShaderResources body;
1904 VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check,2182 } *cmd = container_of(header, typeof(*cmd), header);
1905 true, false, false),2183 u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) /
1906 VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check,2184 sizeof(SVGA3dShaderResourceViewId);
1907 true, false, false),2185
1908 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check,2186 if ((u64) cmd->body.startView + (u64) num_sr_view >
1909 true, false, false),2187 (u64) SVGA3D_DX_MAX_SRVIEWS ||
1910 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,2188 cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
1911 &vmw_cmd_set_render_target_check, true, false, false),2189 DRM_ERROR("Invalid shader binding.\n");
1912 VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state,2190 return -EINVAL;
1913 true, false, false),2191 }
1914 VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check,2192
1915 true, false, false),2193 return vmw_view_bindings_add(sw_context, vmw_view_sr,
1916 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check,2194 vmw_ctx_binding_sr,
1917 true, false, false),2195 cmd->body.type - SVGA3D_SHADERTYPE_MIN,
2196 (void *) &cmd[1], num_sr_view,
2197 cmd->body.startView);
2198}
2199
2200/**
2201 * vmw_cmd_dx_set_shader - Validate an SVGA_3D_CMD_DX_SET_SHADER
2202 * command
2203 *
2204 * @dev_priv: Pointer to a device private struct.
2205 * @sw_context: The software context being used for this batch.
2206 * @header: Pointer to the command header in the command stream.
2207 */
2208static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
2209 struct vmw_sw_context *sw_context,
2210 SVGA3dCmdHeader *header)
2211{
2212 struct {
2213 SVGA3dCmdHeader header;
2214 SVGA3dCmdDXSetShader body;
2215 } *cmd;
2216 struct vmw_resource *res = NULL;
2217 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2218 struct vmw_ctx_bindinfo_shader binding;
2219 int ret = 0;
2220
2221 if (unlikely(ctx_node == NULL)) {
2222 DRM_ERROR("DX Context not set.\n");
2223 return -EINVAL;
2224 }
2225
2226 cmd = container_of(header, typeof(*cmd), header);
2227
2228 if (cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
2229 DRM_ERROR("Illegal shader type %u.\n",
2230 (unsigned) cmd->body.type);
2231 return -EINVAL;
2232 }
2233
2234 if (cmd->body.shaderId != SVGA3D_INVALID_ID) {
2235 res = vmw_shader_lookup(sw_context->man, cmd->body.shaderId, 0);
2236 if (IS_ERR(res)) {
2237 DRM_ERROR("Could not find shader for binding.\n");
2238 return PTR_ERR(res);
2239 }
2240
2241 ret = vmw_resource_val_add(sw_context, res, NULL);
2242 if (ret)
2243 goto out_unref;
2244 }
2245
2246 binding.bi.ctx = ctx_node->res;
2247 binding.bi.res = res;
2248 binding.bi.bt = vmw_ctx_binding_dx_shader;
2249 binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
2250
2251 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
2252 binding.shader_slot, 0);
2253out_unref:
2254 if (res)
2255 vmw_resource_unreference(&res);
2256
2257 return ret;
2258}
2259
2260/**
2261 * vmw_cmd_dx_set_vertex_buffers - Validates an
2262 * SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS command
2263 *
2264 * @dev_priv: Pointer to a device private struct.
2265 * @sw_context: The software context being used for this batch.
2266 * @header: Pointer to the command header in the command stream.
2267 */
2268static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv,
2269 struct vmw_sw_context *sw_context,
2270 SVGA3dCmdHeader *header)
2271{
2272 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2273 struct vmw_ctx_bindinfo_vb binding;
2274 struct vmw_resource_val_node *res_node;
2275 struct {
2276 SVGA3dCmdHeader header;
2277 SVGA3dCmdDXSetVertexBuffers body;
2278 SVGA3dVertexBuffer buf[];
2279 } *cmd;
2280 int i, ret, num;
2281
2282 if (unlikely(ctx_node == NULL)) {
2283 DRM_ERROR("DX Context not set.\n");
2284 return -EINVAL;
2285 }
2286
2287 cmd = container_of(header, typeof(*cmd), header);
2288 num = (cmd->header.size - sizeof(cmd->body)) /
2289 sizeof(SVGA3dVertexBuffer);
2290 if ((u64)num + (u64)cmd->body.startBuffer >
2291 (u64)SVGA3D_DX_MAX_VERTEXBUFFERS) {
2292 DRM_ERROR("Invalid number of vertex buffers.\n");
2293 return -EINVAL;
2294 }
2295
2296 for (i = 0; i < num; i++) {
2297 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
2298 user_surface_converter,
2299 &cmd->buf[i].sid, &res_node);
2300 if (unlikely(ret != 0))
2301 return ret;
2302
2303 binding.bi.ctx = ctx_node->res;
2304 binding.bi.bt = vmw_ctx_binding_vb;
2305 binding.bi.res = ((res_node) ? res_node->res : NULL);
2306 binding.offset = cmd->buf[i].offset;
2307 binding.stride = cmd->buf[i].stride;
2308 binding.slot = i + cmd->body.startBuffer;
2309
2310 vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
2311 0, binding.slot);
2312 }
2313
2314 return 0;
2315}
2316
2317/**
2318 * vmw_cmd_dx_ia_set_vertex_buffers - Validate an
2319 * SVGA_3D_CMD_DX_IA_SET_VERTEX_BUFFERS command.
2320 *
2321 * @dev_priv: Pointer to a device private struct.
2322 * @sw_context: The software context being used for this batch.
2323 * @header: Pointer to the command header in the command stream.
2324 */
2325static int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv,
2326 struct vmw_sw_context *sw_context,
2327 SVGA3dCmdHeader *header)
2328{
2329 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2330 struct vmw_ctx_bindinfo_ib binding;
2331 struct vmw_resource_val_node *res_node;
2332 struct {
2333 SVGA3dCmdHeader header;
2334 SVGA3dCmdDXSetIndexBuffer body;
2335 } *cmd;
2336 int ret;
2337
2338 if (unlikely(ctx_node == NULL)) {
2339 DRM_ERROR("DX Context not set.\n");
2340 return -EINVAL;
2341 }
2342
2343 cmd = container_of(header, typeof(*cmd), header);
2344 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
2345 user_surface_converter,
2346 &cmd->body.sid, &res_node);
2347 if (unlikely(ret != 0))
2348 return ret;
2349
2350 binding.bi.ctx = ctx_node->res;
2351 binding.bi.res = ((res_node) ? res_node->res : NULL);
2352 binding.bi.bt = vmw_ctx_binding_ib;
2353 binding.offset = cmd->body.offset;
2354 binding.format = cmd->body.format;
2355
2356 vmw_binding_add(ctx_node->staged_bindings, &binding.bi, 0, 0);
2357
2358 return 0;
2359}
2360
2361/**
2362 * vmw_cmd_dx_set_rendertarget - Validate an
2363 * SVGA_3D_CMD_DX_SET_RENDERTARGETS command
2364 *
2365 * @dev_priv: Pointer to a device private struct.
2366 * @sw_context: The software context being used for this batch.
2367 * @header: Pointer to the command header in the command stream.
2368 */
2369static int vmw_cmd_dx_set_rendertargets(struct vmw_private *dev_priv,
2370 struct vmw_sw_context *sw_context,
2371 SVGA3dCmdHeader *header)
2372{
2373 struct {
2374 SVGA3dCmdHeader header;
2375 SVGA3dCmdDXSetRenderTargets body;
2376 } *cmd = container_of(header, typeof(*cmd), header);
2377 int ret;
2378 u32 num_rt_view = (cmd->header.size - sizeof(cmd->body)) /
2379 sizeof(SVGA3dRenderTargetViewId);
2380
2381 if (num_rt_view > SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS) {
2382 DRM_ERROR("Invalid DX Rendertarget binding.\n");
2383 return -EINVAL;
2384 }
2385
2386 ret = vmw_view_bindings_add(sw_context, vmw_view_ds,
2387 vmw_ctx_binding_ds, 0,
2388 &cmd->body.depthStencilViewId, 1, 0);
2389 if (ret)
2390 return ret;
2391
2392 return vmw_view_bindings_add(sw_context, vmw_view_rt,
2393 vmw_ctx_binding_dx_rt, 0,
2394 (void *)&cmd[1], num_rt_view, 0);
2395}
2396
2397/**
2398 * vmw_cmd_dx_clear_rendertarget_view - Validate an
2399 * SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW command
2400 *
2401 * @dev_priv: Pointer to a device private struct.
2402 * @sw_context: The software context being used for this batch.
2403 * @header: Pointer to the command header in the command stream.
2404 */
2405static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv,
2406 struct vmw_sw_context *sw_context,
2407 SVGA3dCmdHeader *header)
2408{
2409 struct {
2410 SVGA3dCmdHeader header;
2411 SVGA3dCmdDXClearRenderTargetView body;
2412 } *cmd = container_of(header, typeof(*cmd), header);
2413
2414 return vmw_view_id_val_add(sw_context, vmw_view_rt,
2415 cmd->body.renderTargetViewId);
2416}
2417
2418/**
2419 * vmw_cmd_dx_clear_rendertarget_view - Validate an
2420 * SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command
2421 *
2422 * @dev_priv: Pointer to a device private struct.
2423 * @sw_context: The software context being used for this batch.
2424 * @header: Pointer to the command header in the command stream.
2425 */
2426static int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv,
2427 struct vmw_sw_context *sw_context,
2428 SVGA3dCmdHeader *header)
2429{
2430 struct {
2431 SVGA3dCmdHeader header;
2432 SVGA3dCmdDXClearDepthStencilView body;
2433 } *cmd = container_of(header, typeof(*cmd), header);
2434
2435 return vmw_view_id_val_add(sw_context, vmw_view_ds,
2436 cmd->body.depthStencilViewId);
2437}
2438
2439static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv,
2440 struct vmw_sw_context *sw_context,
2441 SVGA3dCmdHeader *header)
2442{
2443 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2444 struct vmw_resource_val_node *srf_node;
2445 struct vmw_resource *res;
2446 enum vmw_view_type view_type;
2447 int ret;
2448 /*
2449 * This is based on the fact that all affected define commands have
2450 * the same initial command body layout.
2451 */
2452 struct {
2453 SVGA3dCmdHeader header;
2454 uint32 defined_id;
2455 uint32 sid;
2456 } *cmd;
2457
2458 if (unlikely(ctx_node == NULL)) {
2459 DRM_ERROR("DX Context not set.\n");
2460 return -EINVAL;
2461 }
2462
2463 view_type = vmw_view_cmd_to_type(header->id);
2464 cmd = container_of(header, typeof(*cmd), header);
2465 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
2466 user_surface_converter,
2467 &cmd->sid, &srf_node);
2468 if (unlikely(ret != 0))
2469 return ret;
2470
2471 res = vmw_context_cotable(ctx_node->res, vmw_view_cotables[view_type]);
2472 ret = vmw_cotable_notify(res, cmd->defined_id);
2473 vmw_resource_unreference(&res);
2474 if (unlikely(ret != 0))
2475 return ret;
2476
2477 return vmw_view_add(sw_context->man,
2478 ctx_node->res,
2479 srf_node->res,
2480 view_type,
2481 cmd->defined_id,
2482 header,
2483 header->size + sizeof(*header),
2484 &sw_context->staged_cmd_res);
2485}
2486
2487static int vmw_cmd_dx_so_define(struct vmw_private *dev_priv,
2488 struct vmw_sw_context *sw_context,
2489 SVGA3dCmdHeader *header)
2490{
2491 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2492 struct vmw_resource *res;
2493 /*
2494 * This is based on the fact that all affected define commands have
2495 * the same initial command body layout.
2496 */
2497 struct {
2498 SVGA3dCmdHeader header;
2499 uint32 defined_id;
2500 } *cmd;
2501 enum vmw_so_type so_type;
2502 int ret;
2503
2504 if (unlikely(ctx_node == NULL)) {
2505 DRM_ERROR("DX Context not set.\n");
2506 return -EINVAL;
2507 }
2508
2509 so_type = vmw_so_cmd_to_type(header->id);
2510 res = vmw_context_cotable(ctx_node->res, vmw_so_cotables[so_type]);
2511 cmd = container_of(header, typeof(*cmd), header);
2512 ret = vmw_cotable_notify(res, cmd->defined_id);
2513 vmw_resource_unreference(&res);
2514
2515 return ret;
2516}
2517
2518/**
2519 * vmw_cmd_dx_check_subresource - Validate an
2520 * SVGA_3D_CMD_DX_[X]_SUBRESOURCE command
2521 *
2522 * @dev_priv: Pointer to a device private struct.
2523 * @sw_context: The software context being used for this batch.
2524 * @header: Pointer to the command header in the command stream.
2525 */
2526static int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv,
2527 struct vmw_sw_context *sw_context,
2528 SVGA3dCmdHeader *header)
2529{
2530 struct {
2531 SVGA3dCmdHeader header;
2532 union {
2533 SVGA3dCmdDXReadbackSubResource r_body;
2534 SVGA3dCmdDXInvalidateSubResource i_body;
2535 SVGA3dCmdDXUpdateSubResource u_body;
2536 SVGA3dSurfaceId sid;
2537 };
2538 } *cmd;
2539
2540 BUILD_BUG_ON(offsetof(typeof(*cmd), r_body.sid) !=
2541 offsetof(typeof(*cmd), sid));
2542 BUILD_BUG_ON(offsetof(typeof(*cmd), i_body.sid) !=
2543 offsetof(typeof(*cmd), sid));
2544 BUILD_BUG_ON(offsetof(typeof(*cmd), u_body.sid) !=
2545 offsetof(typeof(*cmd), sid));
2546
2547 cmd = container_of(header, typeof(*cmd), header);
2548
2549 return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
2550 user_surface_converter,
2551 &cmd->sid, NULL);
2552}
2553
2554static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,
2555 struct vmw_sw_context *sw_context,
2556 SVGA3dCmdHeader *header)
2557{
2558 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2559
2560 if (unlikely(ctx_node == NULL)) {
2561 DRM_ERROR("DX Context not set.\n");
2562 return -EINVAL;
2563 }
2564
2565 return 0;
2566}
2567
2568/**
2569 * vmw_cmd_dx_view_remove - validate a view remove command and
2570 * schedule the view resource for removal.
2571 *
2572 * @dev_priv: Pointer to a device private struct.
2573 * @sw_context: The software context being used for this batch.
2574 * @header: Pointer to the command header in the command stream.
2575 *
2576 * Check that the view exists, and if it was not created using this
2577 * command batch, make sure it's validated (present in the device) so that
2578 * the remove command will not confuse the device.
2579 */
2580static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
2581 struct vmw_sw_context *sw_context,
2582 SVGA3dCmdHeader *header)
2583{
2584 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2585 struct {
2586 SVGA3dCmdHeader header;
2587 union vmw_view_destroy body;
2588 } *cmd = container_of(header, typeof(*cmd), header);
2589 enum vmw_view_type view_type = vmw_view_cmd_to_type(header->id);
2590 struct vmw_resource *view;
2591 int ret;
2592
2593 if (!ctx_node) {
2594 DRM_ERROR("DX Context not set.\n");
2595 return -EINVAL;
2596 }
2597
2598 ret = vmw_view_remove(sw_context->man,
2599 cmd->body.view_id, view_type,
2600 &sw_context->staged_cmd_res,
2601 &view);
2602 if (ret || !view)
2603 return ret;
2604
2605 /*
2606 * Add view to the validate list iff it was not created using this
2607 * command batch.
2608 */
2609 return vmw_view_res_val_add(sw_context, view);
2610}
2611
2612/**
2613 * vmw_cmd_dx_define_shader - Validate an SVGA_3D_CMD_DX_DEFINE_SHADER
2614 * command
2615 *
2616 * @dev_priv: Pointer to a device private struct.
2617 * @sw_context: The software context being used for this batch.
2618 * @header: Pointer to the command header in the command stream.
2619 */
2620static int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv,
2621 struct vmw_sw_context *sw_context,
2622 SVGA3dCmdHeader *header)
2623{
2624 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2625 struct vmw_resource *res;
2626 struct {
2627 SVGA3dCmdHeader header;
2628 SVGA3dCmdDXDefineShader body;
2629 } *cmd = container_of(header, typeof(*cmd), header);
2630 int ret;
2631
2632 if (!ctx_node) {
2633 DRM_ERROR("DX Context not set.\n");
2634 return -EINVAL;
2635 }
2636
2637 res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXSHADER);
2638 ret = vmw_cotable_notify(res, cmd->body.shaderId);
2639 vmw_resource_unreference(&res);
2640 if (ret)
2641 return ret;
2642
2643 return vmw_dx_shader_add(sw_context->man, ctx_node->res,
2644 cmd->body.shaderId, cmd->body.type,
2645 &sw_context->staged_cmd_res);
2646}
2647
2648/**
2649 * vmw_cmd_dx_destroy_shader - Validate an SVGA_3D_CMD_DX_DESTROY_SHADER
2650 * command
2651 *
2652 * @dev_priv: Pointer to a device private struct.
2653 * @sw_context: The software context being used for this batch.
2654 * @header: Pointer to the command header in the command stream.
2655 */
2656static int vmw_cmd_dx_destroy_shader(struct vmw_private *dev_priv,
2657 struct vmw_sw_context *sw_context,
2658 SVGA3dCmdHeader *header)
2659{
2660 struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
2661 struct {
2662 SVGA3dCmdHeader header;
2663 SVGA3dCmdDXDestroyShader body;
2664 } *cmd = container_of(header, typeof(*cmd), header);
2665 int ret;
2666
2667 if (!ctx_node) {
2668 DRM_ERROR("DX Context not set.\n");
2669 return -EINVAL;
2670 }
2671
2672 ret = vmw_shader_remove(sw_context->man, cmd->body.shaderId, 0,
2673 &sw_context->staged_cmd_res);
2674 if (ret)
2675 DRM_ERROR("Could not find shader to remove.\n");
2676
2677 return ret;
2678}
2679
2680/**
2681 * vmw_cmd_dx_bind_shader - Validate an SVGA_3D_CMD_DX_BIND_SHADER
2682 * command
2683 *
2684 * @dev_priv: Pointer to a device private struct.
2685 * @sw_context: The software context being used for this batch.
2686 * @header: Pointer to the command header in the command stream.
2687 */
2688static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
2689 struct vmw_sw_context *sw_context,
2690 SVGA3dCmdHeader *header)
2691{
2692 struct vmw_resource_val_node *ctx_node;
2693 struct vmw_resource_val_node *res_node;
2694 struct vmw_resource *res;
2695 struct {
2696 SVGA3dCmdHeader header;
2697 SVGA3dCmdDXBindShader body;
2698 } *cmd = container_of(header, typeof(*cmd), header);
2699 int ret;
2700
2701 if (cmd->body.cid != SVGA3D_INVALID_ID) {
2702 ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
2703 user_context_converter,
2704 &cmd->body.cid, &ctx_node);
2705 if (ret)
2706 return ret;
2707 } else {
2708 ctx_node = sw_context->dx_ctx_node;
2709 if (!ctx_node) {
2710 DRM_ERROR("DX Context not set.\n");
2711 return -EINVAL;
2712 }
2713 }
2714
2715 res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res),
2716 cmd->body.shid, 0);
2717 if (IS_ERR(res)) {
2718 DRM_ERROR("Could not find shader to bind.\n");
2719 return PTR_ERR(res);
2720 }
2721
2722 ret = vmw_resource_val_add(sw_context, res, &res_node);
2723 if (ret) {
2724 DRM_ERROR("Error creating resource validation node.\n");
2725 goto out_unref;
2726 }
2727
2728
2729 ret = vmw_cmd_res_switch_backup(dev_priv, sw_context, res_node,
2730 &cmd->body.mobid,
2731 cmd->body.offsetInBytes);
2732out_unref:
2733 vmw_resource_unreference(&res);
2734
2735 return ret;
2736}
2737
2738static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
2739 struct vmw_sw_context *sw_context,
2740 void *buf, uint32_t *size)
2741{
2742 uint32_t size_remaining = *size;
2743 uint32_t cmd_id;
2744
2745 cmd_id = ((uint32_t *)buf)[0];
2746 switch (cmd_id) {
2747 case SVGA_CMD_UPDATE:
2748 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate);
2749 break;
2750 case SVGA_CMD_DEFINE_GMRFB:
2751 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdDefineGMRFB);
2752 break;
2753 case SVGA_CMD_BLIT_GMRFB_TO_SCREEN:
2754 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
2755 break;
2756 case SVGA_CMD_BLIT_SCREEN_TO_GMRFB:
2757 *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdBlitGMRFBToScreen);
2758 break;
2759 default:
2760 DRM_ERROR("Unsupported SVGA command: %u.\n", cmd_id);
2761 return -EINVAL;
2762 }
2763
2764 if (*size > size_remaining) {
2765 DRM_ERROR("Invalid SVGA command (size mismatch):"
2766 " %u.\n", cmd_id);
2767 return -EINVAL;
2768 }
2769
2770 if (unlikely(!sw_context->kernel)) {
2771 DRM_ERROR("Kernel only SVGA command: %u.\n", cmd_id);
2772 return -EPERM;
2773 }
2774
2775 if (cmd_id == SVGA_CMD_DEFINE_GMRFB)
2776 return vmw_cmd_check_define_gmrfb(dev_priv, sw_context, buf);
2777
2778 return 0;
2779}
2780
2781static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
2782 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
2783 false, false, false),
2784 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
2785 false, false, false),
2786 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check,
2787 true, false, false),
2788 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check,
2789 true, false, false),
2790 VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma,
2791 true, false, false),
2792 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid,
2793 false, false, false),
2794 VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid,
2795 false, false, false),
2796 VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check,
2797 true, false, false),
2798 VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check,
2799 true, false, false),
2800 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check,
2801 true, false, false),
2802 VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
2803 &vmw_cmd_set_render_target_check, true, false, false),
2804 VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state,
2805 true, false, false),
2806 VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check,
2807 true, false, false),
2808 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check,
2809 true, false, false),
1918 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check,2810 VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check,
1919 true, false, false),2811 true, false, false),
1920 VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check,2812 VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check,
@@ -2050,7 +2942,136 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { · 129 unmodified lines
2050 VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,2942 VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
2051 false, false, true),2943 false, false, true),
2052 VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check,2944 VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check,
2053 true, false, true)2945 true, false, true),
2946 VMW_CMD_DEF(SVGA_3D_CMD_GB_SCREEN_DMA, &vmw_cmd_invalid,
2947 false, false, true),
2948 VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH, &vmw_cmd_invalid,
2949 false, false, true),
2950 VMW_CMD_DEF(SVGA_3D_CMD_GB_MOB_FENCE, &vmw_cmd_invalid,
2951 false, false, true),
2952 VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE_V2, &vmw_cmd_invalid,
2953 false, false, true),
2954
2955 /*
2956 * DX commands
2957 */
2958 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_CONTEXT, &vmw_cmd_invalid,
2959 false, false, true),
2960 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_CONTEXT, &vmw_cmd_invalid,
2961 false, false, true),
2962 VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_CONTEXT, &vmw_cmd_invalid,
2963 false, false, true),
2964 VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_CONTEXT, &vmw_cmd_invalid,
2965 false, false, true),
2966 VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_CONTEXT, &vmw_cmd_invalid,
2967 false, false, true),
2968 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER,
2969 &vmw_cmd_dx_set_single_constant_buffer, true, false, true),
2970 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER_RESOURCES,
2971 &vmw_cmd_dx_set_shader_res, true, false, true),
2972 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER, &vmw_cmd_dx_set_shader,
2973 true, false, true),
2974 VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INSTANCED, &vmw_cmd_invalid,
2975 true, false, true),
2976 VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED, &vmw_cmd_invalid,
2977 true, false, true),
2978 VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_AUTO, &vmw_cmd_invalid,
2979 true, false, true),
2980 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS,
2981 &vmw_cmd_dx_set_vertex_buffers, true, false, true),
2982 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INDEX_BUFFER,
2983 &vmw_cmd_dx_set_index_buffer, true, false, true),
2984 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RENDERTARGETS,
2985 &vmw_cmd_dx_set_rendertargets, true, false, true),
2986 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_BLEND_STATE, &vmw_cmd_dx_cid_check,
2987 true, false, true),
2988 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RASTERIZER_STATE, &vmw_cmd_dx_cid_check,
2989 true, false, true),
2990 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_DEPTHSTENCIL_STATE,
2991 &vmw_cmd_dx_cid_check,
2992 true, false, true),
2993 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_QUERY, &vmw_cmd_invalid,
2994 true, false, true),
2995 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_invalid,
2996 true, false, true),
2997 VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_QUERY, &vmw_cmd_invalid,
2998 true, false, true),
2999 VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_invalid,
3000 true, false, true),
3001 VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_invalid,
3002 true, false, true),
3003 VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_QUERY, &vmw_cmd_invalid,
3004 true, false, true),
3005 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_invalid,
3006 true, false, true),
3007 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VIEWPORTS, &vmw_cmd_dx_cid_check,
3008 true, false, true),
3009 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SCISSORRECTS, &vmw_cmd_dx_cid_check,
3010 true, false, true),
3011 VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW,
3012 &vmw_cmd_dx_clear_rendertarget_view, true, false, true),
3013 VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW,
3014 &vmw_cmd_dx_clear_depthstencil_view, true, false, true),
3015 VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION, &vmw_cmd_invalid,
3016 true, false, true),
3017 VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid,
3018 true, false, true),
3019 VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_invalid,
3020 true, false, true),
3021 VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE,
3022 &vmw_cmd_dx_check_subresource, true, false, true),
3023 VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_SUBRESOURCE,
3024 &vmw_cmd_dx_check_subresource, true, false, true),
3025 VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE,
3026 &vmw_cmd_dx_check_subresource, true, false, true),
3027 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW,
3028 &vmw_cmd_dx_view_define, true, false, true),
3029 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW,
3030 &vmw_cmd_dx_view_remove, true, false, true),
3031 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW,
3032 &vmw_cmd_dx_view_define, true, false, true),
3033 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW,
3034 &vmw_cmd_dx_view_remove, true, false, true),
3035 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW,
3036 &vmw_cmd_dx_view_define, true, false, true),
3037 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW,
3038 &vmw_cmd_dx_view_remove, true, false, true),
3039 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT,
3040 &vmw_cmd_dx_so_define, true, false, true),
3041 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT,
3042 &vmw_cmd_dx_cid_check, true, false, true),
3043 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_BLEND_STATE,
3044 &vmw_cmd_dx_so_define, true, false, true),
3045 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_BLEND_STATE,
3046 &vmw_cmd_dx_cid_check, true, false, true),
3047 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE,
3048 &vmw_cmd_dx_so_define, true, false, true),
3049 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE,
3050 &vmw_cmd_dx_cid_check, true, false, true),
3051 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE,
3052 &vmw_cmd_dx_so_define, true, false, true),
3053 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE,
3054 &vmw_cmd_dx_cid_check, true, false, true),
3055 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE,
3056 &vmw_cmd_dx_so_define, true, false, true),
3057 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE,
3058 &vmw_cmd_dx_cid_check, true, false, true),
3059 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADER,
3060 &vmw_cmd_dx_define_shader, true, false, true),
3061 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADER,
3062 &vmw_cmd_dx_destroy_shader, true, false, true),
3063 VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_SHADER,
3064 &vmw_cmd_dx_bind_shader, true, false, true),
3065 VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT,
3066 &vmw_cmd_dx_so_define, true, false, true),
3067 VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT,
3068 &vmw_cmd_dx_cid_check, true, false, true),
3069 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_STREAMOUTPUT, &vmw_cmd_invalid,
3070 true, false, true),
3071 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INPUT_LAYOUT,
3072 &vmw_cmd_dx_cid_check, true, false, true),
3073 VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_TOPOLOGY,
3074 &vmw_cmd_dx_cid_check, true, false, true),
2054};3075};
2055 3076
2056static int vmw_cmd_check(struct vmw_private *dev_priv,3077static int vmw_cmd_check(struct vmw_private *dev_priv,
@@ -2183,7 +3204,8 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context) · 126 unmodified lines
2183 *3204 *
2184 * @list: The resource list.3205 * @list: The resource list.
2185 */3206 */
2186static void vmw_resource_list_unreference(struct list_head *list)3207static void vmw_resource_list_unreference(struct vmw_sw_context *sw_context,
3208 struct list_head *list)
2187{3209{
2188 struct vmw_resource_val_node *val, *val_next;3210 struct vmw_resource_val_node *val, *val_next;
2189 3211
@@ -2194,8 +3216,15 @@ static void vmw_resource_list_unreference(struct list_head *list) · 4 unmodified lines
2194 list_for_each_entry_safe(val, val_next, list, head) {3216 list_for_each_entry_safe(val, val_next, list, head) {
2195 list_del_init(&val->head);3217 list_del_init(&val->head);
2196 vmw_resource_unreference(&val->res);3218 vmw_resource_unreference(&val->res);
2197 if (unlikely(val->staged_bindings))3219
2198 kfree(val->staged_bindings);3220 if (val->staged_bindings) {
3221 if (val->staged_bindings != sw_context->staged_bindings)
3222 vmw_binding_state_free(val->staged_bindings);
3223 else
3224 sw_context->staged_bindings_inuse = false;
3225 val->staged_bindings = NULL;
3226 }
3227
2199 kfree(val);3228 kfree(val);
2200 }3229 }
2201}3230}
@@ -2431,8 +3460,13 @@ static int vmw_execbuf_submit_fifo(struct vmw_private *dev_priv, · 229 unmodified lines
2431 u32 command_size,3460 u32 command_size,
2432 struct vmw_sw_context *sw_context)3461 struct vmw_sw_context *sw_context)
2433{3462{
2434 void *cmd = vmw_fifo_reserve(dev_priv, command_size);3463 void *cmd;
2435 3464
3465 if (sw_context->dx_ctx_node)
3466 cmd = vmw_fifo_reserve_dx(dev_priv, command_size,
3467 sw_context->dx_ctx_node->res->id);
3468 else
3469 cmd = vmw_fifo_reserve(dev_priv, command_size);
2436 if (!cmd) {3470 if (!cmd) {
2437 DRM_ERROR("Failed reserving fifo space for commands.\n");3471 DRM_ERROR("Failed reserving fifo space for commands.\n");
2438 return -ENOMEM;3472 return -ENOMEM;
@@ -2464,8 +3498,10 @@ static int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv, · 25 unmodified lines
2464 u32 command_size,3498 u32 command_size,
2465 struct vmw_sw_context *sw_context)3499 struct vmw_sw_context *sw_context)
2466{3500{
3501 u32 id = ((sw_context->dx_ctx_node) ? sw_context->dx_ctx_node->res->id :
3502 SVGA3D_INVALID_ID);
2467 void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size,3503 void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size,
2468 SVGA3D_INVALID_ID, false, header);3504 id, false, header);
2469 3505
2470 vmw_apply_relocations(sw_context);3506 vmw_apply_relocations(sw_context);
2471 vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);3507 vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
@@ -2535,12 +3571,44 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, · 63 unmodified lines
2535 return kernel_commands;3571 return kernel_commands;
2536}3572}
2537 3573
3574static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
3575 struct vmw_sw_context *sw_context,
3576 uint32_t handle)
3577{
3578 struct vmw_resource_val_node *ctx_node;
3579 struct vmw_resource *res;
3580 int ret;
3581
3582 if (handle == SVGA3D_INVALID_ID)
3583 return 0;
3584
3585 ret = vmw_user_resource_lookup_handle(dev_priv, sw_context->fp->tfile,
3586 handle, user_context_converter,
3587 &res);
3588 if (unlikely(ret != 0)) {
3589 DRM_ERROR("Could not find or user DX context 0x%08x.\n",
3590 (unsigned) handle);
3591 return ret;
3592 }
3593
3594 ret = vmw_resource_val_add(sw_context, res, &ctx_node);
3595 if (unlikely(ret != 0))
3596 goto out_err;
3597
3598 sw_context->dx_ctx_node = ctx_node;
3599 sw_context->man = vmw_context_res_man(res);
3600out_err:
3601 vmw_resource_unreference(&res);
3602 return ret;
3603}
3604
2538int vmw_execbuf_process(struct drm_file *file_priv,3605int vmw_execbuf_process(struct drm_file *file_priv,
2539 struct vmw_private *dev_priv,3606 struct vmw_private *dev_priv,
2540 void __user *user_commands,3607 void __user *user_commands,
2541 void *kernel_commands,3608 void *kernel_commands,
2542 uint32_t command_size,3609 uint32_t command_size,
2543 uint64_t throttle_us,3610 uint64_t throttle_us,
3611 uint32_t dx_context_handle,
2544 struct drm_vmw_fence_rep __user *user_fence_rep,3612 struct drm_vmw_fence_rep __user *user_fence_rep,
2545 struct vmw_fence_obj **out_fence)3613 struct vmw_fence_obj **out_fence)
2546{3614{
@@ -2596,12 +3664,17 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 49 unmodified lines
2596 sw_context->cur_reloc = 0;3664 sw_context->cur_reloc = 0;
2597 sw_context->cur_val_buf = 0;3665 sw_context->cur_val_buf = 0;
2598 INIT_LIST_HEAD(&sw_context->resource_list);3666 INIT_LIST_HEAD(&sw_context->resource_list);
3667 INIT_LIST_HEAD(&sw_context->ctx_resource_list);
2599 sw_context->cur_query_bo = dev_priv->pinned_bo;3668 sw_context->cur_query_bo = dev_priv->pinned_bo;
2600 sw_context->last_query_ctx = NULL;3669 sw_context->last_query_ctx = NULL;
2601 sw_context->needs_post_query_barrier = false;3670 sw_context->needs_post_query_barrier = false;
3671 sw_context->dx_ctx_node = NULL;
2602 memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));3672 memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));
2603 INIT_LIST_HEAD(&sw_context->validate_nodes);3673 INIT_LIST_HEAD(&sw_context->validate_nodes);
2604 INIT_LIST_HEAD(&sw_context->res_relocations);3674 INIT_LIST_HEAD(&sw_context->res_relocations);
3675 if (sw_context->staged_bindings)
3676 vmw_binding_state_reset(sw_context->staged_bindings);
3677
2605 if (!sw_context->res_ht_initialized) {3678 if (!sw_context->res_ht_initialized) {
2606 ret = drm_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);3679 ret = drm_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
2607 if (unlikely(ret != 0))3680 if (unlikely(ret != 0))
@@ -2610,11 +3683,20 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 2 unmodified lines
2610 }3683 }
2611 INIT_LIST_HEAD(&sw_context->staged_cmd_res);3684 INIT_LIST_HEAD(&sw_context->staged_cmd_res);
2612 INIT_LIST_HEAD(&resource_list);3685 INIT_LIST_HEAD(&resource_list);
3686 ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
3687 if (unlikely(ret != 0)) {
3688 list_splice_init(&sw_context->ctx_resource_list,
3689 &sw_context->resource_list);
3690 goto out_err_nores;
3691 }
3692
2613 ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,3693 ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
2614 command_size);3694 command_size);
2615 if (unlikely(ret != 0))3695 if (unlikely(ret != 0))
2616 goto out_err_nores;3696 goto out_err_nores;
2617 3697
3698 list_splice_init(&sw_context->ctx_resource_list,
3699 &sw_context->resource_list);
2618 ret = vmw_resources_reserve(sw_context);3700 ret = vmw_resources_reserve(sw_context);
2619 if (unlikely(ret != 0))3701 if (unlikely(ret != 0))
2620 goto out_err_nores;3702 goto out_err_nores;
@@ -2622,7 +3704,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 1 unmodified line
2622 ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,3704 ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,
2623 true, NULL);3705 true, NULL);
2624 if (unlikely(ret != 0))3706 if (unlikely(ret != 0))
2625 goto out_err;3707 goto out_err_nores;
2626 3708
2627 ret = vmw_validate_buffers(dev_priv, sw_context);3709 ret = vmw_validate_buffers(dev_priv, sw_context);
2628 if (unlikely(ret != 0))3710 if (unlikely(ret != 0))
@@ -2652,8 +3734,9 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 23 unmodified lines
2652 sw_context);3734 sw_context);
2653 header = NULL;3735 header = NULL;
2654 }3736 }
3737 mutex_unlock(&dev_priv->binding_mutex);
2655 if (ret)3738 if (ret)
2656 goto out_unlock_binding;3739 goto out_err;
2657 3740
2658 vmw_query_bo_switch_commit(dev_priv, sw_context);3741 vmw_query_bo_switch_commit(dev_priv, sw_context);
2659 ret = vmw_execbuf_fence_commands(file_priv, dev_priv,3742 ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
@@ -2668,8 +3751,8 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 8 unmodified lines
2668 if (ret != 0)3751 if (ret != 0)
2669 DRM_ERROR("Fence submission error. Syncing.\n");3752 DRM_ERROR("Fence submission error. Syncing.\n");
2670 3753
2671 vmw_resource_list_unreserve(&sw_context->resource_list, false);3754 vmw_resource_list_unreserve(sw_context, &sw_context->resource_list,
2672 mutex_unlock(&dev_priv->binding_mutex);3755 false);
2673 3756
2674 ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,3757 ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
2675 (void *) fence);3758 (void *) fence);
@@ -2698,7 +3781,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, · 22 unmodified lines
2698 * Unreference resources outside of the cmdbuf_mutex to3781 * Unreference resources outside of the cmdbuf_mutex to
2699 * avoid deadlocks in resource destruction paths.3782 * avoid deadlocks in resource destruction paths.
2700 */3783 */
2701 vmw_resource_list_unreference(&resource_list);3784 vmw_resource_list_unreference(sw_context, &resource_list);
2702 3785
2703 return 0;3786 return 0;
2704 3787
@@ -2707,7 +3790,8 @@ out_unlock_binding: · 2 unmodified lines
2707out_err:3790out_err:
2708 ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes);3791 ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes);
2709out_err_nores:3792out_err_nores:
2710 vmw_resource_list_unreserve(&sw_context->resource_list, true);3793 vmw_resource_list_unreserve(sw_context, &sw_context->resource_list,
3794 true);
2711 vmw_resource_relocations_free(&sw_context->res_relocations);3795 vmw_resource_relocations_free(&sw_context->res_relocations);
2712 vmw_free_relocations(sw_context);3796 vmw_free_relocations(sw_context);
2713 vmw_clear_validations(sw_context);3797 vmw_clear_validations(sw_context);
@@ -2725,7 +3809,7 @@ out_unlock: · 11 unmodified lines
2725 * Unreference resources outside of the cmdbuf_mutex to3809 * Unreference resources outside of the cmdbuf_mutex to
2726 * avoid deadlocks in resource destruction paths.3810 * avoid deadlocks in resource destruction paths.
2727 */3811 */
2728 vmw_resource_list_unreference(&resource_list);3812 vmw_resource_list_unreference(sw_context, &resource_list);
2729 if (unlikely(error_resource != NULL))3813 if (unlikely(error_resource != NULL))
2730 vmw_resource_unreference(&error_resource);3814 vmw_resource_unreference(&error_resource);
2731out_free_header:3815out_free_header:
@@ -2877,36 +3961,68 @@ void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv) · 145 unmodified lines
2877 mutex_unlock(&dev_priv->cmdbuf_mutex);3961 mutex_unlock(&dev_priv->cmdbuf_mutex);
2878}3962}
2879 3963
2880 3964int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data,
2881int vmw_execbuf_ioctl(struct drm_device *dev, void *data,3965 struct drm_file *file_priv, size_t size)
2882 struct drm_file *file_priv)
2883{3966{
2884 struct vmw_private *dev_priv = vmw_priv(dev);3967 struct vmw_private *dev_priv = vmw_priv(dev);
2885 struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;3968 struct drm_vmw_execbuf_arg arg;
2886 int ret;3969 int ret;
3970 static const size_t copy_offset[] = {
3971 offsetof(struct drm_vmw_execbuf_arg, context_handle),
3972 sizeof(struct drm_vmw_execbuf_arg)};
3973
3974 if (unlikely(size < copy_offset[0])) {
3975 DRM_ERROR("Invalid command size, ioctl %d\n",
3976 DRM_VMW_EXECBUF);
3977 return -EINVAL;
3978 }
3979
3980 if (copy_from_user(&arg, (void __user *) data, copy_offset[0]) != 0)
3981 return -EFAULT;
2887 3982
2888 /*3983 /*
2889 * This will allow us to extend the ioctl argument while3984 * Extend the ioctl argument while
2890 * maintaining backwards compatibility:3985 * maintaining backwards compatibility:
2891 * We take different code paths depending on the value of3986 * We take different code paths depending on the value of
2892 * arg->version.3987 * arg.version.
2893 */3988 */
2894 3989
2895 if (unlikely(arg->version != DRM_VMW_EXECBUF_VERSION)) {3990 if (unlikely(arg.version > DRM_VMW_EXECBUF_VERSION ||
3991 arg.version == 0)) {
2896 DRM_ERROR("Incorrect execbuf version.\n");3992 DRM_ERROR("Incorrect execbuf version.\n");
2897 DRM_ERROR("You're running outdated experimental "
2898 "vmwgfx user-space drivers.");
2899 return -EINVAL;3993 return -EINVAL;
2900 }3994 }
2901 3995
3996 if (arg.version > 1 &&
3997 copy_from_user(&arg.context_handle,
3998 (void __user *) (data + copy_offset[0]),
3999 copy_offset[arg.version - 1] -
4000 copy_offset[0]) != 0)
4001 return -EFAULT;
4002
4003 switch (arg.version) {
4004 case 1:
4005 arg.context_handle = (uint32_t) -1;
4006 break;
4007 case 2:
4008 if (arg.pad64 != 0) {
4009 DRM_ERROR("Unused IOCTL data not set to zero.\n");
4010 return -EINVAL;
4011 }
4012 break;
4013 default:
4014 break;
4015 }
4016
2902 ret = ttm_read_lock(&dev_priv->reservation_sem, true);4017 ret = ttm_read_lock(&dev_priv->reservation_sem, true);
2903 if (unlikely(ret != 0))4018 if (unlikely(ret != 0))
2904 return ret;4019 return ret;
2905 4020
2906 ret = vmw_execbuf_process(file_priv, dev_priv,4021 ret = vmw_execbuf_process(file_priv, dev_priv,
2907 (void __user *)(unsigned long)arg->commands,4022 (void __user *)(unsigned long)arg.commands,
2908 NULL, arg->command_size, arg->throttle_us,4023 NULL, arg.command_size, arg.throttle_us,
2909 (void __user *)(unsigned long)arg->fence_rep,4024 arg.context_handle,
4025 (void __user *)(unsigned long)arg.fence_rep,
2910 NULL);4026 NULL);
2911 ttm_read_unlock(&dev_priv->reservation_sem);4027 ttm_read_unlock(&dev_priv->reservation_sem);
2912 if (unlikely(ret != 0))4028 if (unlikely(ret != 0))
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c+24−4
@@ -29,6 +29,11 @@ · 28 unmodified lines
29#include <drm/drmP.h>29#include <drm/drmP.h>
30#include <drm/ttm/ttm_placement.h>30#include <drm/ttm/ttm_placement.h>
31 31
32struct vmw_temp_set_context {
33 SVGA3dCmdHeader header;
34 SVGA3dCmdDXTempSetContext body;
35};
36
32bool vmw_fifo_have_3d(struct vmw_private *dev_priv)37bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
33{38{
34 u32 __iomem *fifo_mem = dev_priv->mmio_virt;39 u32 __iomem *fifo_mem = dev_priv->mmio_virt;
@@ -99,6 +104,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) · 64 unmodified lines
99 uint32_t max;104 uint32_t max;
100 uint32_t min;105 uint32_t min;
101 106
107 fifo->dx = false;
102 fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE;108 fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE;
103 fifo->static_buffer = vmalloc(fifo->static_buffer_size);109 fifo->static_buffer = vmalloc(fifo->static_buffer_size);
104 if (unlikely(fifo->static_buffer == NULL))110 if (unlikely(fifo->static_buffer == NULL))
@@ -396,15 +402,20 @@ out_err: · 291 unmodified lines
396 return NULL;402 return NULL;
397}403}
398 404
399void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)405void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes,
406 int ctx_id)
400{407{
401 void *ret;408 void *ret;
402 409
403 if (dev_priv->cman)410 if (dev_priv->cman)
404 ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes,411 ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes,
405 SVGA3D_INVALID_ID, false, NULL);412 ctx_id, false, NULL);
406 else413 else if (ctx_id == SVGA3D_INVALID_ID)
407 ret = vmw_local_fifo_reserve(dev_priv, bytes);414 ret = vmw_local_fifo_reserve(dev_priv, bytes);
415 else {
416 WARN_ON("Command buffer has not been allocated.\n");
417 ret = NULL;
418 }
408 if (IS_ERR_OR_NULL(ret)) {419 if (IS_ERR_OR_NULL(ret)) {
409 DRM_ERROR("Fifo reserve failure of %u bytes.\n",420 DRM_ERROR("Fifo reserve failure of %u bytes.\n",
410 (unsigned) bytes);421 (unsigned) bytes);
@@ -466,6 +477,10 @@ static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) · 55 unmodified lines
466 uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);477 uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
467 bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;478 bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
468 479
480 if (fifo_state->dx)
481 bytes += sizeof(struct vmw_temp_set_context);
482
483 fifo_state->dx = false;
469 BUG_ON((bytes & 3) != 0);484 BUG_ON((bytes & 3) != 0);
470 BUG_ON(bytes > fifo_state->reserved_size);485 BUG_ON(bytes > fifo_state->reserved_size);
471 486
@@ -518,7 +533,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) · 46 unmodified lines
518 * @dev_priv: Pointer to device private structure.533 * @dev_priv: Pointer to device private structure.
519 * @bytes: Number of bytes to commit.534 * @bytes: Number of bytes to commit.
520 */535 */
521static void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes)536void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes)
522{537{
523 if (dev_priv->cman)538 if (dev_priv->cman)
524 vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true);539 vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true);
@@ -706,3 +721,8 @@ int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv, · 181 unmodified lines
706 721
707 return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid);722 return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid);
708}723}
724
725void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
726{
727 return vmw_fifo_reserve_dx(dev_priv, bytes, SVGA3D_INVALID_ID);
728}
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c+5−2
@@ -110,6 +110,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, · 109 unmodified lines
110 param->value =110 param->value =
111 (dev_priv->active_display_unit == vmw_du_screen_target);111 (dev_priv->active_display_unit == vmw_du_screen_target);
112 break;112 break;
113 case DRM_VMW_PARAM_DX:
114 param->value = dev_priv->has_dx;
115 break;
113 default:116 default:
114 DRM_ERROR("Illegal vmwgfx get param request: %d\n",117 DRM_ERROR("Illegal vmwgfx get param request: %d\n",
115 param->param);118 param->param);
@@ -193,8 +196,8 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, · 77 unmodified lines
193 uint32_t *bounce32 = (uint32_t *) bounce;196 uint32_t *bounce32 = (uint32_t *) bounce;
194 197
195 num = size / sizeof(uint32_t);198 num = size / sizeof(uint32_t);
196 if (num > SVGA3D_DEVCAP_MAX)199 if (num > SVGA3D_DEVCAP_DX)
197 num = SVGA3D_DEVCAP_MAX;200 num = SVGA3D_DEVCAP_DX;
198 201
199 spin_lock(&dev_priv->cap_lock);202 spin_lock(&dev_priv->cap_lock);
200 for (i = 0; i < num; ++i) {203 for (i = 0; i < num; ++i) {
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c+10−5
@@ -528,7 +528,11 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, · 527 unmodified lines
528 return -EINVAL;528 return -EINVAL;
529 }529 }
530 530
531 if (unlikely(format != surface->format)) {531 /*
532 * For DX, surface format validation is done when surface->scanout
533 * is set.
534 */
535 if (!dev_priv->has_dx && format != surface->format) {
532 DRM_ERROR("Invalid surface format for requested mode.\n");536 DRM_ERROR("Invalid surface format for requested mode.\n");
533 return -EINVAL;537 return -EINVAL;
534 }538 }
@@ -754,6 +758,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, · 219 unmodified lines
754 true, /* can be a scanout buffer */758 true, /* can be a scanout buffer */
755 1, /* num of mip levels */759 1, /* num of mip levels */
756 0,760 0,
761 0,
757 content_base_size,762 content_base_size,
758 srf_out);763 srf_out);
759 if (ret) {764 if (ret) {
@@ -769,7 +774,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, · 9 unmodified lines
769 vmw_dmabuf_unreference(&res->backup);774 vmw_dmabuf_unreference(&res->backup);
770 res->backup = vmw_dmabuf_reference(dmabuf_mob);775 res->backup = vmw_dmabuf_reference(dmabuf_mob);
771 res->backup_offset = 0;776 res->backup_offset = 0;
772 vmw_resource_unreserve(res, NULL, 0);777 vmw_resource_unreserve(res, false, NULL, 0);
773 mutex_unlock(&res->dev_priv->cmdbuf_mutex);778 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
774 779
775 return 0;780 return 0;
@@ -1869,7 +1874,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, · 1093 unmodified lines
1869void vmw_kms_helper_resource_revert(struct vmw_resource *res)1874void vmw_kms_helper_resource_revert(struct vmw_resource *res)
1870{1875{
1871 vmw_kms_helper_buffer_revert(res->backup);1876 vmw_kms_helper_buffer_revert(res->backup);
1872 vmw_resource_unreserve(res, NULL, 0);1877 vmw_resource_unreserve(res, false, NULL, 0);
1873 mutex_unlock(&res->dev_priv->cmdbuf_mutex);1878 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
1874}1879}
1875 1880
@@ -1916,7 +1921,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, · 40 unmodified lines
1916out_revert:1921out_revert:
1917 vmw_kms_helper_buffer_revert(res->backup);1922 vmw_kms_helper_buffer_revert(res->backup);
1918out_unreserve:1923out_unreserve:
1919 vmw_resource_unreserve(res, NULL, 0);1924 vmw_resource_unreserve(res, false, NULL, 0);
1920out_unlock:1925out_unlock:
1921 mutex_unlock(&res->dev_priv->cmdbuf_mutex);1926 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
1922 return ret;1927 return ret;
@@ -1937,7 +1942,7 @@ void vmw_kms_helper_resource_finish(struct vmw_resource *res, · 14 unmodified lines
1937 vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup,1942 vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup,
1938 out_fence, NULL);1943 out_fence, NULL);
1939 1944
1940 vmw_resource_unreserve(res, NULL, 0);1945 vmw_resource_unreserve(res, false, NULL, 0);
1941 mutex_unlock(&res->dev_priv->cmdbuf_mutex);1946 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
1942}1947}
1943 1948
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c+105−64
@@ -67,9 +67,23 @@ struct vmw_mob { · 66 unmodified lines
67 * @size: Size of the table (page-aligned).67 * @size: Size of the table (page-aligned).
68 * @page_table: Pointer to a struct vmw_mob holding the page table.68 * @page_table: Pointer to a struct vmw_mob holding the page table.
69 */69 */
70struct vmw_otable {70static const struct vmw_otable pre_dx_tables[] = {
71 unsigned long size;71 {VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE, NULL, true},
72 struct vmw_mob *page_table;72 {VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE, NULL, true},
73 {VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE, NULL, true},
74 {VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE, NULL, true},
75 {VMWGFX_NUM_GB_SCREEN_TARGET * SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE,
76 NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE}
77};
78
79static const struct vmw_otable dx_tables[] = {
80 {VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE, NULL, true},
81 {VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE, NULL, true},
82 {VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE, NULL, true},
83 {VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE, NULL, true},
84 {VMWGFX_NUM_GB_SCREEN_TARGET * SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE,
85 NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE},
86 {VMWGFX_NUM_DXCONTEXT * sizeof(SVGAOTableDXContextEntry), NULL, true},
73};87};
74 88
75static int vmw_mob_pt_populate(struct vmw_private *dev_priv,89static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
@@ -92,6 +106,7 @@ static void vmw_mob_pt_setup(struct vmw_mob *mob, · 16 unmodified lines
92 */106 */
93static int vmw_setup_otable_base(struct vmw_private *dev_priv,107static int vmw_setup_otable_base(struct vmw_private *dev_priv,
94 SVGAOTableType type,108 SVGAOTableType type,
109 struct ttm_buffer_object *otable_bo,
95 unsigned long offset,110 unsigned long offset,
96 struct vmw_otable *otable)111 struct vmw_otable *otable)
97{112{
@@ -106,7 +121,7 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv, · 8 unmodified lines
106 121
107 BUG_ON(otable->page_table != NULL);122 BUG_ON(otable->page_table != NULL);
108 123
109 vsgt = vmw_bo_sg_table(dev_priv->otable_bo);124 vsgt = vmw_bo_sg_table(otable_bo);
110 vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);125 vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);
111 WARN_ON(!vmw_piter_next(&iter));126 WARN_ON(!vmw_piter_next(&iter));
112 127
@@ -193,7 +208,7 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, · 80 unmodified lines
193 "takedown.\n");208 "takedown.\n");
194 return;209 return;
195 }210 }
196 211
197 memset(cmd, 0, sizeof(*cmd));212 memset(cmd, 0, sizeof(*cmd));
198 cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;213 cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
199 cmd->header.size = sizeof(cmd->body);214 cmd->header.size = sizeof(cmd->body);
@@ -218,47 +233,21 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, · 18 unmodified lines
218 otable->page_table = NULL;233 otable->page_table = NULL;
219}234}
220 235
221/*236
222 * vmw_otables_setup - Set up guest backed memory object tables237static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
223 *238 struct vmw_otable_batch *batch)
224 * @dev_priv: Pointer to a device private structure
225 *
226 * Takes care of the device guest backed surface
227 * initialization, by setting up the guest backed memory object tables.
228 * Returns 0 on success and various error codes on failure. A succesful return
229 * means the object tables can be taken down using the vmw_otables_takedown
230 * function.
231 */
232int vmw_otables_setup(struct vmw_private *dev_priv)
233{239{
234 unsigned long offset;240 unsigned long offset;
235 unsigned long bo_size;241 unsigned long bo_size;
236 struct vmw_otable *otables;242 struct vmw_otable *otables = batch->otables;
237 SVGAOTableType i;243 SVGAOTableType i;
238 int ret;244 int ret;
239 245
240 otables = kzalloc(SVGA_OTABLE_DX9_MAX * sizeof(*otables),
241 GFP_KERNEL);
242 if (unlikely(otables == NULL)) {
243 DRM_ERROR("Failed to allocate space for otable "
244 "metadata.\n");
245 return -ENOMEM;
246 }
247
248 otables[SVGA_OTABLE_MOB].size =
249 VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE;
250 otables[SVGA_OTABLE_SURFACE].size =
251 VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE;
252 otables[SVGA_OTABLE_CONTEXT].size =
253 VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE;
254 otables[SVGA_OTABLE_SHADER].size =
255 VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE;
256 otables[SVGA_OTABLE_SCREENTARGET].size =
257 VMWGFX_NUM_GB_SCREEN_TARGET *
258 SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE;
259
260 bo_size = 0;246 bo_size = 0;
261 for (i = 0; i < SVGA_OTABLE_DX9_MAX; ++i) {247 for (i = 0; i < batch->num_otables; ++i) {
248 if (!otables[i].enabled)
249 continue;
250
262 otables[i].size =251 otables[i].size =
263 (otables[i].size + PAGE_SIZE - 1) & PAGE_MASK;252 (otables[i].size + PAGE_SIZE - 1) & PAGE_MASK;
264 bo_size += otables[i].size;253 bo_size += otables[i].size;
@@ -268,63 +257,105 @@ int vmw_otables_setup(struct vmw_private *dev_priv) · 3 unmodified lines
268 ttm_bo_type_device,257 ttm_bo_type_device,
269 &vmw_sys_ne_placement,258 &vmw_sys_ne_placement,
270 0, false, NULL,259 0, false, NULL,
271 &dev_priv->otable_bo);260 &batch->otable_bo);
272 261
273 if (unlikely(ret != 0))262 if (unlikely(ret != 0))
274 goto out_no_bo;263 goto out_no_bo;
275 264
276 ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, NULL);265 ret = ttm_bo_reserve(batch->otable_bo, false, true, false, NULL);
277 BUG_ON(ret != 0);266 BUG_ON(ret != 0);
278 ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm);267 ret = vmw_bo_driver.ttm_tt_populate(batch->otable_bo->ttm);
279 if (unlikely(ret != 0))268 if (unlikely(ret != 0))
280 goto out_unreserve;269 goto out_unreserve;
281 ret = vmw_bo_map_dma(dev_priv->otable_bo);270 ret = vmw_bo_map_dma(batch->otable_bo);
282 if (unlikely(ret != 0))271 if (unlikely(ret != 0))
283 goto out_unreserve;272 goto out_unreserve;
284 273
285 ttm_bo_unreserve(dev_priv->otable_bo);274 ttm_bo_unreserve(batch->otable_bo);
286 275
287 offset = 0;276 offset = 0;
288 for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) {277 for (i = 0; i < batch->num_otables; ++i) {
289 ret = vmw_setup_otable_base(dev_priv, i, offset,278 if (!batch->otables[i].enabled)
279 continue;
280
281 ret = vmw_setup_otable_base(dev_priv, i, batch->otable_bo,
282 offset,
290 &otables[i]);283 &otables[i]);
291 if (unlikely(ret != 0))284 if (unlikely(ret != 0))
292 goto out_no_setup;285 goto out_no_setup;
293 offset += otables[i].size;286 offset += otables[i].size;
294 }287 }
295 288
296 dev_priv->otables = otables;
297 return 0;289 return 0;
298 290
299out_unreserve:291out_unreserve:
300 ttm_bo_unreserve(dev_priv->otable_bo);292 ttm_bo_unreserve(batch->otable_bo);
301out_no_setup:293out_no_setup:
302 for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)294 for (i = 0; i < batch->num_otables; ++i) {
303 vmw_takedown_otable_base(dev_priv, i, &otables[i]);295 if (batch->otables[i].enabled)
296 vmw_takedown_otable_base(dev_priv, i,
297 &batch->otables[i]);
298 }
304 299
305 ttm_bo_unref(&dev_priv->otable_bo);300 ttm_bo_unref(&batch->otable_bo);
306out_no_bo:301out_no_bo:
307 kfree(otables);
308 return ret;302 return ret;
309}303}
310 304
311
312/*305/*
313 * vmw_otables_takedown - Take down guest backed memory object tables306 * vmw_otables_setup - Set up guest backed memory object tables
314 *307 *
315 * @dev_priv: Pointer to a device private structure308 * @dev_priv: Pointer to a device private structure
316 *309 *
317 * Take down the Guest Memory Object tables.310 * Takes care of the device guest backed surface
311 * initialization, by setting up the guest backed memory object tables.
312 * Returns 0 on success and various error codes on failure. A successful return
313 * means the object tables can be taken down using the vmw_otables_takedown
314 * function.
318 */315 */
319void vmw_otables_takedown(struct vmw_private *dev_priv)316int vmw_otables_setup(struct vmw_private *dev_priv)
317{
318 struct vmw_otable **otables = &dev_priv->otable_batch.otables;
319 int ret;
320
321 if (dev_priv->has_dx) {
322 *otables = kmalloc(sizeof(dx_tables), GFP_KERNEL);
323 if (*otables == NULL)
324 return -ENOMEM;
325
326 memcpy(*otables, dx_tables, sizeof(dx_tables));
327 dev_priv->otable_batch.num_otables = ARRAY_SIZE(dx_tables);
328 } else {
329 *otables = kmalloc(sizeof(pre_dx_tables), GFP_KERNEL);
330 if (*otables == NULL)
331 return -ENOMEM;
332
333 memcpy(*otables, pre_dx_tables, sizeof(pre_dx_tables));
334 dev_priv->otable_batch.num_otables = ARRAY_SIZE(pre_dx_tables);
335 }
336
337 ret = vmw_otable_batch_setup(dev_priv, &dev_priv->otable_batch);
338 if (unlikely(ret != 0))
339 goto out_setup;
340
341 return 0;
342
343out_setup:
344 kfree(*otables);
345 return ret;
346}
347
348static void vmw_otable_batch_takedown(struct vmw_private *dev_priv,
349 struct vmw_otable_batch *batch)
320{350{
321 SVGAOTableType i;351 SVGAOTableType i;
322 struct ttm_buffer_object *bo = dev_priv->otable_bo;352 struct ttm_buffer_object *bo = batch->otable_bo;
323 int ret;353 int ret;
324 354
325 for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)355 for (i = 0; i < batch->num_otables; ++i)
326 vmw_takedown_otable_base(dev_priv, i,356 if (batch->otables[i].enabled)
327 &dev_priv->otables[i]);357 vmw_takedown_otable_base(dev_priv, i,
358 &batch->otables[i]);
328 359
329 ret = ttm_bo_reserve(bo, false, true, false, NULL);360 ret = ttm_bo_reserve(bo, false, true, false, NULL);
330 BUG_ON(ret != 0);361 BUG_ON(ret != 0);
@@ -332,11 +363,21 @@ void vmw_otables_takedown(struct vmw_private *dev_priv) · 1 unmodified line
332 vmw_fence_single_bo(bo, NULL);363 vmw_fence_single_bo(bo, NULL);
333 ttm_bo_unreserve(bo);364 ttm_bo_unreserve(bo);
334 365
335 ttm_bo_unref(&dev_priv->otable_bo);366 ttm_bo_unref(&batch->otable_bo);
336 kfree(dev_priv->otables);
337 dev_priv->otables = NULL;
338}367}
339 368
369/*
370 * vmw_otables_takedown - Take down guest backed memory object tables
371 *
372 * @dev_priv: Pointer to a device private structure
373 *
374 * Take down the Guest Memory Object tables.
375 */
376void vmw_otables_takedown(struct vmw_private *dev_priv)
377{
378 vmw_otable_batch_takedown(dev_priv, &dev_priv->otable_batch);
379 kfree(dev_priv->otable_batch.otables);
380}
340 381
341/*382/*
342 * vmw_mob_calculate_pt_pages - Calculate the number of page table pages383 * vmw_mob_calculate_pt_pages - Calculate the number of page table pages
@@ -410,7 +451,7 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv, · 67 unmodified lines
410 goto out_unreserve;451 goto out_unreserve;
411 452
412 ttm_bo_unreserve(mob->pt_bo);453 ttm_bo_unreserve(mob->pt_bo);
413 454
414 return 0;455 return 0;
415 456
416out_unreserve:457out_unreserve:
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c+34−14
@@ -31,6 +31,7 @@ · 30 unmodified lines
31#include <drm/ttm/ttm_placement.h>31#include <drm/ttm/ttm_placement.h>
32#include <drm/drmP.h>32#include <drm/drmP.h>
33#include "vmwgfx_resource_priv.h"33#include "vmwgfx_resource_priv.h"
34#include "vmwgfx_binding.h"
34 35
35#define VMW_RES_EVICT_ERR_COUNT 1036#define VMW_RES_EVICT_ERR_COUNT 10
36 37
@@ -144,10 +145,10 @@ static void vmw_resource_release(struct kref *kref) · 107 unmodified lines
144 }145 }
145 146
146 if (likely(res->hw_destroy != NULL)) {147 if (likely(res->hw_destroy != NULL)) {
147 res->hw_destroy(res);
148 mutex_lock(&dev_priv->binding_mutex);148 mutex_lock(&dev_priv->binding_mutex);
149 vmw_context_binding_res_list_kill(&res->binding_head);149 vmw_binding_res_list_kill(&res->binding_head);
150 mutex_unlock(&dev_priv->binding_mutex);150 mutex_unlock(&dev_priv->binding_mutex);
151 res->hw_destroy(res);
151 }152 }
152 153
153 id = res->id;154 id = res->id;
@@ -1149,14 +1150,16 @@ out_bind_failed: · 995 unmodified lines
1149 * command submission.1150 * command submission.
1150 *1151 *
1151 * @res: Pointer to the struct vmw_resource to unreserve.1152 * @res: Pointer to the struct vmw_resource to unreserve.
1153 * @switch_backup: Backup buffer has been switched.
1152 * @new_backup: Pointer to new backup buffer if command submission1154 * @new_backup: Pointer to new backup buffer if command submission
1153 * switched.1155 * switched. May be NULL.
1154 * @new_backup_offset: New backup offset if @new_backup is !NULL.1156 * @new_backup_offset: New backup offset if @switch_backup is true.
1155 *1157 *
1156 * Currently unreserving a resource means putting it back on the device's1158 * Currently unreserving a resource means putting it back on the device's
1157 * resource lru list, so that it can be evicted if necessary.1159 * resource lru list, so that it can be evicted if necessary.
1158 */1160 */
1159void vmw_resource_unreserve(struct vmw_resource *res,1161void vmw_resource_unreserve(struct vmw_resource *res,
1162 bool switch_backup,
1160 struct vmw_dma_buffer *new_backup,1163 struct vmw_dma_buffer *new_backup,
1161 unsigned long new_backup_offset)1164 unsigned long new_backup_offset)
1162{1165{
@@ -1165,19 +1168,22 @@ void vmw_resource_unreserve(struct vmw_resource *res, · 2 unmodified lines
1165 if (!list_empty(&res->lru_head))1168 if (!list_empty(&res->lru_head))
1166 return;1169 return;
1167 1170
1168 if (new_backup && new_backup != res->backup) {1171 if (switch_backup && new_backup != res->backup) {
1169
1170 if (res->backup) {1172 if (res->backup) {
1171 lockdep_assert_held(&res->backup->base.resv->lock.base);1173 lockdep_assert_held(&res->backup->base.resv->lock.base);
1172 list_del_init(&res->mob_head);1174 list_del_init(&res->mob_head);
1173 vmw_dmabuf_unreference(&res->backup);1175 vmw_dmabuf_unreference(&res->backup);
1174 }1176 }
1175 1177
1176 res->backup = vmw_dmabuf_reference(new_backup);1178 if (new_backup) {
1177 lockdep_assert_held(&new_backup->base.resv->lock.base);1179 res->backup = vmw_dmabuf_reference(new_backup);
1178 list_add_tail(&res->mob_head, &new_backup->res_list);1180 lockdep_assert_held(&new_backup->base.resv->lock.base);
1181 list_add_tail(&res->mob_head, &new_backup->res_list);
1182 } else {
1183 res->backup = NULL;
1184 }
1179 }1185 }
1180 if (new_backup)1186 if (switch_backup)
1181 res->backup_offset = new_backup_offset;1187 res->backup_offset = new_backup_offset;
1182 1188
1183 if (!res->func->may_evict || res->id == -1 || res->pin_count)1189 if (!res->func->may_evict || res->id == -1 || res->pin_count)
@@ -1269,8 +1275,12 @@ int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, · 85 unmodified lines
1269 if (res->func->needs_backup && res->backup == NULL &&1275 if (res->func->needs_backup && res->backup == NULL &&
1270 !no_backup) {1276 !no_backup) {
1271 ret = vmw_resource_buf_alloc(res, interruptible);1277 ret = vmw_resource_buf_alloc(res, interruptible);
1272 if (unlikely(ret != 0))1278 if (unlikely(ret != 0)) {
1279 DRM_ERROR("Failed to allocate a backup buffer "
1280 "of size %lu. bytes\n",
1281 (unsigned long) res->backup_size);
1273 return ret;1282 return ret;
1283 }
1274 }1284 }
1275 1285
1276 return 0;1286 return 0;
@@ -1354,7 +1364,7 @@ int vmw_resource_validate(struct vmw_resource *res) · 77 unmodified lines
1354 struct ttm_validate_buffer val_buf;1364 struct ttm_validate_buffer val_buf;
1355 unsigned err_count = 0;1365 unsigned err_count = 0;
1356 1366
1357 if (likely(!res->func->may_evict))1367 if (!res->func->create)
1358 return 0;1368 return 0;
1359 1369
1360 val_buf.bo = NULL;1370 val_buf.bo = NULL;
@@ -1624,7 +1634,7 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible) · 263 unmodified lines
1624 res->pin_count++;1634 res->pin_count++;
1625 1635
1626out_no_validate:1636out_no_validate:
1627 vmw_resource_unreserve(res, NULL, 0UL);1637 vmw_resource_unreserve(res, false, NULL, 0UL);
1628out_no_reserve:1638out_no_reserve:
1629 mutex_unlock(&dev_priv->cmdbuf_mutex);1639 mutex_unlock(&dev_priv->cmdbuf_mutex);
1630 ttm_write_unlock(&dev_priv->reservation_sem);1640 ttm_write_unlock(&dev_priv->reservation_sem);
@@ -1660,8 +1670,18 @@ void vmw_resource_unpin(struct vmw_resource *res) · 29 unmodified lines
1660 ttm_bo_unreserve(&vbo->base);1670 ttm_bo_unreserve(&vbo->base);
1661 }1671 }
1662 1672
1663 vmw_resource_unreserve(res, NULL, 0UL);1673 vmw_resource_unreserve(res, false, NULL, 0UL);
1664 1674
1665 mutex_unlock(&dev_priv->cmdbuf_mutex);1675 mutex_unlock(&dev_priv->cmdbuf_mutex);
1666 ttm_read_unlock(&dev_priv->reservation_sem);1676 ttm_read_unlock(&dev_priv->reservation_sem);
1667}1677}
1678
1679/**
1680 * vmw_res_type - Return the resource type
1681 *
1682 * @res: Pointer to the resource
1683 */
1684enum vmw_res_type vmw_res_type(const struct vmw_resource *res)
1685{
1686 return res->func->res_type;
1687}
drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h+11−1
@@ -30,6 +30,12 @@ · 29 unmodified lines
30 30
31#include "vmwgfx_drv.h"31#include "vmwgfx_drv.h"
32 32
33enum vmw_cmdbuf_res_state {
34 VMW_CMDBUF_RES_COMMITTED,
35 VMW_CMDBUF_RES_ADD,
36 VMW_CMDBUF_RES_DEL
37};
38
33/**39/**
34 * struct vmw_user_resource_conv - Identify a derived user-exported resource40 * struct vmw_user_resource_conv - Identify a derived user-exported resource
35 * type and provide a function to convert its ttm_base_object pointer to41 * type and provide a function to convert its ttm_base_object pointer to
@@ -55,8 +61,10 @@ struct vmw_user_resource_conv { · 19 unmodified lines
55 * @bind: Bind a hardware resource to persistent buffer storage.61 * @bind: Bind a hardware resource to persistent buffer storage.
56 * @unbind: Unbind a hardware resource from persistent62 * @unbind: Unbind a hardware resource from persistent
57 * buffer storage.63 * buffer storage.
64 * @commit_notify: If the resource is a command buffer managed resource,
65 * callback to notify that a define or remove command
66 * has been committed to the device.
58 */67 */
59
60struct vmw_res_func {68struct vmw_res_func {
61 enum vmw_res_type res_type;69 enum vmw_res_type res_type;
62 bool needs_backup;70 bool needs_backup;
@@ -71,6 +79,8 @@ struct vmw_res_func { · 8 unmodified lines
71 int (*unbind) (struct vmw_resource *res,79 int (*unbind) (struct vmw_resource *res,
72 bool readback,80 bool readback,
73 struct ttm_validate_buffer *val_buf);81 struct ttm_validate_buffer *val_buf);
82 void (*commit_notify)(struct vmw_resource *res,
83 enum vmw_cmdbuf_res_state state);
74};84};
75 85
76int vmw_resource_alloc_id(struct vmw_resource *res);86int vmw_resource_alloc_id(struct vmw_resource *res);
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c+440−44
@@ -27,12 +27,15 @@ · 26 unmodified lines
27 27
28#include "vmwgfx_drv.h"28#include "vmwgfx_drv.h"
29#include "vmwgfx_resource_priv.h"29#include "vmwgfx_resource_priv.h"
30#include "vmwgfx_binding.h"
30#include "ttm/ttm_placement.h"31#include "ttm/ttm_placement.h"
31 32
32struct vmw_shader {33struct vmw_shader {
33 struct vmw_resource res;34 struct vmw_resource res;
34 SVGA3dShaderType type;35 SVGA3dShaderType type;
35 uint32_t size;36 uint32_t size;
37 uint8_t num_input_sig;
38 uint8_t num_output_sig;
36};39};
37 40
38struct vmw_user_shader {41struct vmw_user_shader {
@@ -40,8 +43,18 @@ struct vmw_user_shader { · 1 unmodified line
40 struct vmw_shader shader;43 struct vmw_shader shader;
41};44};
42 45
46struct vmw_dx_shader {
47 struct vmw_resource res;
48 struct vmw_resource *ctx;
49 struct vmw_resource *cotable;
50 u32 id;
51 bool committed;
52 struct list_head cotable_head;
53};
54
43static uint64_t vmw_user_shader_size;55static uint64_t vmw_user_shader_size;
44static uint64_t vmw_shader_size;56static uint64_t vmw_shader_size;
57static size_t vmw_shader_dx_size;
45 58
46static void vmw_user_shader_free(struct vmw_resource *res);59static void vmw_user_shader_free(struct vmw_resource *res);
47static struct vmw_resource *60static struct vmw_resource *
@@ -55,6 +68,18 @@ static int vmw_gb_shader_unbind(struct vmw_resource *res, · 7 unmodified lines
55 struct ttm_validate_buffer *val_buf);68 struct ttm_validate_buffer *val_buf);
56static int vmw_gb_shader_destroy(struct vmw_resource *res);69static int vmw_gb_shader_destroy(struct vmw_resource *res);
57 70
71static int vmw_dx_shader_create(struct vmw_resource *res);
72static int vmw_dx_shader_bind(struct vmw_resource *res,
73 struct ttm_validate_buffer *val_buf);
74static int vmw_dx_shader_unbind(struct vmw_resource *res,
75 bool readback,
76 struct ttm_validate_buffer *val_buf);
77static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
78 enum vmw_cmdbuf_res_state state);
79static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
80static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
81static uint64_t vmw_user_shader_size;
82
58static const struct vmw_user_resource_conv user_shader_conv = {83static const struct vmw_user_resource_conv user_shader_conv = {
59 .object_type = VMW_RES_SHADER,84 .object_type = VMW_RES_SHADER,
60 .base_obj_to_res = vmw_user_shader_base_to_res,85 .base_obj_to_res = vmw_user_shader_base_to_res,
@@ -77,6 +102,24 @@ static const struct vmw_res_func vmw_gb_shader_func = { · 16 unmodified lines
77 .unbind = vmw_gb_shader_unbind102 .unbind = vmw_gb_shader_unbind
78};103};
79 104
105static const struct vmw_res_func vmw_dx_shader_func = {
106 .res_type = vmw_res_shader,
107 .needs_backup = true,
108 .may_evict = false,
109 .type_name = "dx shaders",
110 .backup_placement = &vmw_mob_placement,
111 .create = vmw_dx_shader_create,
112 /*
113 * The destroy callback is only called with a committed resource on
114 * context destroy, in which case we destroy the cotable anyway,
115 * so there's no need to destroy DX shaders separately.
116 */
117 .destroy = NULL,
118 .bind = vmw_dx_shader_bind,
119 .unbind = vmw_dx_shader_unbind,
120 .commit_notify = vmw_dx_shader_commit_notify,
121};
122
80/**123/**
81 * Shader management:124 * Shader management:
82 */125 */
@@ -87,25 +130,42 @@ vmw_res_to_shader(struct vmw_resource *res) · 4 unmodified lines
87 return container_of(res, struct vmw_shader, res);130 return container_of(res, struct vmw_shader, res);
88}131}
89 132
133/**
134 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
135 * struct vmw_dx_shader
136 *
137 * @res: Pointer to the struct vmw_resource.
138 */
139static inline struct vmw_dx_shader *
140vmw_res_to_dx_shader(struct vmw_resource *res)
141{
142 return container_of(res, struct vmw_dx_shader, res);
143}
144
90static void vmw_hw_shader_destroy(struct vmw_resource *res)145static void vmw_hw_shader_destroy(struct vmw_resource *res)
91{146{
92 (void) vmw_gb_shader_destroy(res);147 if (likely(res->func->destroy))
148 (void) res->func->destroy(res);
149 else
150 res->id = -1;
93}151}
94 152
153
95static int vmw_gb_shader_init(struct vmw_private *dev_priv,154static int vmw_gb_shader_init(struct vmw_private *dev_priv,
96 struct vmw_resource *res,155 struct vmw_resource *res,
97 uint32_t size,156 uint32_t size,
98 uint64_t offset,157 uint64_t offset,
99 SVGA3dShaderType type,158 SVGA3dShaderType type,
159 uint8_t num_input_sig,
160 uint8_t num_output_sig,
100 struct vmw_dma_buffer *byte_code,161 struct vmw_dma_buffer *byte_code,
101 void (*res_free) (struct vmw_resource *res))162 void (*res_free) (struct vmw_resource *res))
102{163{
103 struct vmw_shader *shader = vmw_res_to_shader(res);164 struct vmw_shader *shader = vmw_res_to_shader(res);
104 int ret;165 int ret;
105 166
106 ret = vmw_resource_init(dev_priv, res, true,167 ret = vmw_resource_init(dev_priv, res, true, res_free,
107 res_free, &vmw_gb_shader_func);168 &vmw_gb_shader_func);
108
109 169
110 if (unlikely(ret != 0)) {170 if (unlikely(ret != 0)) {
111 if (res_free)171 if (res_free)
@@ -122,11 +182,17 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv, · 10 unmodified lines
122 }182 }
123 shader->size = size;183 shader->size = size;
124 shader->type = type;184 shader->type = type;
185 shader->num_input_sig = num_input_sig;
186 shader->num_output_sig = num_output_sig;
125 187
126 vmw_resource_activate(res, vmw_hw_shader_destroy);188 vmw_resource_activate(res, vmw_hw_shader_destroy);
127 return 0;189 return 0;
128}190}
129 191
192/*
193 * GB shader code:
194 */
195
130static int vmw_gb_shader_create(struct vmw_resource *res)196static int vmw_gb_shader_create(struct vmw_resource *res)
131{197{
132 struct vmw_private *dev_priv = res->dev_priv;198 struct vmw_private *dev_priv = res->dev_priv;
@@ -259,7 +325,7 @@ static int vmw_gb_shader_destroy(struct vmw_resource *res) · 126 unmodified lines
259 return 0;325 return 0;
260 326
261 mutex_lock(&dev_priv->binding_mutex);327 mutex_lock(&dev_priv->binding_mutex);
262 vmw_context_binding_res_list_scrub(&res->binding_head);328 vmw_binding_res_list_scrub(&res->binding_head);
263 329
264 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));330 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
265 if (unlikely(cmd == NULL)) {331 if (unlikely(cmd == NULL)) {
@@ -280,6 +346,321 @@ static int vmw_gb_shader_destroy(struct vmw_resource *res) · 14 unmodified lines
280 return 0;346 return 0;
281}347}
282 348
349/*
350 * DX shader code:
351 */
352
353/**
354 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
355 * committed to hardware from a user-supplied command stream.
356 *
357 * @res: Pointer to the shader resource.
358 * @state: Indicating whether a creation or removal has been committed.
359 *
360 */
361static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
362 enum vmw_cmdbuf_res_state state)
363{
364 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
365 struct vmw_private *dev_priv = res->dev_priv;
366
367 if (state == VMW_CMDBUF_RES_ADD) {
368 mutex_lock(&dev_priv->binding_mutex);
369 vmw_cotable_add_resource(shader->cotable,
370 &shader->cotable_head);
371 shader->committed = true;
372 res->id = shader->id;
373 mutex_unlock(&dev_priv->binding_mutex);
374 } else {
375 mutex_lock(&dev_priv->binding_mutex);
376 list_del_init(&shader->cotable_head);
377 shader->committed = false;
378 res->id = -1;
379 mutex_unlock(&dev_priv->binding_mutex);
380 }
381}
382
383/**
384 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
385 *
386 * @res: The shader resource
387 *
388 * This function reverts a scrub operation.
389 */
390static int vmw_dx_shader_unscrub(struct vmw_resource *res)
391{
392 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
393 struct vmw_private *dev_priv = res->dev_priv;
394 struct {
395 SVGA3dCmdHeader header;
396 SVGA3dCmdDXBindShader body;
397 } *cmd;
398
399 if (!list_empty(&shader->cotable_head) || !shader->committed)
400 return 0;
401
402 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd),
403 shader->ctx->id);
404 if (unlikely(cmd == NULL)) {
405 DRM_ERROR("Failed reserving FIFO space for shader "
406 "scrubbing.\n");
407 return -ENOMEM;
408 }
409
410 cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
411 cmd->header.size = sizeof(cmd->body);
412 cmd->body.cid = shader->ctx->id;
413 cmd->body.shid = shader->id;
414 cmd->body.mobid = res->backup->base.mem.start;
415 cmd->body.offsetInBytes = res->backup_offset;
416 vmw_fifo_commit(dev_priv, sizeof(*cmd));
417
418 vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
419
420 return 0;
421}
422
423/**
424 * vmw_dx_shader_create - The DX shader create callback
425 *
426 * @res: The DX shader resource
427 *
428 * The create callback is called as part of resource validation and
429 * makes sure that we unscrub the shader if it's previously been scrubbed.
430 */
431static int vmw_dx_shader_create(struct vmw_resource *res)
432{
433 struct vmw_private *dev_priv = res->dev_priv;
434 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
435 int ret = 0;
436
437 WARN_ON_ONCE(!shader->committed);
438
439 if (!list_empty(&res->mob_head)) {
440 mutex_lock(&dev_priv->binding_mutex);
441 ret = vmw_dx_shader_unscrub(res);
442 mutex_unlock(&dev_priv->binding_mutex);
443 }
444
445 res->id = shader->id;
446 return ret;
447}
448
449/**
450 * vmw_dx_shader_bind - The DX shader bind callback
451 *
452 * @res: The DX shader resource
453 * @val_buf: Pointer to the validate buffer.
454 *
455 */
456static int vmw_dx_shader_bind(struct vmw_resource *res,
457 struct ttm_validate_buffer *val_buf)
458{
459 struct vmw_private *dev_priv = res->dev_priv;
460 struct ttm_buffer_object *bo = val_buf->bo;
461
462 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
463 mutex_lock(&dev_priv->binding_mutex);
464 vmw_dx_shader_unscrub(res);
465 mutex_unlock(&dev_priv->binding_mutex);
466
467 return 0;
468}
469
470/**
471 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
472 *
473 * @res: The shader resource
474 *
475 * This function unbinds a MOB from the DX shader without requiring the
476 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
477 * However, once the driver eventually decides to unbind the MOB, it doesn't
478 * need to access the context.
479 */
480static int vmw_dx_shader_scrub(struct vmw_resource *res)
481{
482 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
483 struct vmw_private *dev_priv = res->dev_priv;
484 struct {
485 SVGA3dCmdHeader header;
486 SVGA3dCmdDXBindShader body;
487 } *cmd;
488
489 if (list_empty(&shader->cotable_head))
490 return 0;
491
492 WARN_ON_ONCE(!shader->committed);
493 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
494 if (unlikely(cmd == NULL)) {
495 DRM_ERROR("Failed reserving FIFO space for shader "
496 "scrubbing.\n");
497 return -ENOMEM;
498 }
499
500 cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
501 cmd->header.size = sizeof(cmd->body);
502 cmd->body.cid = shader->ctx->id;
503 cmd->body.shid = res->id;
504 cmd->body.mobid = SVGA3D_INVALID_ID;
505 cmd->body.offsetInBytes = 0;
506 vmw_fifo_commit(dev_priv, sizeof(*cmd));
507 res->id = -1;
508 list_del_init(&shader->cotable_head);
509
510 return 0;
511}
512
513/**
514 * vmw_dx_shader_unbind - The dx shader unbind callback.
515 *
516 * @res: The shader resource
517 * @readback: Whether this is a readback unbind. Currently unused.
518 * @val_buf: MOB buffer information.
519 */
520static int vmw_dx_shader_unbind(struct vmw_resource *res,
521 bool readback,
522 struct ttm_validate_buffer *val_buf)
523{
524 struct vmw_private *dev_priv = res->dev_priv;
525 struct vmw_fence_obj *fence;
526 int ret;
527
528 BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
529
530 mutex_lock(&dev_priv->binding_mutex);
531 ret = vmw_dx_shader_scrub(res);
532 mutex_unlock(&dev_priv->binding_mutex);
533
534 if (ret)
535 return ret;
536
537 (void) vmw_execbuf_fence_commands(NULL, dev_priv,
538 &fence, NULL);
539 vmw_fence_single_bo(val_buf->bo, fence);
540
541 if (likely(fence != NULL))
542 vmw_fence_obj_unreference(&fence);
543
544 return 0;
545}
546
547/**
548 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
549 * DX shaders.
550 *
551 * @dev_priv: Pointer to device private structure.
552 * @list: The list of cotable resources.
553 * @readback: Whether the call was part of a readback unbind.
554 *
555 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
556 * destroy operation won't need to swap in the context.
557 */
558void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
559 struct list_head *list,
560 bool readback)
561{
562 struct vmw_dx_shader *entry, *next;
563
564 WARN_ON_ONCE(!mutex_is_locked(&dev_priv->binding_mutex));
565
566 list_for_each_entry_safe(entry, next, list, cotable_head) {
567 WARN_ON(vmw_dx_shader_scrub(&entry->res));
568 if (!readback)
569 entry->committed = false;
570 }
571}
572
573/**
574 * vmw_dx_shader_res_free - The DX shader free callback
575 *
576 * @res: The shader resource
577 *
578 * Frees the DX shader resource and updates memory accounting.
579 */
580static void vmw_dx_shader_res_free(struct vmw_resource *res)
581{
582 struct vmw_private *dev_priv = res->dev_priv;
583 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
584
585 vmw_resource_unreference(&shader->cotable);
586 kfree(shader);
587 ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
588}
589
590/**
591 * vmw_dx_shader_add - Add a shader resource as a command buffer managed
592 * resource.
593 *
594 * @man: The command buffer resource manager.
595 * @ctx: Pointer to the context resource.
596 * @user_key: The id used for this shader.
597 * @shader_type: The shader type.
598 * @list: The list of staged command buffer managed resources.
599 */
600int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
601 struct vmw_resource *ctx,
602 u32 user_key,
603 SVGA3dShaderType shader_type,
604 struct list_head *list)
605{
606 struct vmw_dx_shader *shader;
607 struct vmw_resource *res;
608 struct vmw_private *dev_priv = ctx->dev_priv;
609 int ret;
610
611 if (!vmw_shader_dx_size)
612 vmw_shader_dx_size = ttm_round_pot(sizeof(*shader));
613
614 if (!vmw_shader_id_ok(user_key, shader_type))
615 return -EINVAL;
616
617 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size,
618 false, true);
619 if (ret) {
620 if (ret != -ERESTARTSYS)
621 DRM_ERROR("Out of graphics memory for shader "
622 "creation.\n");
623 return ret;
624 }
625
626 shader = kmalloc(sizeof(*shader), GFP_KERNEL);
627 if (!shader) {
628 ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
629 return -ENOMEM;
630 }
631
632 res = &shader->res;
633 shader->ctx = ctx;
634 shader->cotable = vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER);
635 shader->id = user_key;
636 shader->committed = false;
637 INIT_LIST_HEAD(&shader->cotable_head);
638 ret = vmw_resource_init(dev_priv, res, true,
639 vmw_dx_shader_res_free, &vmw_dx_shader_func);
640 if (ret)
641 goto out_resource_init;
642
643 /*
644 * The user_key name-space is not per shader type for DX shaders,
645 * so when hashing, use a single zero shader type.
646 */
647 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
648 vmw_shader_key(user_key, 0),
649 res, list);
650 if (ret)
651 goto out_resource_init;
652
653 res->id = shader->id;
654 vmw_resource_activate(res, vmw_hw_shader_destroy);
655
656out_resource_init:
657 vmw_resource_unreference(&res);
658
659 return ret;
660}
661
662
663
283/**664/**
284 * User-space shader management:665 * User-space shader management:
285 */666 */
@@ -341,6 +722,8 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv, · 55 unmodified lines
341 size_t shader_size,722 size_t shader_size,
342 size_t offset,723 size_t offset,
343 SVGA3dShaderType shader_type,724 SVGA3dShaderType shader_type,
725 uint8_t num_input_sig,
726 uint8_t num_output_sig,
344 struct ttm_object_file *tfile,727 struct ttm_object_file *tfile,
345 u32 *handle)728 u32 *handle)
346{729{
@@ -383,7 +766,8 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv, · 36 unmodified lines
383 */766 */
384 767
385 ret = vmw_gb_shader_init(dev_priv, res, shader_size,768 ret = vmw_gb_shader_init(dev_priv, res, shader_size,
386 offset, shader_type, buffer,769 offset, shader_type, num_input_sig,
770 num_output_sig, buffer,
387 vmw_user_shader_free);771 vmw_user_shader_free);
388 if (unlikely(ret != 0))772 if (unlikely(ret != 0))
389 goto out;773 goto out;
@@ -449,7 +833,7 @@ static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, · 59 unmodified lines
449 * From here on, the destructor takes over resource freeing.833 * From here on, the destructor takes over resource freeing.
450 */834 */
451 ret = vmw_gb_shader_init(dev_priv, res, shader_size,835 ret = vmw_gb_shader_init(dev_priv, res, shader_size,
452 offset, shader_type, buffer,836 offset, shader_type, 0, 0, buffer,
453 vmw_shader_free);837 vmw_shader_free);
454 838
455out_err:839out_err:
@@ -457,19 +841,20 @@ out_err: · 1 unmodified line
457}841}
458 842
459 843
460int vmw_shader_define_ioctl(struct drm_device *dev, void *data,844static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
461 struct drm_file *file_priv)845 enum drm_vmw_shader_type shader_type_drm,
846 u32 buffer_handle, size_t size, size_t offset,
847 uint8_t num_input_sig, uint8_t num_output_sig,
848 uint32_t *shader_handle)
462{849{
463 struct vmw_private *dev_priv = vmw_priv(dev);850 struct vmw_private *dev_priv = vmw_priv(dev);
464 struct drm_vmw_shader_create_arg *arg =
465 (struct drm_vmw_shader_create_arg *)data;
466 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;851 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
467 struct vmw_dma_buffer *buffer = NULL;852 struct vmw_dma_buffer *buffer = NULL;
468 SVGA3dShaderType shader_type;853 SVGA3dShaderType shader_type;
469 int ret;854 int ret;
470 855
471 if (arg->buffer_handle != SVGA3D_INVALID_ID) {856 if (buffer_handle != SVGA3D_INVALID_ID) {
472 ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle,857 ret = vmw_user_dmabuf_lookup(tfile, buffer_handle,
473 &buffer);858 &buffer);
474 if (unlikely(ret != 0)) {859 if (unlikely(ret != 0)) {
475 DRM_ERROR("Could not find buffer for shader "860 DRM_ERROR("Could not find buffer for shader "
@@ -478,23 +863,20 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data, · 2 unmodified lines
478 }863 }
479 864
480 if ((u64)buffer->base.num_pages * PAGE_SIZE <865 if ((u64)buffer->base.num_pages * PAGE_SIZE <
481 (u64)arg->size + (u64)arg->offset) {866 (u64)size + (u64)offset) {
482 DRM_ERROR("Illegal buffer- or shader size.\n");867 DRM_ERROR("Illegal buffer- or shader size.\n");
483 ret = -EINVAL;868 ret = -EINVAL;
484 goto out_bad_arg;869 goto out_bad_arg;
485 }870 }
486 }871 }
487 872
488 switch (arg->shader_type) {873 switch (shader_type_drm) {
489 case drm_vmw_shader_type_vs:874 case drm_vmw_shader_type_vs:
490 shader_type = SVGA3D_SHADERTYPE_VS;875 shader_type = SVGA3D_SHADERTYPE_VS;
491 break;876 break;
492 case drm_vmw_shader_type_ps:877 case drm_vmw_shader_type_ps:
493 shader_type = SVGA3D_SHADERTYPE_PS;878 shader_type = SVGA3D_SHADERTYPE_PS;
494 break;879 break;
495 case drm_vmw_shader_type_gs:
496 shader_type = SVGA3D_SHADERTYPE_GS;
497 break;
498 default:880 default:
499 DRM_ERROR("Illegal shader type.\n");881 DRM_ERROR("Illegal shader type.\n");
500 ret = -EINVAL;882 ret = -EINVAL;
@@ -505,8 +887,9 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data, · 4 unmodified lines
505 if (unlikely(ret != 0))887 if (unlikely(ret != 0))
506 goto out_bad_arg;888 goto out_bad_arg;
507 889
508 ret = vmw_user_shader_alloc(dev_priv, buffer, arg->size, arg->offset,890 ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
509 shader_type, tfile, &arg->shader_handle);891 shader_type, num_input_sig,
892 num_output_sig, tfile, shader_handle);
510 893
511 ttm_read_unlock(&dev_priv->reservation_sem);894 ttm_read_unlock(&dev_priv->reservation_sem);
512out_bad_arg:895out_bad_arg:
@@ -515,7 +898,7 @@ out_bad_arg: · 2 unmodified lines
515}898}
516 899
517/**900/**
518 * vmw_compat_shader_id_ok - Check whether a compat shader user key and901 * vmw_shader_id_ok - Check whether a compat shader user key and
519 * shader type are within valid bounds.902 * shader type are within valid bounds.
520 *903 *
521 * @user_key: User space id of the shader.904 * @user_key: User space id of the shader.
@@ -523,13 +906,13 @@ out_bad_arg: · 1 unmodified line
523 *906 *
524 * Returns true if valid false if not.907 * Returns true if valid false if not.
525 */908 */
526static bool vmw_compat_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)909static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
527{910{
528 return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;911 return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
529}912}
530 913
531/**914/**
532 * vmw_compat_shader_key - Compute a hash key suitable for a compat shader.915 * vmw_shader_key - Compute a hash key suitable for a compat shader.
533 *916 *
534 * @user_key: User space id of the shader.917 * @user_key: User space id of the shader.
535 * @shader_type: Shader type.918 * @shader_type: Shader type.
@@ -537,13 +920,13 @@ static bool vmw_compat_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) · 1 unmodified line
537 * Returns a hash key suitable for a command buffer managed resource920 * Returns a hash key suitable for a command buffer managed resource
538 * manager hash table.921 * manager hash table.
539 */922 */
540static u32 vmw_compat_shader_key(u32 user_key, SVGA3dShaderType shader_type)923static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
541{924{
542 return user_key | (shader_type << 20);925 return user_key | (shader_type << 20);
543}926}
544 927
545/**928/**
546 * vmw_compat_shader_remove - Stage a compat shader for removal.929 * vmw_shader_remove - Stage a compat shader for removal.
547 *930 *
548 * @man: Pointer to the compat shader manager identifying the shader namespace.931 * @man: Pointer to the compat shader manager identifying the shader namespace.
549 * @user_key: The key that is used to identify the shader. The key is932 * @user_key: The key that is used to identify the shader. The key is
@@ -551,17 +934,18 @@ static u32 vmw_compat_shader_key(u32 user_key, SVGA3dShaderType shader_type) · 1 unmodified line
551 * @shader_type: Shader type.934 * @shader_type: Shader type.
552 * @list: Caller's list of staged command buffer resource actions.935 * @list: Caller's list of staged command buffer resource actions.
553 */936 */
554int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man,937int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
555 u32 user_key, SVGA3dShaderType shader_type,938 u32 user_key, SVGA3dShaderType shader_type,
556 struct list_head *list)939 struct list_head *list)
557{940{
558 if (!vmw_compat_shader_id_ok(user_key, shader_type))941 struct vmw_resource *dummy;
942
943 if (!vmw_shader_id_ok(user_key, shader_type))
559 return -EINVAL;944 return -EINVAL;
560 945
561 return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_compat_shader,946 return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
562 vmw_compat_shader_key(user_key,947 vmw_shader_key(user_key, shader_type),
563 shader_type),948 list, &dummy);
564 list);
565}949}
566 950
567/**951/**
@@ -591,7 +975,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, · 23 unmodified lines
591 int ret;975 int ret;
592 struct vmw_resource *res;976 struct vmw_resource *res;
593 977
594 if (!vmw_compat_shader_id_ok(user_key, shader_type))978 if (!vmw_shader_id_ok(user_key, shader_type))
595 return -EINVAL;979 return -EINVAL;
596 980
597 /* Allocate and pin a DMA buffer */981 /* Allocate and pin a DMA buffer */
@@ -628,8 +1012,8 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, · 30 unmodified lines
628 if (unlikely(ret != 0))1012 if (unlikely(ret != 0))
629 goto no_reserve;1013 goto no_reserve;
630 1014
631 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_compat_shader,1015 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
632 vmw_compat_shader_key(user_key, shader_type),1016 vmw_shader_key(user_key, shader_type),
633 res, list);1017 res, list);
634 vmw_resource_unreference(&res);1018 vmw_resource_unreference(&res);
635no_reserve:1019no_reserve:
@@ -639,7 +1023,7 @@ out: · 3 unmodified lines
639}1023}
640 1024
641/**1025/**
642 * vmw_compat_shader_lookup - Look up a compat shader1026 * vmw_shader_lookup - Look up a compat shader
643 *1027 *
644 * @man: Pointer to the command buffer managed resource manager identifying1028 * @man: Pointer to the command buffer managed resource manager identifying
645 * the shader namespace.1029 * the shader namespace.
@@ -650,14 +1034,26 @@ out: · 4 unmodified lines
650 * found. An error pointer otherwise.1034 * found. An error pointer otherwise.
651 */1035 */
652struct vmw_resource *1036struct vmw_resource *
653vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man,1037vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
654 u32 user_key,1038 u32 user_key,
655 SVGA3dShaderType shader_type)1039 SVGA3dShaderType shader_type)
656{1040{
657 if (!vmw_compat_shader_id_ok(user_key, shader_type))1041 if (!vmw_shader_id_ok(user_key, shader_type))
658 return ERR_PTR(-EINVAL);1042 return ERR_PTR(-EINVAL);
659 1043
660 return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_compat_shader,1044 return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
661 vmw_compat_shader_key(user_key,1045 vmw_shader_key(user_key, shader_type));
662 shader_type));1046}
1047
1048int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
1049 struct drm_file *file_priv)
1050{
1051 struct drm_vmw_shader_create_arg *arg =
1052 (struct drm_vmw_shader_create_arg *)data;
1053
1054 return vmw_shader_define(dev, file_priv, arg->shader_type,
1055 arg->buffer_handle,
1056 arg->size, arg->offset,
1057 0, 0,
1058 &arg->shader_handle);
663}1059}
drivers/gpu/drm/vmwgfx/vmwgfx_so.c+555−0
@@ -0,0 +1,555 @@
1/**************************************************************************
2 * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include "vmwgfx_drv.h"
28#include "vmwgfx_resource_priv.h"
29#include "vmwgfx_so.h"
30#include "vmwgfx_binding.h"
31
32/*
33 * The currently only reason we need to keep track of views is that if we
34 * destroy a hardware surface, all views pointing to it must also be destroyed,
35 * otherwise the device will error.
36 * So in particuar if a surface is evicted, we must destroy all views pointing
37 * to it, and all context bindings of that view. Similarly we must restore
38 * the view bindings, views and surfaces pointed to by the views when a
39 * context is referenced in the command stream.
40 */
41
42/**
43 * struct vmw_view - view metadata
44 *
45 * @res: The struct vmw_resource we derive from
46 * @ctx: Non-refcounted pointer to the context this view belongs to.
47 * @srf: Refcounted pointer to the surface pointed to by this view.
48 * @cotable: Refcounted pointer to the cotable holding this view.
49 * @srf_head: List head for the surface-to-view list.
50 * @cotable_head: List head for the cotable-to_view list.
51 * @view_type: View type.
52 * @view_id: User-space per context view id. Currently used also as per
53 * context device view id.
54 * @cmd_size: Size of the SVGA3D define view command that we've copied from the
55 * command stream.
56 * @committed: Whether the view is actually created or pending creation at the
57 * device level.
58 * @cmd: The SVGA3D define view command copied from the command stream.
59 */
60struct vmw_view {
61 struct rcu_head rcu;
62 struct vmw_resource res;
63 struct vmw_resource *ctx; /* Immutable */
64 struct vmw_resource *srf; /* Immutable */
65 struct vmw_resource *cotable; /* Immutable */
66 struct list_head srf_head; /* Protected by binding_mutex */
67 struct list_head cotable_head; /* Protected by binding_mutex */
68 unsigned view_type; /* Immutable */
69 unsigned view_id; /* Immutable */
70 u32 cmd_size; /* Immutable */
71 bool committed; /* Protected by binding_mutex */
72 u32 cmd[1]; /* Immutable */
73};
74
75static int vmw_view_create(struct vmw_resource *res);
76static int vmw_view_destroy(struct vmw_resource *res);
77static void vmw_hw_view_destroy(struct vmw_resource *res);
78static void vmw_view_commit_notify(struct vmw_resource *res,
79 enum vmw_cmdbuf_res_state state);
80
81static const struct vmw_res_func vmw_view_func = {
82 .res_type = vmw_res_view,
83 .needs_backup = false,
84 .may_evict = false,
85 .type_name = "DX view",
86 .backup_placement = NULL,
87 .create = vmw_view_create,
88 .commit_notify = vmw_view_commit_notify,
89};
90
91/**
92 * struct vmw_view - view define command body stub
93 *
94 * @view_id: The device id of the view being defined
95 * @sid: The surface id of the view being defined
96 *
97 * This generic struct is used by the code to change @view_id and @sid of a
98 * saved view define command.
99 */
100struct vmw_view_define {
101 uint32 view_id;
102 uint32 sid;
103};
104
105/**
106 * vmw_view - Convert a struct vmw_resource to a struct vmw_view
107 *
108 * @res: Pointer to the resource to convert.
109 *
110 * Returns a pointer to a struct vmw_view.
111 */
112static struct vmw_view *vmw_view(struct vmw_resource *res)
113{
114 return container_of(res, struct vmw_view, res);
115}
116
117/**
118 * vmw_view_commit_notify - Notify that a view operation has been committed to
119 * hardware from a user-supplied command stream.
120 *
121 * @res: Pointer to the view resource.
122 * @state: Indicating whether a creation or removal has been committed.
123 *
124 */
125static void vmw_view_commit_notify(struct vmw_resource *res,
126 enum vmw_cmdbuf_res_state state)
127{
128 struct vmw_view *view = vmw_view(res);
129 struct vmw_private *dev_priv = res->dev_priv;
130
131 mutex_lock(&dev_priv->binding_mutex);
132 if (state == VMW_CMDBUF_RES_ADD) {
133 struct vmw_surface *srf = vmw_res_to_srf(view->srf);
134
135 list_add_tail(&view->srf_head, &srf->view_list);
136 vmw_cotable_add_resource(view->cotable, &view->cotable_head);
137 view->committed = true;
138 res->id = view->view_id;
139
140 } else {
141 list_del_init(&view->cotable_head);
142 list_del_init(&view->srf_head);
143 view->committed = false;
144 res->id = -1;
145 }
146 mutex_unlock(&dev_priv->binding_mutex);
147}
148
149/**
150 * vmw_view_create - Create a hardware view.
151 *
152 * @res: Pointer to the view resource.
153 *
154 * Create a hardware view. Typically used if that view has previously been
155 * destroyed by an eviction operation.
156 */
157static int vmw_view_create(struct vmw_resource *res)
158{
159 struct vmw_view *view = vmw_view(res);
160 struct vmw_surface *srf = vmw_res_to_srf(view->srf);
161 struct vmw_private *dev_priv = res->dev_priv;
162 struct {
163 SVGA3dCmdHeader header;
164 struct vmw_view_define body;
165 } *cmd;
166
167 mutex_lock(&dev_priv->binding_mutex);
168 if (!view->committed) {
169 mutex_unlock(&dev_priv->binding_mutex);
170 return 0;
171 }
172
173 cmd = vmw_fifo_reserve_dx(res->dev_priv, view->cmd_size,
174 view->ctx->id);
175 if (!cmd) {
176 DRM_ERROR("Failed reserving FIFO space for view creation.\n");
177 mutex_unlock(&dev_priv->binding_mutex);
178 return -ENOMEM;
179 }
180 memcpy(cmd, &view->cmd, view->cmd_size);
181 WARN_ON(cmd->body.view_id != view->view_id);
182 /* Sid may have changed due to surface eviction. */
183 WARN_ON(view->srf->id == SVGA3D_INVALID_ID);
184 cmd->body.sid = view->srf->id;
185 vmw_fifo_commit(res->dev_priv, view->cmd_size);
186 res->id = view->view_id;
187 list_add_tail(&view->srf_head, &srf->view_list);
188 vmw_cotable_add_resource(view->cotable, &view->cotable_head);
189 mutex_unlock(&dev_priv->binding_mutex);
190
191 return 0;
192}
193
194/**
195 * vmw_view_destroy - Destroy a hardware view.
196 *
197 * @res: Pointer to the view resource.
198 *
199 * Destroy a hardware view. Typically used on unexpected termination of the
200 * owning process or if the surface the view is pointing to is destroyed.
201 */
202static int vmw_view_destroy(struct vmw_resource *res)
203{
204 struct vmw_private *dev_priv = res->dev_priv;
205 struct vmw_view *view = vmw_view(res);
206 struct {
207 SVGA3dCmdHeader header;
208 union vmw_view_destroy body;
209 } *cmd;
210
211 WARN_ON_ONCE(!mutex_is_locked(&dev_priv->binding_mutex));
212 vmw_binding_res_list_scrub(&res->binding_head);
213
214 if (!view->committed || res->id == -1)
215 return 0;
216
217 cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), view->ctx->id);
218 if (!cmd) {
219 DRM_ERROR("Failed reserving FIFO space for view "
220 "destruction.\n");
221 return -ENOMEM;
222 }
223
224 cmd->header.id = vmw_view_destroy_cmds[view->view_type];
225 cmd->header.size = sizeof(cmd->body);
226 cmd->body.view_id = view->view_id;
227 vmw_fifo_commit(dev_priv, sizeof(*cmd));
228 res->id = -1;
229 list_del_init(&view->cotable_head);
230 list_del_init(&view->srf_head);
231
232 return 0;
233}
234
235/**
236 * vmw_hw_view_destroy - Destroy a hardware view as part of resource cleanup.
237 *
238 * @res: Pointer to the view resource.
239 *
240 * Destroy a hardware view if it's still present.
241 */
242static void vmw_hw_view_destroy(struct vmw_resource *res)
243{
244 struct vmw_private *dev_priv = res->dev_priv;
245
246 mutex_lock(&dev_priv->binding_mutex);
247 WARN_ON(vmw_view_destroy(res));
248 res->id = -1;
249 mutex_unlock(&dev_priv->binding_mutex);
250}
251
252/**
253 * vmw_view_key - Compute a view key suitable for the cmdbuf resource manager
254 *
255 * @user_key: The user-space id used for the view.
256 * @view_type: The view type.
257 *
258 * Destroy a hardware view if it's still present.
259 */
260static u32 vmw_view_key(u32 user_key, enum vmw_view_type view_type)
261{
262 return user_key | (view_type << 20);
263}
264
265/**
266 * vmw_view_id_ok - Basic view id and type range checks.
267 *
268 * @user_key: The user-space id used for the view.
269 * @view_type: The view type.
270 *
271 * Checks that the view id and type (typically provided by user-space) is
272 * valid.
273 */
274static bool vmw_view_id_ok(u32 user_key, enum vmw_view_type view_type)
275{
276 return (user_key < SVGA_COTABLE_MAX_IDS &&
277 view_type < vmw_view_max);
278}
279
280/**
281 * vmw_view_res_free - resource res_free callback for view resources
282 *
283 * @res: Pointer to a struct vmw_resource
284 *
285 * Frees memory and memory accounting held by a struct vmw_view.
286 */
287static void vmw_view_res_free(struct vmw_resource *res)
288{
289 struct vmw_view *view = vmw_view(res);
290 size_t size = offsetof(struct vmw_view, cmd) + view->cmd_size;
291 struct vmw_private *dev_priv = res->dev_priv;
292
293 vmw_resource_unreference(&view->cotable);
294 vmw_resource_unreference(&view->srf);
295 kfree_rcu(view, rcu);
296 ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
297}
298
299/**
300 * vmw_view_add - Create a view resource and stage it for addition
301 * as a command buffer managed resource.
302 *
303 * @man: Pointer to the compat shader manager identifying the shader namespace.
304 * @ctx: Pointer to a struct vmw_resource identifying the active context.
305 * @srf: Pointer to a struct vmw_resource identifying the surface the view
306 * points to.
307 * @view_type: The view type deduced from the view create command.
308 * @user_key: The key that is used to identify the shader. The key is
309 * unique to the view type and to the context.
310 * @cmd: Pointer to the view create command in the command stream.
311 * @cmd_size: Size of the view create command in the command stream.
312 * @list: Caller's list of staged command buffer resource actions.
313 */
314int vmw_view_add(struct vmw_cmdbuf_res_manager *man,
315 struct vmw_resource *ctx,
316 struct vmw_resource *srf,
317 enum vmw_view_type view_type,
318 u32 user_key,
319 const void *cmd,
320 size_t cmd_size,
321 struct list_head *list)
322{
323 static const size_t vmw_view_define_sizes[] = {
324 [vmw_view_sr] = sizeof(SVGA3dCmdDXDefineShaderResourceView),
325 [vmw_view_rt] = sizeof(SVGA3dCmdDXDefineRenderTargetView),
326 [vmw_view_ds] = sizeof(SVGA3dCmdDXDefineDepthStencilView)
327 };
328
329 struct vmw_private *dev_priv = ctx->dev_priv;
330 struct vmw_resource *res;
331 struct vmw_view *view;
332 size_t size;
333 int ret;
334
335 if (cmd_size != vmw_view_define_sizes[view_type] +
336 sizeof(SVGA3dCmdHeader)) {
337 DRM_ERROR("Illegal view create command size.\n");
338 return -EINVAL;
339 }
340
341 if (!vmw_view_id_ok(user_key, view_type)) {
342 DRM_ERROR("Illegal view add view id.\n");
343 return -EINVAL;
344 }
345
346 size = offsetof(struct vmw_view, cmd) + cmd_size;
347
348 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), size, false, true);
349 if (ret) {
350 if (ret != -ERESTARTSYS)
351 DRM_ERROR("Out of graphics memory for view"
352 " creation.\n");
353 return ret;
354 }
355
356 view = kmalloc(size, GFP_KERNEL);
357 if (!view) {
358 ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
359 return -ENOMEM;
360 }
361
362 res = &view->res;
363 view->ctx = ctx;
364 view->srf = vmw_resource_reference(srf);
365 view->cotable = vmw_context_cotable(ctx, vmw_view_cotables[view_type]);
366 view->view_type = view_type;
367 view->view_id = user_key;
368 view->cmd_size = cmd_size;
369 view->committed = false;
370 INIT_LIST_HEAD(&view->srf_head);
371 INIT_LIST_HEAD(&view->cotable_head);
372 memcpy(&view->cmd, cmd, cmd_size);
373 ret = vmw_resource_init(dev_priv, res, true,
374 vmw_view_res_free, &vmw_view_func);
375 if (ret)
376 goto out_resource_init;
377
378 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_view,
379 vmw_view_key(user_key, view_type),
380 res, list);
381 if (ret)
382 goto out_resource_init;
383
384 res->id = view->view_id;
385 vmw_resource_activate(res, vmw_hw_view_destroy);
386
387out_resource_init:
388 vmw_resource_unreference(&res);
389
390 return ret;
391}
392
393/**
394 * vmw_view_remove - Stage a view for removal.
395 *
396 * @man: Pointer to the view manager identifying the shader namespace.
397 * @user_key: The key that is used to identify the view. The key is
398 * unique to the view type.
399 * @view_type: View type
400 * @list: Caller's list of staged command buffer resource actions.
401 * @res_p: If the resource is in an already committed state, points to the
402 * struct vmw_resource on successful return. The pointer will be
403 * non ref-counted.
404 */
405int vmw_view_remove(struct vmw_cmdbuf_res_manager *man,
406 u32 user_key, enum vmw_view_type view_type,
407 struct list_head *list,
408 struct vmw_resource **res_p)
409{
410 if (!vmw_view_id_ok(user_key, view_type)) {
411 DRM_ERROR("Illegal view remove view id.\n");
412 return -EINVAL;
413 }
414
415 return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_view,
416 vmw_view_key(user_key, view_type),
417 list, res_p);
418}
419
420/**
421 * vmw_view_cotable_list_destroy - Evict all views belonging to a cotable.
422 *
423 * @dev_priv: Pointer to a device private struct.
424 * @list: List of views belonging to a cotable.
425 * @readback: Unused. Needed for function interface only.
426 *
427 * This function evicts all views belonging to a cotable.
428 * It must be called with the binding_mutex held, and the caller must hold
429 * a reference to the view resource. This is typically called before the
430 * cotable is paged out.
431 */
432void vmw_view_cotable_list_destroy(struct vmw_private *dev_priv,
433 struct list_head *list,
434 bool readback)
435{
436 struct vmw_view *entry, *next;
437
438 WARN_ON_ONCE(!mutex_is_locked(&dev_priv->binding_mutex));
439
440 list_for_each_entry_safe(entry, next, list, cotable_head)
441 WARN_ON(vmw_view_destroy(&entry->res));
442}
443
444/**
445 * vmw_view_surface_list_destroy - Evict all views pointing to a surface
446 *
447 * @dev_priv: Pointer to a device private struct.
448 * @list: List of views pointing to a surface.
449 *
450 * This function evicts all views pointing to a surface. This is typically
451 * called before the surface is evicted.
452 */
453void vmw_view_surface_list_destroy(struct vmw_private *dev_priv,
454 struct list_head *list)
455{
456 struct vmw_view *entry, *next;
457
458 WARN_ON_ONCE(!mutex_is_locked(&dev_priv->binding_mutex));
459
460 list_for_each_entry_safe(entry, next, list, srf_head)
461 WARN_ON(vmw_view_destroy(&entry->res));
462}
463
464/**
465 * vmw_view_srf - Return a non-refcounted pointer to the surface a view is
466 * pointing to.
467 *
468 * @res: pointer to a view resource.
469 *
470 * Note that the view itself is holding a reference, so as long
471 * the view resource is alive, the surface resource will be.
472 */
473struct vmw_resource *vmw_view_srf(struct vmw_resource *res)
474{
475 return vmw_view(res)->srf;
476}
477
478/**
479 * vmw_view_lookup - Look up a view.
480 *
481 * @man: The context's cmdbuf ref manager.
482 * @view_type: The view type.
483 * @user_key: The view user id.
484 *
485 * returns a refcounted pointer to a view or an error pointer if not found.
486 */
487struct vmw_resource *vmw_view_lookup(struct vmw_cmdbuf_res_manager *man,
488 enum vmw_view_type view_type,
489 u32 user_key)
490{
491 return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_view,
492 vmw_view_key(user_key, view_type));
493}
494
495const u32 vmw_view_destroy_cmds[] = {
496 [vmw_view_sr] = SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW,
497 [vmw_view_rt] = SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW,
498 [vmw_view_ds] = SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW,
499};
500
501const SVGACOTableType vmw_view_cotables[] = {
502 [vmw_view_sr] = SVGA_COTABLE_SRVIEW,
503 [vmw_view_rt] = SVGA_COTABLE_RTVIEW,
504 [vmw_view_ds] = SVGA_COTABLE_DSVIEW,
505};
506
507const SVGACOTableType vmw_so_cotables[] = {
508 [vmw_so_el] = SVGA_COTABLE_ELEMENTLAYOUT,
509 [vmw_so_bs] = SVGA_COTABLE_BLENDSTATE,
510 [vmw_so_ds] = SVGA_COTABLE_DEPTHSTENCIL,
511 [vmw_so_rs] = SVGA_COTABLE_RASTERIZERSTATE,
512 [vmw_so_ss] = SVGA_COTABLE_SAMPLER,
513 [vmw_so_so] = SVGA_COTABLE_STREAMOUTPUT
514};
515
516
517/* To remove unused function warning */
518static void vmw_so_build_asserts(void) __attribute__((used));
519
520
521/*
522 * This function is unused at run-time, and only used to dump various build
523 * asserts important for code optimization assumptions.
524 */
525static void vmw_so_build_asserts(void)
526{
527 /* Assert that our vmw_view_cmd_to_type() function is correct. */
528 BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW !=
529 SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 1);
530 BUILD_BUG_ON(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW !=
531 SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 2);
532 BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW !=
533 SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 3);
534 BUILD_BUG_ON(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW !=
535 SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 4);
536 BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW !=
537 SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 5);
538
539 /* Assert that our "one body fits all" assumption is valid */
540 BUILD_BUG_ON(sizeof(union vmw_view_destroy) != sizeof(u32));
541
542 /* Assert that the view key space can hold all view ids. */
543 BUILD_BUG_ON(SVGA_COTABLE_MAX_IDS >= ((1 << 20) - 1));
544
545 /*
546 * Assert that the offset of sid in all view define commands
547 * is what we assume it to be.
548 */
549 BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
550 offsetof(SVGA3dCmdDXDefineShaderResourceView, sid));
551 BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
552 offsetof(SVGA3dCmdDXDefineRenderTargetView, sid));
553 BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
554 offsetof(SVGA3dCmdDXDefineDepthStencilView, sid));
555}
drivers/gpu/drm/vmwgfx/vmwgfx_so.h+160−0
@@ -0,0 +1,160 @@
1/**************************************************************************
2 * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26#ifndef VMW_SO_H
27#define VMW_SO_H
28
29enum vmw_view_type {
30 vmw_view_sr,
31 vmw_view_rt,
32 vmw_view_ds,
33 vmw_view_max,
34};
35
36enum vmw_so_type {
37 vmw_so_el,
38 vmw_so_bs,
39 vmw_so_ds,
40 vmw_so_rs,
41 vmw_so_ss,
42 vmw_so_so,
43 vmw_so_max,
44};
45
46/**
47 * union vmw_view_destroy - view destruction command body
48 *
49 * @rtv: RenderTarget view destruction command body
50 * @srv: ShaderResource view destruction command body
51 * @dsv: DepthStencil view destruction command body
52 * @view_id: A single u32 view id.
53 *
54 * The assumption here is that all union members are really represented by a
55 * single u32 in the command stream. If that's not the case,
56 * the size of this union will not equal the size of an u32, and the
57 * assumption is invalid, and we detect that at compile time in the
58 * vmw_so_build_asserts() function.
59 */
60union vmw_view_destroy {
61 struct SVGA3dCmdDXDestroyRenderTargetView rtv;
62 struct SVGA3dCmdDXDestroyShaderResourceView srv;
63 struct SVGA3dCmdDXDestroyDepthStencilView dsv;
64 u32 view_id;
65};
66
67/* Map enum vmw_view_type to view destroy command ids*/
68extern const u32 vmw_view_destroy_cmds[];
69
70/* Map enum vmw_view_type to SVGACOTableType */
71extern const SVGACOTableType vmw_view_cotables[];
72
73/* Map enum vmw_so_type to SVGACOTableType */
74extern const SVGACOTableType vmw_so_cotables[];
75
76/*
77 * vmw_view_cmd_to_type - Return the view type for a create or destroy command
78 *
79 * @id: The SVGA3D command id.
80 *
81 * For a given view create or destroy command id, return the corresponding
82 * enum vmw_view_type. If the command is unknown, return vmw_view_max.
83 * The validity of the simplified calculation is verified in the
84 * vmw_so_build_asserts() function.
85 */
86static inline enum vmw_view_type vmw_view_cmd_to_type(u32 id)
87{
88 u32 tmp = (id - SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW) / 2;
89
90 if (tmp > (u32)vmw_view_max)
91 return vmw_view_max;
92
93 return (enum vmw_view_type) tmp;
94}
95
96/*
97 * vmw_so_cmd_to_type - Return the state object type for a
98 * create or destroy command
99 *
100 * @id: The SVGA3D command id.
101 *
102 * For a given state object create or destroy command id,
103 * return the corresponding enum vmw_so_type. If the command is uknown,
104 * return vmw_so_max. We should perhaps optimize this function using
105 * a similar strategy as vmw_view_cmd_to_type().
106 */
107static inline enum vmw_so_type vmw_so_cmd_to_type(u32 id)
108{
109 switch (id) {
110 case SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT:
111 case SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT:
112 return vmw_so_el;
113 case SVGA_3D_CMD_DX_DEFINE_BLEND_STATE:
114 case SVGA_3D_CMD_DX_DESTROY_BLEND_STATE:
115 return vmw_so_bs;
116 case SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE:
117 case SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE:
118 return vmw_so_ds;
119 case SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE:
120 case SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE:
121 return vmw_so_rs;
122 case SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE:
123 case SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE:
124 return vmw_so_ss;
125 case SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT:
126 case SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT:
127 return vmw_so_so;
128 default:
129 break;
130 }
131 return vmw_so_max;
132}
133
134/*
135 * View management - vmwgfx_so.c
136 */
137extern int vmw_view_add(struct vmw_cmdbuf_res_manager *man,
138 struct vmw_resource *ctx,
139 struct vmw_resource *srf,
140 enum vmw_view_type view_type,
141 u32 user_key,
142 const void *cmd,
143 size_t cmd_size,
144 struct list_head *list);
145
146extern int vmw_view_remove(struct vmw_cmdbuf_res_manager *man,
147 u32 user_key, enum vmw_view_type view_type,
148 struct list_head *list,
149 struct vmw_resource **res_p);
150
151extern void vmw_view_surface_list_destroy(struct vmw_private *dev_priv,
152 struct list_head *view_list);
153extern void vmw_view_cotable_list_destroy(struct vmw_private *dev_priv,
154 struct list_head *list,
155 bool readback);
156extern struct vmw_resource *vmw_view_srf(struct vmw_resource *res);
157extern struct vmw_resource *vmw_view_lookup(struct vmw_cmdbuf_res_manager *man,
158 enum vmw_view_type view_type,
159 u32 user_key);
160#endif
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c+1−0
@@ -561,6 +561,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) · 560 unmodified lines
561 true, /* a scanout buffer */561 true, /* a scanout buffer */
562 content_srf.mip_levels[0],562 content_srf.mip_levels[0],
563 content_srf.multisample_count,563 content_srf.multisample_count,
564 0,
564 display_base_size,565 display_base_size,
565 &display_srf);566 &display_srf);
566 if (unlikely(ret != 0)) {567 if (unlikely(ret != 0)) {
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c+87−22
@@ -27,9 +27,12 @@ · 26 unmodified lines
27 27
28#include "vmwgfx_drv.h"28#include "vmwgfx_drv.h"
29#include "vmwgfx_resource_priv.h"29#include "vmwgfx_resource_priv.h"
30#include "vmwgfx_so.h"
31#include "vmwgfx_binding.h"
30#include <ttm/ttm_placement.h>32#include <ttm/ttm_placement.h>
31#include "device_include/svga3d_surfacedefs.h"33#include "device_include/svga3d_surfacedefs.h"
32 34
35
33/**36/**
34 * struct vmw_user_surface - User-space visible surface resource37 * struct vmw_user_surface - User-space visible surface resource
35 *38 *
@@ -593,6 +596,7 @@ static int vmw_surface_init(struct vmw_private *dev_priv, · 557 unmodified lines
593 * surface validate.596 * surface validate.
594 */597 */
595 598
599 INIT_LIST_HEAD(&srf->view_list);
596 vmw_resource_activate(res, vmw_hw_surface_destroy);600 vmw_resource_activate(res, vmw_hw_surface_destroy);
597 return ret;601 return ret;
598}602}
@@ -723,6 +727,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, · 124 unmodified lines
723 desc = svga3dsurface_get_desc(req->format);727 desc = svga3dsurface_get_desc(req->format);
724 if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {728 if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
725 DRM_ERROR("Invalid surface format for surface creation.\n");729 DRM_ERROR("Invalid surface format for surface creation.\n");
730 DRM_ERROR("Format requested is: %d\n", req->format);
726 return -EINVAL;731 return -EINVAL;
727 }732 }
728 733
@@ -1018,12 +1023,16 @@ static int vmw_gb_surface_create(struct vmw_resource *res) · 289 unmodified lines
1018{1023{
1019 struct vmw_private *dev_priv = res->dev_priv;1024 struct vmw_private *dev_priv = res->dev_priv;
1020 struct vmw_surface *srf = vmw_res_to_srf(res);1025 struct vmw_surface *srf = vmw_res_to_srf(res);
1021 uint32_t cmd_len, submit_len;1026 uint32_t cmd_len, cmd_id, submit_len;
1022 int ret;1027 int ret;
1023 struct {1028 struct {
1024 SVGA3dCmdHeader header;1029 SVGA3dCmdHeader header;
1025 SVGA3dCmdDefineGBSurface body;1030 SVGA3dCmdDefineGBSurface body;
1026 } *cmd;1031 } *cmd;
1032 struct {
1033 SVGA3dCmdHeader header;
1034 SVGA3dCmdDefineGBSurface_v2 body;
1035 } *cmd2;
1027 1036
1028 if (likely(res->id != -1))1037 if (likely(res->id != -1))
1029 return 0;1038 return 0;
@@ -1040,9 +1049,19 @@ static int vmw_gb_surface_create(struct vmw_resource *res) · 10 unmodified lines
1040 goto out_no_fifo;1049 goto out_no_fifo;
1041 }1050 }
1042 1051
1043 cmd_len = sizeof(cmd->body);1052 if (srf->array_size > 0) {
1044 submit_len = sizeof(*cmd);1053 /* has_dx checked on creation time. */
1054 cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2;
1055 cmd_len = sizeof(cmd2->body);
1056 submit_len = sizeof(*cmd2);
1057 } else {
1058 cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE;
1059 cmd_len = sizeof(cmd->body);
1060 submit_len = sizeof(*cmd);
1061 }
1062
1045 cmd = vmw_fifo_reserve(dev_priv, submit_len);1063 cmd = vmw_fifo_reserve(dev_priv, submit_len);
1064 cmd2 = (typeof(cmd2))cmd;
1046 if (unlikely(cmd == NULL)) {1065 if (unlikely(cmd == NULL)) {
1047 DRM_ERROR("Failed reserving FIFO space for surface "1066 DRM_ERROR("Failed reserving FIFO space for surface "
1048 "creation.\n");1067 "creation.\n");
@@ -1050,17 +1069,33 @@ static int vmw_gb_surface_create(struct vmw_resource *res) · 1 unmodified line
1050 goto out_no_fifo;1069 goto out_no_fifo;
1051 }1070 }
1052 1071
1053 cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SURFACE;1072 if (srf->array_size > 0) {
1054 cmd->header.size = cmd_len;1073 cmd2->header.id = cmd_id;
1055 cmd->body.sid = srf->res.id;1074 cmd2->header.size = cmd_len;
1056 cmd->body.surfaceFlags = srf->flags;1075 cmd2->body.sid = srf->res.id;
1057 cmd->body.format = srf->format;1076 cmd2->body.surfaceFlags = srf->flags;
1058 cmd->body.numMipLevels = srf->mip_levels[0];1077 cmd2->body.format = cpu_to_le32(srf->format);
1059 cmd->body.multisampleCount = srf->multisample_count;1078 cmd2->body.numMipLevels = srf->mip_levels[0];
1060 cmd->body.autogenFilter = srf->autogen_filter;1079 cmd2->body.multisampleCount = srf->multisample_count;
1061 cmd->body.size.width = srf->base_size.width;1080 cmd2->body.autogenFilter = srf->autogen_filter;
1062 cmd->body.size.height = srf->base_size.height;1081 cmd2->body.size.width = srf->base_size.width;
1063 cmd->body.size.depth = srf->base_size.depth;1082 cmd2->body.size.height = srf->base_size.height;
1083 cmd2->body.size.depth = srf->base_size.depth;
1084 cmd2->body.arraySize = srf->array_size;
1085 } else {
1086 cmd->header.id = cmd_id;
1087 cmd->header.size = cmd_len;
1088 cmd->body.sid = srf->res.id;
1089 cmd->body.surfaceFlags = srf->flags;
1090 cmd->body.format = cpu_to_le32(srf->format);
1091 cmd->body.numMipLevels = srf->mip_levels[0];
1092 cmd->body.multisampleCount = srf->multisample_count;
1093 cmd->body.autogenFilter = srf->autogen_filter;
1094 cmd->body.size.width = srf->base_size.width;
1095 cmd->body.size.height = srf->base_size.height;
1096 cmd->body.size.depth = srf->base_size.depth;
1097 }
1098
1064 vmw_fifo_commit(dev_priv, submit_len);1099 vmw_fifo_commit(dev_priv, submit_len);
1065 1100
1066 return 0;1101 return 0;
@@ -1188,6 +1223,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, · 121 unmodified lines
1188static int vmw_gb_surface_destroy(struct vmw_resource *res)1223static int vmw_gb_surface_destroy(struct vmw_resource *res)
1189{1224{
1190 struct vmw_private *dev_priv = res->dev_priv;1225 struct vmw_private *dev_priv = res->dev_priv;
1226 struct vmw_surface *srf = vmw_res_to_srf(res);
1191 struct {1227 struct {
1192 SVGA3dCmdHeader header;1228 SVGA3dCmdHeader header;
1193 SVGA3dCmdDestroyGBSurface body;1229 SVGA3dCmdDestroyGBSurface body;
@@ -1197,7 +1233,8 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) · 3 unmodified lines
1197 return 0;1233 return 0;
1198 1234
1199 mutex_lock(&dev_priv->binding_mutex);1235 mutex_lock(&dev_priv->binding_mutex);
1200 vmw_context_binding_res_list_scrub(&res->binding_head);1236 vmw_view_surface_list_destroy(dev_priv, &srf->view_list);
1237 vmw_binding_res_list_scrub(&res->binding_head);
1201 1238
1202 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));1239 cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
1203 if (unlikely(cmd == NULL)) {1240 if (unlikely(cmd == NULL)) {
@@ -1259,6 +1296,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, · 55 unmodified lines
1259 req->drm_surface_flags & drm_vmw_surface_flag_scanout,1296 req->drm_surface_flags & drm_vmw_surface_flag_scanout,
1260 req->mip_levels,1297 req->mip_levels,
1261 req->multisample_count,1298 req->multisample_count,
1299 req->array_size,
1262 req->base_size,1300 req->base_size,
1263 &srf);1301 &srf);
1264 if (unlikely(ret != 0))1302 if (unlikely(ret != 0))
@@ -1275,10 +1313,17 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, · 10 unmodified lines
1275 res = &user_srf->srf.res;1313 res = &user_srf->srf.res;
1276 1314
1277 1315
1278 if (req->buffer_handle != SVGA3D_INVALID_ID)1316 if (req->buffer_handle != SVGA3D_INVALID_ID) {
1279 ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,1317 ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
1280 &res->backup);1318 &res->backup);
1281 else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)1319 if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE <
1320 res->backup_size) {
1321 DRM_ERROR("Surface backup buffer is too small.\n");
1322 vmw_dmabuf_unreference(&res->backup);
1323 ret = -EINVAL;
1324 goto out_unlock;
1325 }
1326 } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)
1282 ret = vmw_user_dmabuf_alloc(dev_priv, tfile,1327 ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
1283 res->backup_size,1328 res->backup_size,
1284 req->drm_surface_flags &1329 req->drm_surface_flags &
@@ -1378,6 +1423,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, · 93 unmodified lines
1378 rep->creq.drm_surface_flags = 0;1423 rep->creq.drm_surface_flags = 0;
1379 rep->creq.multisample_count = srf->multisample_count;1424 rep->creq.multisample_count = srf->multisample_count;
1380 rep->creq.autogen_filter = srf->autogen_filter;1425 rep->creq.autogen_filter = srf->autogen_filter;
1426 rep->creq.array_size = srf->array_size;
1381 rep->creq.buffer_handle = backup_handle;1427 rep->creq.buffer_handle = backup_handle;
1382 rep->creq.base_size = srf->base_size;1428 rep->creq.base_size = srf->base_size;
1383 rep->crep.handle = user_srf->prime.base.hash.key;1429 rep->crep.handle = user_srf->prime.base.hash.key;
@@ -1404,6 +1450,7 @@ out_bad_resource: · 20 unmodified lines
1404 * @for_scanout: true if inteded to be used for scanout buffer1450 * @for_scanout: true if inteded to be used for scanout buffer
1405 * @num_mip_levels: number of MIP levels1451 * @num_mip_levels: number of MIP levels
1406 * @multisample_count:1452 * @multisample_count:
1453 * @array_size: Surface array size.
1407 * @size: width, heigh, depth of the surface requested1454 * @size: width, heigh, depth of the surface requested
1408 * @user_srf_out: allocated user_srf. Set to NULL on failure.1455 * @user_srf_out: allocated user_srf. Set to NULL on failure.
1409 *1456 *
@@ -1419,6 +1466,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, · 9 unmodified lines
1419 bool for_scanout,1466 bool for_scanout,
1420 uint32_t num_mip_levels,1467 uint32_t num_mip_levels,
1421 uint32_t multisample_count,1468 uint32_t multisample_count,
1469 uint32_t array_size,
1422 struct drm_vmw_size size,1470 struct drm_vmw_size size,
1423 struct vmw_surface **srf_out)1471 struct vmw_surface **srf_out)
1424{1472{
@@ -1426,7 +1474,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, · 1 unmodified line
1426 struct vmw_user_surface *user_srf;1474 struct vmw_user_surface *user_srf;
1427 struct vmw_surface *srf;1475 struct vmw_surface *srf;
1428 int ret;1476 int ret;
1429 1477 u32 num_layers;
1430 1478
1431 *srf_out = NULL;1479 *srf_out = NULL;
1432 1480
@@ -1445,6 +1493,12 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, · 12 unmodified lines
1445 }1493 }
1446 }1494 }
1447 1495
1496 /* array_size must be null for non-GL3 host. */
1497 if (array_size > 0 && !dev_priv->has_dx) {
1498 DRM_ERROR("Tried to create DX surface on non-DX host.\n");
1499 return -EINVAL;
1500 }
1501
1448 ret = ttm_read_lock(&dev_priv->reservation_sem, true);1502 ret = ttm_read_lock(&dev_priv->reservation_sem, true);
1449 if (unlikely(ret != 0))1503 if (unlikely(ret != 0))
1450 return ret;1504 return ret;
@@ -1481,10 +1535,21 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, · 30 unmodified lines
1481 srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;1535 srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
1482 srf->multisample_count = multisample_count;1536 srf->multisample_count = multisample_count;
1483 1537
1484 srf->res.backup_size = svga3dsurface_get_serialized_size(srf->format,1538 if (array_size)
1485 srf->base_size,1539 num_layers = array_size;
1486 srf->mip_levels[0],1540 else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP)
1487 srf->flags & SVGA3D_SURFACE_CUBEMAP);1541 num_layers = SVGA3D_MAX_SURFACE_FACES;
1542 else
1543 num_layers = 1;
1544
1545 srf->res.backup_size =
1546 svga3dsurface_get_serialized_size(srf->format,
1547 srf->base_size,
1548 srf->mip_levels[0],
1549 num_layers);
1550
1551 if (srf->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
1552 srf->res.backup_size += sizeof(SVGA3dDXSOState);
1488 1553
1489 if (dev_priv->active_display_unit == vmw_du_screen_target &&1554 if (dev_priv->active_display_unit == vmw_du_screen_target &&
1490 for_scanout)1555 for_scanout)
include/uapi/drm/vmwgfx_drm.h+32−3
@@ -64,6 +64,7 @@ · 63 unmodified lines
64#define DRM_VMW_GB_SURFACE_CREATE 2364#define DRM_VMW_GB_SURFACE_CREATE 23
65#define DRM_VMW_GB_SURFACE_REF 2465#define DRM_VMW_GB_SURFACE_REF 24
66#define DRM_VMW_SYNCCPU 2566#define DRM_VMW_SYNCCPU 25
67#define DRM_VMW_CREATE_EXTENDED_CONTEXT 26
67 68
68/*************************************************************************/69/*************************************************************************/
69/**70/**
@@ -89,6 +90,7 @@ · 19 unmodified lines
89#define DRM_VMW_PARAM_MAX_MOB_MEMORY 990#define DRM_VMW_PARAM_MAX_MOB_MEMORY 9
90#define DRM_VMW_PARAM_MAX_MOB_SIZE 1091#define DRM_VMW_PARAM_MAX_MOB_SIZE 10
91#define DRM_VMW_PARAM_SCREEN_TARGET 1192#define DRM_VMW_PARAM_SCREEN_TARGET 11
93#define DRM_VMW_PARAM_DX 12
92 94
93/**95/**
94 * enum drm_vmw_handle_type - handle type for ref ioctls96 * enum drm_vmw_handle_type - handle type for ref ioctls
@@ -297,7 +299,7 @@ union drm_vmw_surface_reference_arg { · 202 unmodified lines
297 * Argument to the DRM_VMW_EXECBUF Ioctl.299 * Argument to the DRM_VMW_EXECBUF Ioctl.
298 */300 */
299 301
300#define DRM_VMW_EXECBUF_VERSION 1302#define DRM_VMW_EXECBUF_VERSION 2
301 303
302struct drm_vmw_execbuf_arg {304struct drm_vmw_execbuf_arg {
303 uint64_t commands;305 uint64_t commands;
@@ -306,6 +308,8 @@ struct drm_vmw_execbuf_arg { · 2 unmodified lines
306 uint64_t fence_rep;308 uint64_t fence_rep;
307 uint32_t version;309 uint32_t version;
308 uint32_t flags;310 uint32_t flags;
311 uint32_t context_handle;
312 uint32_t pad64;
309};313};
310 314
311/**315/**
@@ -826,7 +830,6 @@ struct drm_vmw_update_layout_arg { · 514 unmodified lines
826enum drm_vmw_shader_type {830enum drm_vmw_shader_type {
827 drm_vmw_shader_type_vs = 0,831 drm_vmw_shader_type_vs = 0,
828 drm_vmw_shader_type_ps,832 drm_vmw_shader_type_ps,
829 drm_vmw_shader_type_gs
830};833};
831 834
832 835
@@ -908,6 +911,8 @@ enum drm_vmw_surface_flags { · 75 unmodified lines
908 * @buffer_handle Buffer handle of backup buffer. SVGA3D_INVALID_ID911 * @buffer_handle Buffer handle of backup buffer. SVGA3D_INVALID_ID
909 * if none.912 * if none.
910 * @base_size Size of the base mip level for all faces.913 * @base_size Size of the base mip level for all faces.
914 * @array_size Must be zero for non-DX hardware, and if non-zero
915 * svga3d_flags must have proper bind flags setup.
911 *916 *
912 * Input argument to the DRM_VMW_GB_SURFACE_CREATE Ioctl.917 * Input argument to the DRM_VMW_GB_SURFACE_CREATE Ioctl.
913 * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.918 * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.
@@ -920,7 +925,7 @@ struct drm_vmw_gb_surface_create_req { · 6 unmodified lines
920 uint32_t multisample_count;925 uint32_t multisample_count;
921 uint32_t autogen_filter;926 uint32_t autogen_filter;
922 uint32_t buffer_handle;927 uint32_t buffer_handle;
923 uint32_t pad64;928 uint32_t array_size;
924 struct drm_vmw_size base_size;929 struct drm_vmw_size base_size;
925};930};
926 931
@@ -1060,4 +1065,28 @@ struct drm_vmw_synccpu_arg { · 133 unmodified lines
1060 uint32_t pad64;1065 uint32_t pad64;
1061};1066};
1062 1067
1068/*************************************************************************/
1069/**
1070 * DRM_VMW_CREATE_EXTENDED_CONTEXT - Create a host context.
1071 *
1072 * Allocates a device unique context id, and queues a create context command
1073 * for the host. Does not wait for host completion.
1074 */
1075enum drm_vmw_extended_context {
1076 drm_vmw_context_legacy,
1077 drm_vmw_context_dx
1078};
1079
1080/**
1081 * union drm_vmw_extended_context_arg
1082 *
1083 * @req: Context type.
1084 * @rep: Context identifier.
1085 *
1086 * Argument to the DRM_VMW_CREATE_EXTENDED_CONTEXT Ioctl.
1087 */
1088union drm_vmw_extended_context_arg {
1089 enum drm_vmw_extended_context req;
1090 struct drm_vmw_context_arg rep;
1091};
1063#endif1092#endif