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 |