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);