1 1.2 riastrad /* $NetBSD: vmwgfx_shader.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 1.2 riastrad 3 1.3 riastrad // SPDX-License-Identifier: GPL-2.0 OR MIT 4 1.1 riastrad /************************************************************************** 5 1.1 riastrad * 6 1.3 riastrad * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the 10 1.1 riastrad * "Software"), to deal in the Software without restriction, including 11 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 12 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 13 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 14 1.1 riastrad * the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the 17 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 18 1.1 riastrad * of the Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad **************************************************************************/ 29 1.1 riastrad 30 1.2 riastrad #include <sys/cdefs.h> 31 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_shader.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 32 1.2 riastrad 33 1.3 riastrad #include <drm/ttm/ttm_placement.h> 34 1.3 riastrad 35 1.1 riastrad #include "vmwgfx_drv.h" 36 1.1 riastrad #include "vmwgfx_resource_priv.h" 37 1.2 riastrad #include "vmwgfx_binding.h" 38 1.1 riastrad 39 1.1 riastrad struct vmw_shader { 40 1.1 riastrad struct vmw_resource res; 41 1.1 riastrad SVGA3dShaderType type; 42 1.1 riastrad uint32_t size; 43 1.2 riastrad uint8_t num_input_sig; 44 1.2 riastrad uint8_t num_output_sig; 45 1.1 riastrad }; 46 1.1 riastrad 47 1.1 riastrad struct vmw_user_shader { 48 1.1 riastrad struct ttm_base_object base; 49 1.1 riastrad struct vmw_shader shader; 50 1.1 riastrad }; 51 1.1 riastrad 52 1.2 riastrad struct vmw_dx_shader { 53 1.2 riastrad struct vmw_resource res; 54 1.2 riastrad struct vmw_resource *ctx; 55 1.2 riastrad struct vmw_resource *cotable; 56 1.2 riastrad u32 id; 57 1.2 riastrad bool committed; 58 1.2 riastrad struct list_head cotable_head; 59 1.1 riastrad }; 60 1.1 riastrad 61 1.2 riastrad static uint64_t vmw_user_shader_size; 62 1.2 riastrad static uint64_t vmw_shader_size; 63 1.2 riastrad static size_t vmw_shader_dx_size; 64 1.1 riastrad 65 1.1 riastrad static void vmw_user_shader_free(struct vmw_resource *res); 66 1.1 riastrad static struct vmw_resource * 67 1.1 riastrad vmw_user_shader_base_to_res(struct ttm_base_object *base); 68 1.1 riastrad 69 1.1 riastrad static int vmw_gb_shader_create(struct vmw_resource *res); 70 1.1 riastrad static int vmw_gb_shader_bind(struct vmw_resource *res, 71 1.1 riastrad struct ttm_validate_buffer *val_buf); 72 1.1 riastrad static int vmw_gb_shader_unbind(struct vmw_resource *res, 73 1.1 riastrad bool readback, 74 1.1 riastrad struct ttm_validate_buffer *val_buf); 75 1.1 riastrad static int vmw_gb_shader_destroy(struct vmw_resource *res); 76 1.1 riastrad 77 1.2 riastrad static int vmw_dx_shader_create(struct vmw_resource *res); 78 1.2 riastrad static int vmw_dx_shader_bind(struct vmw_resource *res, 79 1.2 riastrad struct ttm_validate_buffer *val_buf); 80 1.2 riastrad static int vmw_dx_shader_unbind(struct vmw_resource *res, 81 1.2 riastrad bool readback, 82 1.2 riastrad struct ttm_validate_buffer *val_buf); 83 1.2 riastrad static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 84 1.2 riastrad enum vmw_cmdbuf_res_state state); 85 1.2 riastrad static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type); 86 1.2 riastrad static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type); 87 1.1 riastrad static uint64_t vmw_user_shader_size; 88 1.1 riastrad 89 1.1 riastrad static const struct vmw_user_resource_conv user_shader_conv = { 90 1.1 riastrad .object_type = VMW_RES_SHADER, 91 1.1 riastrad .base_obj_to_res = vmw_user_shader_base_to_res, 92 1.1 riastrad .res_free = vmw_user_shader_free 93 1.1 riastrad }; 94 1.1 riastrad 95 1.1 riastrad const struct vmw_user_resource_conv *user_shader_converter = 96 1.1 riastrad &user_shader_conv; 97 1.1 riastrad 98 1.1 riastrad 99 1.1 riastrad static const struct vmw_res_func vmw_gb_shader_func = { 100 1.1 riastrad .res_type = vmw_res_shader, 101 1.1 riastrad .needs_backup = true, 102 1.1 riastrad .may_evict = true, 103 1.3 riastrad .prio = 3, 104 1.3 riastrad .dirty_prio = 3, 105 1.1 riastrad .type_name = "guest backed shaders", 106 1.1 riastrad .backup_placement = &vmw_mob_placement, 107 1.1 riastrad .create = vmw_gb_shader_create, 108 1.1 riastrad .destroy = vmw_gb_shader_destroy, 109 1.1 riastrad .bind = vmw_gb_shader_bind, 110 1.1 riastrad .unbind = vmw_gb_shader_unbind 111 1.1 riastrad }; 112 1.1 riastrad 113 1.2 riastrad static const struct vmw_res_func vmw_dx_shader_func = { 114 1.2 riastrad .res_type = vmw_res_shader, 115 1.2 riastrad .needs_backup = true, 116 1.3 riastrad .may_evict = true, 117 1.3 riastrad .prio = 3, 118 1.3 riastrad .dirty_prio = 3, 119 1.2 riastrad .type_name = "dx shaders", 120 1.2 riastrad .backup_placement = &vmw_mob_placement, 121 1.2 riastrad .create = vmw_dx_shader_create, 122 1.2 riastrad /* 123 1.2 riastrad * The destroy callback is only called with a committed resource on 124 1.2 riastrad * context destroy, in which case we destroy the cotable anyway, 125 1.2 riastrad * so there's no need to destroy DX shaders separately. 126 1.2 riastrad */ 127 1.2 riastrad .destroy = NULL, 128 1.2 riastrad .bind = vmw_dx_shader_bind, 129 1.2 riastrad .unbind = vmw_dx_shader_unbind, 130 1.2 riastrad .commit_notify = vmw_dx_shader_commit_notify, 131 1.2 riastrad }; 132 1.2 riastrad 133 1.1 riastrad /** 134 1.1 riastrad * Shader management: 135 1.1 riastrad */ 136 1.1 riastrad 137 1.1 riastrad static inline struct vmw_shader * 138 1.1 riastrad vmw_res_to_shader(struct vmw_resource *res) 139 1.1 riastrad { 140 1.1 riastrad return container_of(res, struct vmw_shader, res); 141 1.1 riastrad } 142 1.1 riastrad 143 1.2 riastrad /** 144 1.2 riastrad * vmw_res_to_dx_shader - typecast a struct vmw_resource to a 145 1.2 riastrad * struct vmw_dx_shader 146 1.2 riastrad * 147 1.2 riastrad * @res: Pointer to the struct vmw_resource. 148 1.2 riastrad */ 149 1.2 riastrad static inline struct vmw_dx_shader * 150 1.2 riastrad vmw_res_to_dx_shader(struct vmw_resource *res) 151 1.2 riastrad { 152 1.2 riastrad return container_of(res, struct vmw_dx_shader, res); 153 1.2 riastrad } 154 1.2 riastrad 155 1.1 riastrad static void vmw_hw_shader_destroy(struct vmw_resource *res) 156 1.1 riastrad { 157 1.2 riastrad if (likely(res->func->destroy)) 158 1.2 riastrad (void) res->func->destroy(res); 159 1.2 riastrad else 160 1.2 riastrad res->id = -1; 161 1.1 riastrad } 162 1.1 riastrad 163 1.2 riastrad 164 1.1 riastrad static int vmw_gb_shader_init(struct vmw_private *dev_priv, 165 1.1 riastrad struct vmw_resource *res, 166 1.1 riastrad uint32_t size, 167 1.1 riastrad uint64_t offset, 168 1.1 riastrad SVGA3dShaderType type, 169 1.2 riastrad uint8_t num_input_sig, 170 1.2 riastrad uint8_t num_output_sig, 171 1.3 riastrad struct vmw_buffer_object *byte_code, 172 1.1 riastrad void (*res_free) (struct vmw_resource *res)) 173 1.1 riastrad { 174 1.1 riastrad struct vmw_shader *shader = vmw_res_to_shader(res); 175 1.1 riastrad int ret; 176 1.1 riastrad 177 1.2 riastrad ret = vmw_resource_init(dev_priv, res, true, res_free, 178 1.2 riastrad &vmw_gb_shader_func); 179 1.1 riastrad 180 1.1 riastrad if (unlikely(ret != 0)) { 181 1.1 riastrad if (res_free) 182 1.1 riastrad res_free(res); 183 1.1 riastrad else 184 1.1 riastrad kfree(res); 185 1.1 riastrad return ret; 186 1.1 riastrad } 187 1.1 riastrad 188 1.1 riastrad res->backup_size = size; 189 1.1 riastrad if (byte_code) { 190 1.3 riastrad res->backup = vmw_bo_reference(byte_code); 191 1.1 riastrad res->backup_offset = offset; 192 1.1 riastrad } 193 1.1 riastrad shader->size = size; 194 1.1 riastrad shader->type = type; 195 1.2 riastrad shader->num_input_sig = num_input_sig; 196 1.2 riastrad shader->num_output_sig = num_output_sig; 197 1.1 riastrad 198 1.3 riastrad res->hw_destroy = vmw_hw_shader_destroy; 199 1.1 riastrad return 0; 200 1.1 riastrad } 201 1.1 riastrad 202 1.2 riastrad /* 203 1.2 riastrad * GB shader code: 204 1.2 riastrad */ 205 1.2 riastrad 206 1.1 riastrad static int vmw_gb_shader_create(struct vmw_resource *res) 207 1.1 riastrad { 208 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 209 1.1 riastrad struct vmw_shader *shader = vmw_res_to_shader(res); 210 1.1 riastrad int ret; 211 1.1 riastrad struct { 212 1.1 riastrad SVGA3dCmdHeader header; 213 1.1 riastrad SVGA3dCmdDefineGBShader body; 214 1.1 riastrad } *cmd; 215 1.1 riastrad 216 1.1 riastrad if (likely(res->id != -1)) 217 1.1 riastrad return 0; 218 1.1 riastrad 219 1.1 riastrad ret = vmw_resource_alloc_id(res); 220 1.1 riastrad if (unlikely(ret != 0)) { 221 1.1 riastrad DRM_ERROR("Failed to allocate a shader id.\n"); 222 1.1 riastrad goto out_no_id; 223 1.1 riastrad } 224 1.1 riastrad 225 1.1 riastrad if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { 226 1.1 riastrad ret = -EBUSY; 227 1.1 riastrad goto out_no_fifo; 228 1.1 riastrad } 229 1.1 riastrad 230 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 231 1.1 riastrad if (unlikely(cmd == NULL)) { 232 1.1 riastrad ret = -ENOMEM; 233 1.1 riastrad goto out_no_fifo; 234 1.1 riastrad } 235 1.1 riastrad 236 1.1 riastrad cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; 237 1.1 riastrad cmd->header.size = sizeof(cmd->body); 238 1.1 riastrad cmd->body.shid = res->id; 239 1.1 riastrad cmd->body.type = shader->type; 240 1.1 riastrad cmd->body.sizeInBytes = shader->size; 241 1.1 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 242 1.2 riastrad vmw_fifo_resource_inc(dev_priv); 243 1.1 riastrad 244 1.1 riastrad return 0; 245 1.1 riastrad 246 1.1 riastrad out_no_fifo: 247 1.1 riastrad vmw_resource_release_id(res); 248 1.1 riastrad out_no_id: 249 1.1 riastrad return ret; 250 1.1 riastrad } 251 1.1 riastrad 252 1.1 riastrad static int vmw_gb_shader_bind(struct vmw_resource *res, 253 1.1 riastrad struct ttm_validate_buffer *val_buf) 254 1.1 riastrad { 255 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 256 1.1 riastrad struct { 257 1.1 riastrad SVGA3dCmdHeader header; 258 1.1 riastrad SVGA3dCmdBindGBShader body; 259 1.1 riastrad } *cmd; 260 1.1 riastrad struct ttm_buffer_object *bo = val_buf->bo; 261 1.1 riastrad 262 1.1 riastrad BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 263 1.1 riastrad 264 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 265 1.3 riastrad if (unlikely(cmd == NULL)) 266 1.1 riastrad return -ENOMEM; 267 1.1 riastrad 268 1.1 riastrad cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 269 1.1 riastrad cmd->header.size = sizeof(cmd->body); 270 1.1 riastrad cmd->body.shid = res->id; 271 1.1 riastrad cmd->body.mobid = bo->mem.start; 272 1.2 riastrad cmd->body.offsetInBytes = res->backup_offset; 273 1.1 riastrad res->backup_dirty = false; 274 1.1 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 275 1.1 riastrad 276 1.1 riastrad return 0; 277 1.1 riastrad } 278 1.1 riastrad 279 1.1 riastrad static int vmw_gb_shader_unbind(struct vmw_resource *res, 280 1.1 riastrad bool readback, 281 1.1 riastrad struct ttm_validate_buffer *val_buf) 282 1.1 riastrad { 283 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 284 1.1 riastrad struct { 285 1.1 riastrad SVGA3dCmdHeader header; 286 1.1 riastrad SVGA3dCmdBindGBShader body; 287 1.1 riastrad } *cmd; 288 1.1 riastrad struct vmw_fence_obj *fence; 289 1.1 riastrad 290 1.1 riastrad BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); 291 1.1 riastrad 292 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 293 1.3 riastrad if (unlikely(cmd == NULL)) 294 1.1 riastrad return -ENOMEM; 295 1.1 riastrad 296 1.1 riastrad cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 297 1.1 riastrad cmd->header.size = sizeof(cmd->body); 298 1.1 riastrad cmd->body.shid = res->id; 299 1.1 riastrad cmd->body.mobid = SVGA3D_INVALID_ID; 300 1.1 riastrad cmd->body.offsetInBytes = 0; 301 1.1 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 302 1.1 riastrad 303 1.1 riastrad /* 304 1.1 riastrad * Create a fence object and fence the backup buffer. 305 1.1 riastrad */ 306 1.1 riastrad 307 1.1 riastrad (void) vmw_execbuf_fence_commands(NULL, dev_priv, 308 1.1 riastrad &fence, NULL); 309 1.1 riastrad 310 1.3 riastrad vmw_bo_fence_single(val_buf->bo, fence); 311 1.1 riastrad 312 1.1 riastrad if (likely(fence != NULL)) 313 1.1 riastrad vmw_fence_obj_unreference(&fence); 314 1.1 riastrad 315 1.1 riastrad return 0; 316 1.1 riastrad } 317 1.1 riastrad 318 1.1 riastrad static int vmw_gb_shader_destroy(struct vmw_resource *res) 319 1.1 riastrad { 320 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 321 1.1 riastrad struct { 322 1.1 riastrad SVGA3dCmdHeader header; 323 1.1 riastrad SVGA3dCmdDestroyGBShader body; 324 1.1 riastrad } *cmd; 325 1.1 riastrad 326 1.1 riastrad if (likely(res->id == -1)) 327 1.1 riastrad return 0; 328 1.1 riastrad 329 1.1 riastrad mutex_lock(&dev_priv->binding_mutex); 330 1.2 riastrad vmw_binding_res_list_scrub(&res->binding_head); 331 1.1 riastrad 332 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 333 1.1 riastrad if (unlikely(cmd == NULL)) { 334 1.1 riastrad mutex_unlock(&dev_priv->binding_mutex); 335 1.1 riastrad return -ENOMEM; 336 1.1 riastrad } 337 1.1 riastrad 338 1.1 riastrad cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; 339 1.1 riastrad cmd->header.size = sizeof(cmd->body); 340 1.1 riastrad cmd->body.shid = res->id; 341 1.1 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 342 1.1 riastrad mutex_unlock(&dev_priv->binding_mutex); 343 1.1 riastrad vmw_resource_release_id(res); 344 1.2 riastrad vmw_fifo_resource_dec(dev_priv); 345 1.2 riastrad 346 1.2 riastrad return 0; 347 1.2 riastrad } 348 1.2 riastrad 349 1.2 riastrad /* 350 1.2 riastrad * DX shader code: 351 1.2 riastrad */ 352 1.2 riastrad 353 1.2 riastrad /** 354 1.2 riastrad * vmw_dx_shader_commit_notify - Notify that a shader operation has been 355 1.2 riastrad * committed to hardware from a user-supplied command stream. 356 1.2 riastrad * 357 1.2 riastrad * @res: Pointer to the shader resource. 358 1.2 riastrad * @state: Indicating whether a creation or removal has been committed. 359 1.2 riastrad * 360 1.2 riastrad */ 361 1.2 riastrad static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 362 1.2 riastrad enum vmw_cmdbuf_res_state state) 363 1.2 riastrad { 364 1.2 riastrad struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 365 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 366 1.2 riastrad 367 1.2 riastrad if (state == VMW_CMDBUF_RES_ADD) { 368 1.2 riastrad mutex_lock(&dev_priv->binding_mutex); 369 1.2 riastrad vmw_cotable_add_resource(shader->cotable, 370 1.2 riastrad &shader->cotable_head); 371 1.2 riastrad shader->committed = true; 372 1.2 riastrad res->id = shader->id; 373 1.2 riastrad mutex_unlock(&dev_priv->binding_mutex); 374 1.2 riastrad } else { 375 1.2 riastrad mutex_lock(&dev_priv->binding_mutex); 376 1.2 riastrad list_del_init(&shader->cotable_head); 377 1.2 riastrad shader->committed = false; 378 1.2 riastrad res->id = -1; 379 1.2 riastrad mutex_unlock(&dev_priv->binding_mutex); 380 1.2 riastrad } 381 1.2 riastrad } 382 1.2 riastrad 383 1.2 riastrad /** 384 1.2 riastrad * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader. 385 1.2 riastrad * 386 1.2 riastrad * @res: The shader resource 387 1.2 riastrad * 388 1.2 riastrad * This function reverts a scrub operation. 389 1.2 riastrad */ 390 1.2 riastrad static int vmw_dx_shader_unscrub(struct vmw_resource *res) 391 1.2 riastrad { 392 1.2 riastrad struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 393 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 394 1.2 riastrad struct { 395 1.2 riastrad SVGA3dCmdHeader header; 396 1.2 riastrad SVGA3dCmdDXBindShader body; 397 1.2 riastrad } *cmd; 398 1.2 riastrad 399 1.2 riastrad if (!list_empty(&shader->cotable_head) || !shader->committed) 400 1.2 riastrad return 0; 401 1.2 riastrad 402 1.3 riastrad cmd = VMW_FIFO_RESERVE_DX(dev_priv, sizeof(*cmd), shader->ctx->id); 403 1.3 riastrad if (unlikely(cmd == NULL)) 404 1.2 riastrad return -ENOMEM; 405 1.2 riastrad 406 1.2 riastrad cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 407 1.2 riastrad cmd->header.size = sizeof(cmd->body); 408 1.2 riastrad cmd->body.cid = shader->ctx->id; 409 1.2 riastrad cmd->body.shid = shader->id; 410 1.2 riastrad cmd->body.mobid = res->backup->base.mem.start; 411 1.2 riastrad cmd->body.offsetInBytes = res->backup_offset; 412 1.2 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 413 1.2 riastrad 414 1.2 riastrad vmw_cotable_add_resource(shader->cotable, &shader->cotable_head); 415 1.2 riastrad 416 1.2 riastrad return 0; 417 1.2 riastrad } 418 1.2 riastrad 419 1.2 riastrad /** 420 1.2 riastrad * vmw_dx_shader_create - The DX shader create callback 421 1.2 riastrad * 422 1.2 riastrad * @res: The DX shader resource 423 1.2 riastrad * 424 1.2 riastrad * The create callback is called as part of resource validation and 425 1.2 riastrad * makes sure that we unscrub the shader if it's previously been scrubbed. 426 1.2 riastrad */ 427 1.2 riastrad static int vmw_dx_shader_create(struct vmw_resource *res) 428 1.2 riastrad { 429 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 430 1.2 riastrad struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 431 1.2 riastrad int ret = 0; 432 1.2 riastrad 433 1.2 riastrad WARN_ON_ONCE(!shader->committed); 434 1.2 riastrad 435 1.3 riastrad if (vmw_resource_mob_attached(res)) { 436 1.2 riastrad mutex_lock(&dev_priv->binding_mutex); 437 1.2 riastrad ret = vmw_dx_shader_unscrub(res); 438 1.2 riastrad mutex_unlock(&dev_priv->binding_mutex); 439 1.2 riastrad } 440 1.2 riastrad 441 1.2 riastrad res->id = shader->id; 442 1.2 riastrad return ret; 443 1.2 riastrad } 444 1.2 riastrad 445 1.2 riastrad /** 446 1.2 riastrad * vmw_dx_shader_bind - The DX shader bind callback 447 1.2 riastrad * 448 1.2 riastrad * @res: The DX shader resource 449 1.2 riastrad * @val_buf: Pointer to the validate buffer. 450 1.2 riastrad * 451 1.2 riastrad */ 452 1.2 riastrad static int vmw_dx_shader_bind(struct vmw_resource *res, 453 1.2 riastrad struct ttm_validate_buffer *val_buf) 454 1.2 riastrad { 455 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 456 1.2 riastrad struct ttm_buffer_object *bo = val_buf->bo; 457 1.2 riastrad 458 1.2 riastrad BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 459 1.2 riastrad mutex_lock(&dev_priv->binding_mutex); 460 1.2 riastrad vmw_dx_shader_unscrub(res); 461 1.2 riastrad mutex_unlock(&dev_priv->binding_mutex); 462 1.1 riastrad 463 1.1 riastrad return 0; 464 1.1 riastrad } 465 1.1 riastrad 466 1.1 riastrad /** 467 1.2 riastrad * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader. 468 1.2 riastrad * 469 1.2 riastrad * @res: The shader resource 470 1.2 riastrad * 471 1.2 riastrad * This function unbinds a MOB from the DX shader without requiring the 472 1.2 riastrad * MOB dma_buffer to be reserved. The driver still considers the MOB bound. 473 1.2 riastrad * However, once the driver eventually decides to unbind the MOB, it doesn't 474 1.2 riastrad * need to access the context. 475 1.2 riastrad */ 476 1.2 riastrad static int vmw_dx_shader_scrub(struct vmw_resource *res) 477 1.2 riastrad { 478 1.2 riastrad struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 479 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 480 1.2 riastrad struct { 481 1.2 riastrad SVGA3dCmdHeader header; 482 1.2 riastrad SVGA3dCmdDXBindShader body; 483 1.2 riastrad } *cmd; 484 1.2 riastrad 485 1.2 riastrad if (list_empty(&shader->cotable_head)) 486 1.2 riastrad return 0; 487 1.2 riastrad 488 1.2 riastrad WARN_ON_ONCE(!shader->committed); 489 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 490 1.3 riastrad if (unlikely(cmd == NULL)) 491 1.2 riastrad return -ENOMEM; 492 1.2 riastrad 493 1.2 riastrad cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 494 1.2 riastrad cmd->header.size = sizeof(cmd->body); 495 1.2 riastrad cmd->body.cid = shader->ctx->id; 496 1.2 riastrad cmd->body.shid = res->id; 497 1.2 riastrad cmd->body.mobid = SVGA3D_INVALID_ID; 498 1.2 riastrad cmd->body.offsetInBytes = 0; 499 1.2 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 500 1.2 riastrad res->id = -1; 501 1.2 riastrad list_del_init(&shader->cotable_head); 502 1.2 riastrad 503 1.2 riastrad return 0; 504 1.2 riastrad } 505 1.2 riastrad 506 1.2 riastrad /** 507 1.2 riastrad * vmw_dx_shader_unbind - The dx shader unbind callback. 508 1.2 riastrad * 509 1.2 riastrad * @res: The shader resource 510 1.2 riastrad * @readback: Whether this is a readback unbind. Currently unused. 511 1.2 riastrad * @val_buf: MOB buffer information. 512 1.2 riastrad */ 513 1.2 riastrad static int vmw_dx_shader_unbind(struct vmw_resource *res, 514 1.2 riastrad bool readback, 515 1.2 riastrad struct ttm_validate_buffer *val_buf) 516 1.2 riastrad { 517 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 518 1.2 riastrad struct vmw_fence_obj *fence; 519 1.2 riastrad int ret; 520 1.2 riastrad 521 1.2 riastrad BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); 522 1.2 riastrad 523 1.2 riastrad mutex_lock(&dev_priv->binding_mutex); 524 1.2 riastrad ret = vmw_dx_shader_scrub(res); 525 1.2 riastrad mutex_unlock(&dev_priv->binding_mutex); 526 1.2 riastrad 527 1.2 riastrad if (ret) 528 1.2 riastrad return ret; 529 1.2 riastrad 530 1.2 riastrad (void) vmw_execbuf_fence_commands(NULL, dev_priv, 531 1.2 riastrad &fence, NULL); 532 1.3 riastrad vmw_bo_fence_single(val_buf->bo, fence); 533 1.2 riastrad 534 1.2 riastrad if (likely(fence != NULL)) 535 1.2 riastrad vmw_fence_obj_unreference(&fence); 536 1.2 riastrad 537 1.2 riastrad return 0; 538 1.2 riastrad } 539 1.2 riastrad 540 1.2 riastrad /** 541 1.2 riastrad * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for 542 1.2 riastrad * DX shaders. 543 1.2 riastrad * 544 1.2 riastrad * @dev_priv: Pointer to device private structure. 545 1.2 riastrad * @list: The list of cotable resources. 546 1.2 riastrad * @readback: Whether the call was part of a readback unbind. 547 1.2 riastrad * 548 1.2 riastrad * Scrubs all shader MOBs so that any subsequent shader unbind or shader 549 1.2 riastrad * destroy operation won't need to swap in the context. 550 1.2 riastrad */ 551 1.2 riastrad void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv, 552 1.2 riastrad struct list_head *list, 553 1.2 riastrad bool readback) 554 1.2 riastrad { 555 1.2 riastrad struct vmw_dx_shader *entry, *next; 556 1.2 riastrad 557 1.3 riastrad lockdep_assert_held_once(&dev_priv->binding_mutex); 558 1.2 riastrad 559 1.2 riastrad list_for_each_entry_safe(entry, next, list, cotable_head) { 560 1.2 riastrad WARN_ON(vmw_dx_shader_scrub(&entry->res)); 561 1.2 riastrad if (!readback) 562 1.2 riastrad entry->committed = false; 563 1.2 riastrad } 564 1.2 riastrad } 565 1.2 riastrad 566 1.2 riastrad /** 567 1.2 riastrad * vmw_dx_shader_res_free - The DX shader free callback 568 1.2 riastrad * 569 1.2 riastrad * @res: The shader resource 570 1.2 riastrad * 571 1.2 riastrad * Frees the DX shader resource and updates memory accounting. 572 1.2 riastrad */ 573 1.2 riastrad static void vmw_dx_shader_res_free(struct vmw_resource *res) 574 1.2 riastrad { 575 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 576 1.2 riastrad struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 577 1.2 riastrad 578 1.2 riastrad vmw_resource_unreference(&shader->cotable); 579 1.2 riastrad kfree(shader); 580 1.2 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size); 581 1.2 riastrad } 582 1.2 riastrad 583 1.2 riastrad /** 584 1.2 riastrad * vmw_dx_shader_add - Add a shader resource as a command buffer managed 585 1.2 riastrad * resource. 586 1.2 riastrad * 587 1.2 riastrad * @man: The command buffer resource manager. 588 1.2 riastrad * @ctx: Pointer to the context resource. 589 1.2 riastrad * @user_key: The id used for this shader. 590 1.2 riastrad * @shader_type: The shader type. 591 1.2 riastrad * @list: The list of staged command buffer managed resources. 592 1.2 riastrad */ 593 1.2 riastrad int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man, 594 1.2 riastrad struct vmw_resource *ctx, 595 1.2 riastrad u32 user_key, 596 1.2 riastrad SVGA3dShaderType shader_type, 597 1.2 riastrad struct list_head *list) 598 1.2 riastrad { 599 1.2 riastrad struct vmw_dx_shader *shader; 600 1.2 riastrad struct vmw_resource *res; 601 1.2 riastrad struct vmw_private *dev_priv = ctx->dev_priv; 602 1.3 riastrad struct ttm_operation_ctx ttm_opt_ctx = { 603 1.3 riastrad .interruptible = true, 604 1.3 riastrad .no_wait_gpu = false 605 1.3 riastrad }; 606 1.2 riastrad int ret; 607 1.2 riastrad 608 1.2 riastrad if (!vmw_shader_dx_size) 609 1.2 riastrad vmw_shader_dx_size = ttm_round_pot(sizeof(*shader)); 610 1.2 riastrad 611 1.2 riastrad if (!vmw_shader_id_ok(user_key, shader_type)) 612 1.2 riastrad return -EINVAL; 613 1.2 riastrad 614 1.2 riastrad ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size, 615 1.3 riastrad &ttm_opt_ctx); 616 1.2 riastrad if (ret) { 617 1.2 riastrad if (ret != -ERESTARTSYS) 618 1.2 riastrad DRM_ERROR("Out of graphics memory for shader " 619 1.2 riastrad "creation.\n"); 620 1.2 riastrad return ret; 621 1.2 riastrad } 622 1.2 riastrad 623 1.2 riastrad shader = kmalloc(sizeof(*shader), GFP_KERNEL); 624 1.2 riastrad if (!shader) { 625 1.2 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size); 626 1.2 riastrad return -ENOMEM; 627 1.2 riastrad } 628 1.2 riastrad 629 1.2 riastrad res = &shader->res; 630 1.2 riastrad shader->ctx = ctx; 631 1.3 riastrad shader->cotable = vmw_resource_reference 632 1.3 riastrad (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER)); 633 1.2 riastrad shader->id = user_key; 634 1.2 riastrad shader->committed = false; 635 1.2 riastrad INIT_LIST_HEAD(&shader->cotable_head); 636 1.2 riastrad ret = vmw_resource_init(dev_priv, res, true, 637 1.2 riastrad vmw_dx_shader_res_free, &vmw_dx_shader_func); 638 1.2 riastrad if (ret) 639 1.2 riastrad goto out_resource_init; 640 1.2 riastrad 641 1.2 riastrad /* 642 1.2 riastrad * The user_key name-space is not per shader type for DX shaders, 643 1.2 riastrad * so when hashing, use a single zero shader type. 644 1.2 riastrad */ 645 1.2 riastrad ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 646 1.2 riastrad vmw_shader_key(user_key, 0), 647 1.2 riastrad res, list); 648 1.2 riastrad if (ret) 649 1.2 riastrad goto out_resource_init; 650 1.2 riastrad 651 1.2 riastrad res->id = shader->id; 652 1.3 riastrad res->hw_destroy = vmw_hw_shader_destroy; 653 1.2 riastrad 654 1.2 riastrad out_resource_init: 655 1.2 riastrad vmw_resource_unreference(&res); 656 1.2 riastrad 657 1.2 riastrad return ret; 658 1.2 riastrad } 659 1.2 riastrad 660 1.2 riastrad 661 1.2 riastrad 662 1.2 riastrad /** 663 1.1 riastrad * User-space shader management: 664 1.1 riastrad */ 665 1.1 riastrad 666 1.1 riastrad static struct vmw_resource * 667 1.1 riastrad vmw_user_shader_base_to_res(struct ttm_base_object *base) 668 1.1 riastrad { 669 1.1 riastrad return &(container_of(base, struct vmw_user_shader, base)-> 670 1.1 riastrad shader.res); 671 1.1 riastrad } 672 1.1 riastrad 673 1.1 riastrad static void vmw_user_shader_free(struct vmw_resource *res) 674 1.1 riastrad { 675 1.1 riastrad struct vmw_user_shader *ushader = 676 1.1 riastrad container_of(res, struct vmw_user_shader, shader.res); 677 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 678 1.1 riastrad 679 1.1 riastrad ttm_base_object_kfree(ushader, base); 680 1.1 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), 681 1.1 riastrad vmw_user_shader_size); 682 1.1 riastrad } 683 1.1 riastrad 684 1.2 riastrad static void vmw_shader_free(struct vmw_resource *res) 685 1.2 riastrad { 686 1.2 riastrad struct vmw_shader *shader = vmw_res_to_shader(res); 687 1.2 riastrad struct vmw_private *dev_priv = res->dev_priv; 688 1.2 riastrad 689 1.2 riastrad kfree(shader); 690 1.2 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), 691 1.2 riastrad vmw_shader_size); 692 1.2 riastrad } 693 1.2 riastrad 694 1.1 riastrad /** 695 1.1 riastrad * This function is called when user space has no more references on the 696 1.1 riastrad * base object. It releases the base-object's reference on the resource object. 697 1.1 riastrad */ 698 1.1 riastrad 699 1.1 riastrad static void vmw_user_shader_base_release(struct ttm_base_object **p_base) 700 1.1 riastrad { 701 1.1 riastrad struct ttm_base_object *base = *p_base; 702 1.1 riastrad struct vmw_resource *res = vmw_user_shader_base_to_res(base); 703 1.1 riastrad 704 1.1 riastrad *p_base = NULL; 705 1.1 riastrad vmw_resource_unreference(&res); 706 1.1 riastrad } 707 1.1 riastrad 708 1.1 riastrad int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, 709 1.1 riastrad struct drm_file *file_priv) 710 1.1 riastrad { 711 1.1 riastrad struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; 712 1.1 riastrad struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 713 1.1 riastrad 714 1.1 riastrad return ttm_ref_object_base_unref(tfile, arg->handle, 715 1.1 riastrad TTM_REF_USAGE); 716 1.1 riastrad } 717 1.1 riastrad 718 1.2 riastrad static int vmw_user_shader_alloc(struct vmw_private *dev_priv, 719 1.3 riastrad struct vmw_buffer_object *buffer, 720 1.2 riastrad size_t shader_size, 721 1.2 riastrad size_t offset, 722 1.2 riastrad SVGA3dShaderType shader_type, 723 1.2 riastrad uint8_t num_input_sig, 724 1.2 riastrad uint8_t num_output_sig, 725 1.2 riastrad struct ttm_object_file *tfile, 726 1.2 riastrad u32 *handle) 727 1.1 riastrad { 728 1.1 riastrad struct vmw_user_shader *ushader; 729 1.1 riastrad struct vmw_resource *res, *tmp; 730 1.3 riastrad struct ttm_operation_ctx ctx = { 731 1.3 riastrad .interruptible = true, 732 1.3 riastrad .no_wait_gpu = false 733 1.3 riastrad }; 734 1.1 riastrad int ret; 735 1.1 riastrad 736 1.1 riastrad if (unlikely(vmw_user_shader_size == 0)) 737 1.1 riastrad vmw_user_shader_size = 738 1.3 riastrad ttm_round_pot(sizeof(struct vmw_user_shader)) + 739 1.3 riastrad VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; 740 1.1 riastrad 741 1.1 riastrad ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 742 1.1 riastrad vmw_user_shader_size, 743 1.3 riastrad &ctx); 744 1.1 riastrad if (unlikely(ret != 0)) { 745 1.1 riastrad if (ret != -ERESTARTSYS) 746 1.1 riastrad DRM_ERROR("Out of graphics memory for shader " 747 1.1 riastrad "creation.\n"); 748 1.1 riastrad goto out; 749 1.1 riastrad } 750 1.1 riastrad 751 1.1 riastrad ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); 752 1.3 riastrad if (unlikely(!ushader)) { 753 1.1 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), 754 1.1 riastrad vmw_user_shader_size); 755 1.1 riastrad ret = -ENOMEM; 756 1.1 riastrad goto out; 757 1.1 riastrad } 758 1.1 riastrad 759 1.1 riastrad res = &ushader->shader.res; 760 1.1 riastrad ushader->base.shareable = false; 761 1.1 riastrad ushader->base.tfile = NULL; 762 1.1 riastrad 763 1.1 riastrad /* 764 1.1 riastrad * From here on, the destructor takes over resource freeing. 765 1.1 riastrad */ 766 1.1 riastrad 767 1.1 riastrad ret = vmw_gb_shader_init(dev_priv, res, shader_size, 768 1.2 riastrad offset, shader_type, num_input_sig, 769 1.2 riastrad num_output_sig, buffer, 770 1.1 riastrad vmw_user_shader_free); 771 1.1 riastrad if (unlikely(ret != 0)) 772 1.1 riastrad goto out; 773 1.1 riastrad 774 1.1 riastrad tmp = vmw_resource_reference(res); 775 1.1 riastrad ret = ttm_base_object_init(tfile, &ushader->base, false, 776 1.1 riastrad VMW_RES_SHADER, 777 1.1 riastrad &vmw_user_shader_base_release, NULL); 778 1.1 riastrad 779 1.1 riastrad if (unlikely(ret != 0)) { 780 1.1 riastrad vmw_resource_unreference(&tmp); 781 1.1 riastrad goto out_err; 782 1.1 riastrad } 783 1.1 riastrad 784 1.1 riastrad if (handle) 785 1.3 riastrad *handle = ushader->base.handle; 786 1.1 riastrad out_err: 787 1.1 riastrad vmw_resource_unreference(&res); 788 1.1 riastrad out: 789 1.1 riastrad return ret; 790 1.1 riastrad } 791 1.1 riastrad 792 1.1 riastrad 793 1.2 riastrad static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, 794 1.3 riastrad struct vmw_buffer_object *buffer, 795 1.2 riastrad size_t shader_size, 796 1.2 riastrad size_t offset, 797 1.2 riastrad SVGA3dShaderType shader_type) 798 1.2 riastrad { 799 1.2 riastrad struct vmw_shader *shader; 800 1.2 riastrad struct vmw_resource *res; 801 1.3 riastrad struct ttm_operation_ctx ctx = { 802 1.3 riastrad .interruptible = true, 803 1.3 riastrad .no_wait_gpu = false 804 1.3 riastrad }; 805 1.2 riastrad int ret; 806 1.2 riastrad 807 1.2 riastrad if (unlikely(vmw_shader_size == 0)) 808 1.2 riastrad vmw_shader_size = 809 1.3 riastrad ttm_round_pot(sizeof(struct vmw_shader)) + 810 1.3 riastrad VMW_IDA_ACC_SIZE; 811 1.2 riastrad 812 1.2 riastrad ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 813 1.2 riastrad vmw_shader_size, 814 1.3 riastrad &ctx); 815 1.2 riastrad if (unlikely(ret != 0)) { 816 1.2 riastrad if (ret != -ERESTARTSYS) 817 1.2 riastrad DRM_ERROR("Out of graphics memory for shader " 818 1.2 riastrad "creation.\n"); 819 1.2 riastrad goto out_err; 820 1.2 riastrad } 821 1.2 riastrad 822 1.2 riastrad shader = kzalloc(sizeof(*shader), GFP_KERNEL); 823 1.3 riastrad if (unlikely(!shader)) { 824 1.2 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), 825 1.2 riastrad vmw_shader_size); 826 1.2 riastrad ret = -ENOMEM; 827 1.2 riastrad goto out_err; 828 1.2 riastrad } 829 1.2 riastrad 830 1.2 riastrad res = &shader->res; 831 1.2 riastrad 832 1.2 riastrad /* 833 1.2 riastrad * From here on, the destructor takes over resource freeing. 834 1.2 riastrad */ 835 1.2 riastrad ret = vmw_gb_shader_init(dev_priv, res, shader_size, 836 1.2 riastrad offset, shader_type, 0, 0, buffer, 837 1.2 riastrad vmw_shader_free); 838 1.2 riastrad 839 1.2 riastrad out_err: 840 1.2 riastrad return ret ? ERR_PTR(ret) : res; 841 1.2 riastrad } 842 1.2 riastrad 843 1.2 riastrad 844 1.2 riastrad static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, 845 1.2 riastrad enum drm_vmw_shader_type shader_type_drm, 846 1.2 riastrad u32 buffer_handle, size_t size, size_t offset, 847 1.2 riastrad uint8_t num_input_sig, uint8_t num_output_sig, 848 1.2 riastrad uint32_t *shader_handle) 849 1.1 riastrad { 850 1.1 riastrad struct vmw_private *dev_priv = vmw_priv(dev); 851 1.1 riastrad struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 852 1.3 riastrad struct vmw_buffer_object *buffer = NULL; 853 1.1 riastrad SVGA3dShaderType shader_type; 854 1.1 riastrad int ret; 855 1.1 riastrad 856 1.2 riastrad if (buffer_handle != SVGA3D_INVALID_ID) { 857 1.3 riastrad ret = vmw_user_bo_lookup(tfile, buffer_handle, 858 1.2 riastrad &buffer, NULL); 859 1.1 riastrad if (unlikely(ret != 0)) { 860 1.3 riastrad VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n"); 861 1.1 riastrad return ret; 862 1.1 riastrad } 863 1.1 riastrad 864 1.1 riastrad if ((u64)buffer->base.num_pages * PAGE_SIZE < 865 1.2 riastrad (u64)size + (u64)offset) { 866 1.3 riastrad VMW_DEBUG_USER("Illegal buffer- or shader size.\n"); 867 1.1 riastrad ret = -EINVAL; 868 1.1 riastrad goto out_bad_arg; 869 1.1 riastrad } 870 1.1 riastrad } 871 1.1 riastrad 872 1.2 riastrad switch (shader_type_drm) { 873 1.1 riastrad case drm_vmw_shader_type_vs: 874 1.1 riastrad shader_type = SVGA3D_SHADERTYPE_VS; 875 1.1 riastrad break; 876 1.1 riastrad case drm_vmw_shader_type_ps: 877 1.1 riastrad shader_type = SVGA3D_SHADERTYPE_PS; 878 1.1 riastrad break; 879 1.1 riastrad default: 880 1.3 riastrad VMW_DEBUG_USER("Illegal shader type.\n"); 881 1.1 riastrad ret = -EINVAL; 882 1.1 riastrad goto out_bad_arg; 883 1.1 riastrad } 884 1.1 riastrad 885 1.1 riastrad ret = ttm_read_lock(&dev_priv->reservation_sem, true); 886 1.1 riastrad if (unlikely(ret != 0)) 887 1.1 riastrad goto out_bad_arg; 888 1.1 riastrad 889 1.2 riastrad ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset, 890 1.2 riastrad shader_type, num_input_sig, 891 1.2 riastrad num_output_sig, tfile, shader_handle); 892 1.1 riastrad 893 1.1 riastrad ttm_read_unlock(&dev_priv->reservation_sem); 894 1.1 riastrad out_bad_arg: 895 1.3 riastrad vmw_bo_unreference(&buffer); 896 1.1 riastrad return ret; 897 1.1 riastrad } 898 1.1 riastrad 899 1.1 riastrad /** 900 1.2 riastrad * vmw_shader_id_ok - Check whether a compat shader user key and 901 1.2 riastrad * shader type are within valid bounds. 902 1.1 riastrad * 903 1.2 riastrad * @user_key: User space id of the shader. 904 1.2 riastrad * @shader_type: Shader type. 905 1.1 riastrad * 906 1.2 riastrad * Returns true if valid false if not. 907 1.1 riastrad */ 908 1.2 riastrad static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) 909 1.2 riastrad { 910 1.2 riastrad return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; 911 1.1 riastrad } 912 1.1 riastrad 913 1.1 riastrad /** 914 1.2 riastrad * vmw_shader_key - Compute a hash key suitable for a compat shader. 915 1.1 riastrad * 916 1.2 riastrad * @user_key: User space id of the shader. 917 1.2 riastrad * @shader_type: Shader type. 918 1.1 riastrad * 919 1.2 riastrad * Returns a hash key suitable for a command buffer managed resource 920 1.2 riastrad * manager hash table. 921 1.1 riastrad */ 922 1.2 riastrad static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type) 923 1.1 riastrad { 924 1.2 riastrad return user_key | (shader_type << 20); 925 1.1 riastrad } 926 1.1 riastrad 927 1.1 riastrad /** 928 1.2 riastrad * vmw_shader_remove - Stage a compat shader for removal. 929 1.1 riastrad * 930 1.2 riastrad * @man: Pointer to the compat shader manager identifying the shader namespace. 931 1.1 riastrad * @user_key: The key that is used to identify the shader. The key is 932 1.1 riastrad * unique to the shader type. 933 1.1 riastrad * @shader_type: Shader type. 934 1.2 riastrad * @list: Caller's list of staged command buffer resource actions. 935 1.2 riastrad */ 936 1.2 riastrad int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man, 937 1.2 riastrad u32 user_key, SVGA3dShaderType shader_type, 938 1.2 riastrad struct list_head *list) 939 1.1 riastrad { 940 1.2 riastrad struct vmw_resource *dummy; 941 1.1 riastrad 942 1.2 riastrad if (!vmw_shader_id_ok(user_key, shader_type)) 943 1.1 riastrad return -EINVAL; 944 1.1 riastrad 945 1.2 riastrad return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader, 946 1.2 riastrad vmw_shader_key(user_key, shader_type), 947 1.2 riastrad list, &dummy); 948 1.1 riastrad } 949 1.1 riastrad 950 1.1 riastrad /** 951 1.2 riastrad * vmw_compat_shader_add - Create a compat shader and stage it for addition 952 1.2 riastrad * as a command buffer managed resource. 953 1.1 riastrad * 954 1.2 riastrad * @man: Pointer to the compat shader manager identifying the shader namespace. 955 1.1 riastrad * @user_key: The key that is used to identify the shader. The key is 956 1.1 riastrad * unique to the shader type. 957 1.1 riastrad * @bytecode: Pointer to the bytecode of the shader. 958 1.1 riastrad * @shader_type: Shader type. 959 1.1 riastrad * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is 960 1.1 riastrad * to be created with. 961 1.2 riastrad * @list: Caller's list of staged command buffer resource actions. 962 1.1 riastrad * 963 1.1 riastrad */ 964 1.2 riastrad int vmw_compat_shader_add(struct vmw_private *dev_priv, 965 1.2 riastrad struct vmw_cmdbuf_res_manager *man, 966 1.1 riastrad u32 user_key, const void *bytecode, 967 1.1 riastrad SVGA3dShaderType shader_type, 968 1.1 riastrad size_t size, 969 1.1 riastrad struct list_head *list) 970 1.1 riastrad { 971 1.3 riastrad struct ttm_operation_ctx ctx = { false, true }; 972 1.3 riastrad struct vmw_buffer_object *buf; 973 1.1 riastrad struct ttm_bo_kmap_obj map; 974 1.1 riastrad bool is_iomem; 975 1.1 riastrad int ret; 976 1.2 riastrad struct vmw_resource *res; 977 1.1 riastrad 978 1.2 riastrad if (!vmw_shader_id_ok(user_key, shader_type)) 979 1.1 riastrad return -EINVAL; 980 1.1 riastrad 981 1.1 riastrad /* Allocate and pin a DMA buffer */ 982 1.1 riastrad buf = kzalloc(sizeof(*buf), GFP_KERNEL); 983 1.3 riastrad if (unlikely(!buf)) 984 1.1 riastrad return -ENOMEM; 985 1.1 riastrad 986 1.3 riastrad ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement, 987 1.3 riastrad true, vmw_bo_bo_free); 988 1.1 riastrad if (unlikely(ret != 0)) 989 1.1 riastrad goto out; 990 1.1 riastrad 991 1.3 riastrad ret = ttm_bo_reserve(&buf->base, false, true, NULL); 992 1.1 riastrad if (unlikely(ret != 0)) 993 1.1 riastrad goto no_reserve; 994 1.1 riastrad 995 1.1 riastrad /* Map and copy shader bytecode. */ 996 1.1 riastrad ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, 997 1.1 riastrad &map); 998 1.1 riastrad if (unlikely(ret != 0)) { 999 1.1 riastrad ttm_bo_unreserve(&buf->base); 1000 1.1 riastrad goto no_reserve; 1001 1.1 riastrad } 1002 1.1 riastrad 1003 1.1 riastrad memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); 1004 1.1 riastrad WARN_ON(is_iomem); 1005 1.1 riastrad 1006 1.1 riastrad ttm_bo_kunmap(&map); 1007 1.3 riastrad ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx); 1008 1.1 riastrad WARN_ON(ret != 0); 1009 1.1 riastrad ttm_bo_unreserve(&buf->base); 1010 1.1 riastrad 1011 1.2 riastrad res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); 1012 1.1 riastrad if (unlikely(ret != 0)) 1013 1.1 riastrad goto no_reserve; 1014 1.1 riastrad 1015 1.2 riastrad ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 1016 1.2 riastrad vmw_shader_key(user_key, shader_type), 1017 1.2 riastrad res, list); 1018 1.2 riastrad vmw_resource_unreference(&res); 1019 1.1 riastrad no_reserve: 1020 1.3 riastrad vmw_bo_unreference(&buf); 1021 1.1 riastrad out: 1022 1.1 riastrad return ret; 1023 1.1 riastrad } 1024 1.1 riastrad 1025 1.1 riastrad /** 1026 1.2 riastrad * vmw_shader_lookup - Look up a compat shader 1027 1.1 riastrad * 1028 1.2 riastrad * @man: Pointer to the command buffer managed resource manager identifying 1029 1.2 riastrad * the shader namespace. 1030 1.2 riastrad * @user_key: The user space id of the shader. 1031 1.2 riastrad * @shader_type: The shader type. 1032 1.1 riastrad * 1033 1.2 riastrad * Returns a refcounted pointer to a struct vmw_resource if the shader was 1034 1.2 riastrad * found. An error pointer otherwise. 1035 1.1 riastrad */ 1036 1.2 riastrad struct vmw_resource * 1037 1.2 riastrad vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man, 1038 1.2 riastrad u32 user_key, 1039 1.2 riastrad SVGA3dShaderType shader_type) 1040 1.1 riastrad { 1041 1.2 riastrad if (!vmw_shader_id_ok(user_key, shader_type)) 1042 1.2 riastrad return ERR_PTR(-EINVAL); 1043 1.1 riastrad 1044 1.2 riastrad return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader, 1045 1.2 riastrad vmw_shader_key(user_key, shader_type)); 1046 1.1 riastrad } 1047 1.1 riastrad 1048 1.2 riastrad int vmw_shader_define_ioctl(struct drm_device *dev, void *data, 1049 1.2 riastrad struct drm_file *file_priv) 1050 1.1 riastrad { 1051 1.2 riastrad struct drm_vmw_shader_create_arg *arg = 1052 1.2 riastrad (struct drm_vmw_shader_create_arg *)data; 1053 1.1 riastrad 1054 1.2 riastrad return vmw_shader_define(dev, file_priv, arg->shader_type, 1055 1.2 riastrad arg->buffer_handle, 1056 1.2 riastrad arg->size, arg->offset, 1057 1.2 riastrad 0, 0, 1058 1.2 riastrad &arg->shader_handle); 1059 1.1 riastrad } 1060