1 /**************************************************************************
3 * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include "vmwgfx_drv.h"
29 #include "vmwgfx_resource_priv.h"
30 #include "ttm/ttm_placement.h"
32 struct vmw_user_context
{
33 struct ttm_base_object base
;
34 struct vmw_resource res
;
37 static void vmw_user_context_free(struct vmw_resource
*res
);
38 static struct vmw_resource
*
39 vmw_user_context_base_to_res(struct ttm_base_object
*base
);
41 static uint64_t vmw_user_context_size
;
43 static const struct vmw_user_resource_conv user_context_conv
= {
44 .object_type
= VMW_RES_CONTEXT
,
45 .base_obj_to_res
= vmw_user_context_base_to_res
,
46 .res_free
= vmw_user_context_free
49 const struct vmw_user_resource_conv
*user_context_converter
=
53 static const struct vmw_res_func vmw_legacy_context_func
= {
54 .res_type
= vmw_res_context
,
55 .needs_backup
= false,
57 .type_name
= "legacy contexts",
58 .backup_placement
= NULL
,
69 static void vmw_hw_context_destroy(struct vmw_resource
*res
)
72 struct vmw_private
*dev_priv
= res
->dev_priv
;
74 SVGA3dCmdHeader header
;
75 SVGA3dCmdDestroyContext body
;
79 vmw_execbuf_release_pinned_bo(dev_priv
);
80 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
81 if (unlikely(cmd
== NULL
)) {
82 DRM_ERROR("Failed reserving FIFO space for surface "
87 cmd
->header
.id
= cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY
);
88 cmd
->header
.size
= cpu_to_le32(sizeof(cmd
->body
));
89 cmd
->body
.cid
= cpu_to_le32(res
->id
);
91 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
92 vmw_3d_resource_dec(dev_priv
, false);
95 static int vmw_context_init(struct vmw_private
*dev_priv
,
96 struct vmw_resource
*res
,
97 void (*res_free
) (struct vmw_resource
*res
))
102 SVGA3dCmdHeader header
;
103 SVGA3dCmdDefineContext body
;
106 ret
= vmw_resource_init(dev_priv
, res
, false,
107 res_free
, &vmw_legacy_context_func
);
109 if (unlikely(ret
!= 0)) {
110 DRM_ERROR("Failed to allocate a resource id.\n");
114 if (unlikely(res
->id
>= SVGA3D_MAX_CONTEXT_IDS
)) {
115 DRM_ERROR("Out of hw context ids.\n");
116 vmw_resource_unreference(&res
);
120 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
121 if (unlikely(cmd
== NULL
)) {
122 DRM_ERROR("Fifo reserve failed.\n");
123 vmw_resource_unreference(&res
);
127 cmd
->header
.id
= cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE
);
128 cmd
->header
.size
= cpu_to_le32(sizeof(cmd
->body
));
129 cmd
->body
.cid
= cpu_to_le32(res
->id
);
131 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
132 (void) vmw_3d_resource_inc(dev_priv
, false);
133 vmw_resource_activate(res
, vmw_hw_context_destroy
);
137 if (res_free
== NULL
)
144 struct vmw_resource
*vmw_context_alloc(struct vmw_private
*dev_priv
)
146 struct vmw_resource
*res
= kmalloc(sizeof(*res
), GFP_KERNEL
);
149 if (unlikely(res
== NULL
))
152 ret
= vmw_context_init(dev_priv
, res
, NULL
);
154 return (ret
== 0) ? res
: NULL
;
158 * User-space context management:
161 static struct vmw_resource
*
162 vmw_user_context_base_to_res(struct ttm_base_object
*base
)
164 return &(container_of(base
, struct vmw_user_context
, base
)->res
);
167 static void vmw_user_context_free(struct vmw_resource
*res
)
169 struct vmw_user_context
*ctx
=
170 container_of(res
, struct vmw_user_context
, res
);
171 struct vmw_private
*dev_priv
= res
->dev_priv
;
173 ttm_base_object_kfree(ctx
, base
);
174 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
175 vmw_user_context_size
);
179 * This function is called when user space has no more references on the
180 * base object. It releases the base-object's reference on the resource object.
183 static void vmw_user_context_base_release(struct ttm_base_object
**p_base
)
185 struct ttm_base_object
*base
= *p_base
;
186 struct vmw_user_context
*ctx
=
187 container_of(base
, struct vmw_user_context
, base
);
188 struct vmw_resource
*res
= &ctx
->res
;
191 vmw_resource_unreference(&res
);
194 int vmw_context_destroy_ioctl(struct drm_device
*dev
, void *data
,
195 struct drm_file
*file_priv
)
197 struct drm_vmw_context_arg
*arg
= (struct drm_vmw_context_arg
*)data
;
198 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
200 return ttm_ref_object_base_unref(tfile
, arg
->cid
, TTM_REF_USAGE
);
203 int vmw_context_define_ioctl(struct drm_device
*dev
, void *data
,
204 struct drm_file
*file_priv
)
206 struct vmw_private
*dev_priv
= vmw_priv(dev
);
207 struct vmw_user_context
*ctx
;
208 struct vmw_resource
*res
;
209 struct vmw_resource
*tmp
;
210 struct drm_vmw_context_arg
*arg
= (struct drm_vmw_context_arg
*)data
;
211 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
212 struct vmw_master
*vmaster
= vmw_master(file_priv
->master
);
217 * Approximate idr memory usage with 128 bytes. It will be limited
218 * by maximum number_of contexts anyway.
221 if (unlikely(vmw_user_context_size
== 0))
222 vmw_user_context_size
= ttm_round_pot(sizeof(*ctx
)) + 128;
224 ret
= ttm_read_lock(&vmaster
->lock
, true);
225 if (unlikely(ret
!= 0))
228 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
),
229 vmw_user_context_size
,
231 if (unlikely(ret
!= 0)) {
232 if (ret
!= -ERESTARTSYS
)
233 DRM_ERROR("Out of graphics memory for context"
238 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
239 if (unlikely(ctx
== NULL
)) {
240 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
241 vmw_user_context_size
);
247 ctx
->base
.shareable
= false;
248 ctx
->base
.tfile
= NULL
;
251 * From here on, the destructor takes over resource freeing.
254 ret
= vmw_context_init(dev_priv
, res
, vmw_user_context_free
);
255 if (unlikely(ret
!= 0))
258 tmp
= vmw_resource_reference(&ctx
->res
);
259 ret
= ttm_base_object_init(tfile
, &ctx
->base
, false, VMW_RES_CONTEXT
,
260 &vmw_user_context_base_release
, NULL
);
262 if (unlikely(ret
!= 0)) {
263 vmw_resource_unreference(&tmp
);
267 arg
->cid
= ctx
->base
.hash
.key
;
269 vmw_resource_unreference(&res
);
271 ttm_read_unlock(&vmaster
->lock
);