Subversion Repositories Kolibri OS

Rev

Rev 4569 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4075 Serge 1
/**************************************************************************
2
 *
3
 * Copyright © 2009-2012 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
#include "vmwgfx_drv.h"
29
#include "vmwgfx_resource_priv.h"
30
#include "ttm/ttm_placement.h"
31
 
32
struct vmw_user_context {
33
	struct ttm_base_object base;
34
	struct vmw_resource res;
35
};
36
 
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);
40
 
41
static uint64_t vmw_user_context_size;
42
 
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
47
};
48
 
49
const struct vmw_user_resource_conv *user_context_converter =
50
	&user_context_conv;
51
 
52
 
53
static const struct vmw_res_func vmw_legacy_context_func = {
54
	.res_type = vmw_res_context,
55
	.needs_backup = false,
56
	.may_evict = false,
57
	.type_name = "legacy contexts",
58
	.backup_placement = NULL,
59
	.create = NULL,
60
	.destroy = NULL,
61
	.bind = NULL,
62
	.unbind = NULL
63
};
64
 
65
/**
66
 * Context management:
67
 */
68
 
69
static void vmw_hw_context_destroy(struct vmw_resource *res)
70
{
71
 
72
	struct vmw_private *dev_priv = res->dev_priv;
73
	struct {
74
		SVGA3dCmdHeader header;
75
		SVGA3dCmdDestroyContext body;
76
	} *cmd;
77
 
78
 
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 "
83
			  "destruction.\n");
84
		return;
85
	}
86
 
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);
90
 
91
	vmw_fifo_commit(dev_priv, sizeof(*cmd));
92
	vmw_3d_resource_dec(dev_priv, false);
93
}
94
 
95
static int vmw_context_init(struct vmw_private *dev_priv,
96
			    struct vmw_resource *res,
97
			    void (*res_free) (struct vmw_resource *res))
98
{
99
	int ret;
100
 
101
	struct {
102
		SVGA3dCmdHeader header;
103
		SVGA3dCmdDefineContext body;
104
	} *cmd;
105
 
106
	ret = vmw_resource_init(dev_priv, res, false,
107
				res_free, &vmw_legacy_context_func);
108
 
109
	if (unlikely(ret != 0)) {
110
		DRM_ERROR("Failed to allocate a resource id.\n");
111
		goto out_early;
112
	}
113
 
114
	if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
115
		DRM_ERROR("Out of hw context ids.\n");
116
		vmw_resource_unreference(&res);
117
		return -ENOMEM;
118
	}
119
 
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);
124
		return -ENOMEM;
125
	}
126
 
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);
130
 
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);
134
	return 0;
135
 
136
out_early:
137
	if (res_free == NULL)
138
		kfree(res);
139
	else
140
		res_free(res);
141
	return ret;
142
}
143
 
144
struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
145
{
146
	struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
147
	int ret;
148
 
149
	if (unlikely(res == NULL))
150
		return NULL;
151
 
152
	ret = vmw_context_init(dev_priv, res, NULL);
153
 
154
	return (ret == 0) ? res : NULL;
155
}
156
 
157
/**
158
 * User-space context management:
159
 */
160
 
161
static struct vmw_resource *
162
vmw_user_context_base_to_res(struct ttm_base_object *base)
163
{
164
	return &(container_of(base, struct vmw_user_context, base)->res);
165
}
166
 
167
static void vmw_user_context_free(struct vmw_resource *res)
168
{
169
	struct vmw_user_context *ctx =
170
	    container_of(res, struct vmw_user_context, res);
171
	struct vmw_private *dev_priv = res->dev_priv;
172
 
173
//   ttm_base_object_kfree(ctx, base);
174
	ttm_mem_global_free(vmw_mem_glob(dev_priv),
175
			    vmw_user_context_size);
176
}
177
 
178
/**
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.
181
 */
182
 
183
static void vmw_user_context_base_release(struct ttm_base_object **p_base)
184
{
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;
189
 
190
	*p_base = NULL;
191
	vmw_resource_unreference(&res);
192
}
193
 
194
#if 0
195
int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
196
			      struct drm_file *file_priv)
197
{
198
	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
199
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
200
 
201
	return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
202
}
203
 
204
int vmw_context_define_ioctl(struct drm_device *dev, void *data,
205
			     struct drm_file *file_priv)
206
{
207
	struct vmw_private *dev_priv = vmw_priv(dev);
208
	struct vmw_user_context *ctx;
209
	struct vmw_resource *res;
210
	struct vmw_resource *tmp;
211
	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
212
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
213
	struct vmw_master *vmaster = vmw_master(file_priv->master);
214
	int ret;
215
 
216
 
217
	/*
218
	 * Approximate idr memory usage with 128 bytes. It will be limited
219
	 * by maximum number_of contexts anyway.
220
	 */
221
 
222
	if (unlikely(vmw_user_context_size == 0))
223
		vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
224
 
225
	ret = ttm_read_lock(&vmaster->lock, true);
226
	if (unlikely(ret != 0))
227
		return ret;
228
 
229
	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
230
				   vmw_user_context_size,
231
				   false, true);
232
	if (unlikely(ret != 0)) {
233
		if (ret != -ERESTARTSYS)
234
			DRM_ERROR("Out of graphics memory for context"
235
				  " creation.\n");
236
		goto out_unlock;
237
	}
238
 
239
	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
240
	if (unlikely(ctx == NULL)) {
241
		ttm_mem_global_free(vmw_mem_glob(dev_priv),
242
				    vmw_user_context_size);
243
		ret = -ENOMEM;
244
		goto out_unlock;
245
	}
246
 
247
	res = &ctx->res;
248
	ctx->base.shareable = false;
249
	ctx->base.tfile = NULL;
250
 
251
	/*
252
	 * From here on, the destructor takes over resource freeing.
253
	 */
254
 
255
	ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
256
	if (unlikely(ret != 0))
257
		goto out_unlock;
258
 
259
	tmp = vmw_resource_reference(&ctx->res);
260
	ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
261
				   &vmw_user_context_base_release, NULL);
262
 
263
	if (unlikely(ret != 0)) {
264
		vmw_resource_unreference(&tmp);
265
		goto out_err;
266
	}
267
 
268
	arg->cid = ctx->base.hash.key;
269
out_err:
270
	vmw_resource_unreference(&res);
271
out_unlock:
272
	ttm_read_unlock(&vmaster->lock);
273
	return ret;
274
 
275
}
276
#endif