1 1.1 riastrad /* $NetBSD: vmwgfx_cotable.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 1.1 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 2014-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.1 riastrad * Treat context OTables as resources to make use of the resource 31 1.1 riastrad * backing MOB eviction mechanism, that is used to read back the COTable 32 1.1 riastrad * whenever the backing MOB is evicted. 33 1.1 riastrad */ 34 1.1 riastrad 35 1.1 riastrad #include <sys/cdefs.h> 36 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_cotable.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 37 1.1 riastrad 38 1.3 riastrad #include <drm/ttm/ttm_placement.h> 39 1.3 riastrad 40 1.1 riastrad #include "vmwgfx_drv.h" 41 1.1 riastrad #include "vmwgfx_resource_priv.h" 42 1.1 riastrad #include "vmwgfx_so.h" 43 1.1 riastrad 44 1.1 riastrad /** 45 1.1 riastrad * struct vmw_cotable - Context Object Table resource 46 1.1 riastrad * 47 1.1 riastrad * @res: struct vmw_resource we are deriving from. 48 1.1 riastrad * @ctx: non-refcounted pointer to the owning context. 49 1.1 riastrad * @size_read_back: Size of data read back during eviction. 50 1.1 riastrad * @seen_entries: Seen entries in command stream for this cotable. 51 1.1 riastrad * @type: The cotable type. 52 1.1 riastrad * @scrubbed: Whether the cotable has been scrubbed. 53 1.1 riastrad * @resource_list: List of resources in the cotable. 54 1.1 riastrad */ 55 1.1 riastrad struct vmw_cotable { 56 1.1 riastrad struct vmw_resource res; 57 1.1 riastrad struct vmw_resource *ctx; 58 1.1 riastrad size_t size_read_back; 59 1.1 riastrad int seen_entries; 60 1.1 riastrad u32 type; 61 1.1 riastrad bool scrubbed; 62 1.1 riastrad struct list_head resource_list; 63 1.1 riastrad }; 64 1.1 riastrad 65 1.1 riastrad /** 66 1.1 riastrad * struct vmw_cotable_info - Static info about cotable types 67 1.1 riastrad * 68 1.1 riastrad * @min_initial_entries: Min number of initial intries at cotable allocation 69 1.1 riastrad * for this cotable type. 70 1.1 riastrad * @size: Size of each entry. 71 1.1 riastrad */ 72 1.1 riastrad struct vmw_cotable_info { 73 1.1 riastrad u32 min_initial_entries; 74 1.1 riastrad u32 size; 75 1.1 riastrad void (*unbind_func)(struct vmw_private *, struct list_head *, 76 1.1 riastrad bool); 77 1.1 riastrad }; 78 1.1 riastrad 79 1.1 riastrad static const struct vmw_cotable_info co_info[] = { 80 1.1 riastrad {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy}, 81 1.1 riastrad {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy}, 82 1.1 riastrad {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy}, 83 1.1 riastrad {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, 84 1.1 riastrad {1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, 85 1.1 riastrad {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL}, 86 1.1 riastrad {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL}, 87 1.1 riastrad {1, sizeof(SVGACOTableDXSamplerEntry), NULL}, 88 1.1 riastrad {1, sizeof(SVGACOTableDXStreamOutputEntry), NULL}, 89 1.1 riastrad {1, sizeof(SVGACOTableDXQueryEntry), NULL}, 90 1.1 riastrad {1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub} 91 1.1 riastrad }; 92 1.1 riastrad 93 1.1 riastrad /* 94 1.1 riastrad * Cotables with bindings that we remove must be scrubbed first, 95 1.1 riastrad * otherwise, the device will swap in an invalid context when we remove 96 1.1 riastrad * bindings before scrubbing a cotable... 97 1.1 riastrad */ 98 1.1 riastrad const SVGACOTableType vmw_cotable_scrub_order[] = { 99 1.1 riastrad SVGA_COTABLE_RTVIEW, 100 1.1 riastrad SVGA_COTABLE_DSVIEW, 101 1.1 riastrad SVGA_COTABLE_SRVIEW, 102 1.1 riastrad SVGA_COTABLE_DXSHADER, 103 1.1 riastrad SVGA_COTABLE_ELEMENTLAYOUT, 104 1.1 riastrad SVGA_COTABLE_BLENDSTATE, 105 1.1 riastrad SVGA_COTABLE_DEPTHSTENCIL, 106 1.1 riastrad SVGA_COTABLE_RASTERIZERSTATE, 107 1.1 riastrad SVGA_COTABLE_SAMPLER, 108 1.1 riastrad SVGA_COTABLE_STREAMOUTPUT, 109 1.1 riastrad SVGA_COTABLE_DXQUERY, 110 1.1 riastrad }; 111 1.1 riastrad 112 1.1 riastrad static int vmw_cotable_bind(struct vmw_resource *res, 113 1.1 riastrad struct ttm_validate_buffer *val_buf); 114 1.1 riastrad static int vmw_cotable_unbind(struct vmw_resource *res, 115 1.1 riastrad bool readback, 116 1.1 riastrad struct ttm_validate_buffer *val_buf); 117 1.1 riastrad static int vmw_cotable_create(struct vmw_resource *res); 118 1.1 riastrad static int vmw_cotable_destroy(struct vmw_resource *res); 119 1.1 riastrad 120 1.1 riastrad static const struct vmw_res_func vmw_cotable_func = { 121 1.1 riastrad .res_type = vmw_res_cotable, 122 1.1 riastrad .needs_backup = true, 123 1.1 riastrad .may_evict = true, 124 1.3 riastrad .prio = 3, 125 1.3 riastrad .dirty_prio = 3, 126 1.1 riastrad .type_name = "context guest backed object tables", 127 1.1 riastrad .backup_placement = &vmw_mob_placement, 128 1.1 riastrad .create = vmw_cotable_create, 129 1.1 riastrad .destroy = vmw_cotable_destroy, 130 1.1 riastrad .bind = vmw_cotable_bind, 131 1.1 riastrad .unbind = vmw_cotable_unbind, 132 1.1 riastrad }; 133 1.1 riastrad 134 1.1 riastrad /** 135 1.1 riastrad * vmw_cotable - Convert a struct vmw_resource pointer to a struct 136 1.1 riastrad * vmw_cotable pointer 137 1.1 riastrad * 138 1.1 riastrad * @res: Pointer to the resource. 139 1.1 riastrad */ 140 1.1 riastrad static struct vmw_cotable *vmw_cotable(struct vmw_resource *res) 141 1.1 riastrad { 142 1.1 riastrad return container_of(res, struct vmw_cotable, res); 143 1.1 riastrad } 144 1.1 riastrad 145 1.1 riastrad /** 146 1.1 riastrad * vmw_cotable_destroy - Cotable resource destroy callback 147 1.1 riastrad * 148 1.1 riastrad * @res: Pointer to the cotable resource. 149 1.1 riastrad * 150 1.1 riastrad * There is no device cotable destroy command, so this function only 151 1.1 riastrad * makes sure that the resource id is set to invalid. 152 1.1 riastrad */ 153 1.1 riastrad static int vmw_cotable_destroy(struct vmw_resource *res) 154 1.1 riastrad { 155 1.1 riastrad res->id = -1; 156 1.1 riastrad return 0; 157 1.1 riastrad } 158 1.1 riastrad 159 1.1 riastrad /** 160 1.1 riastrad * vmw_cotable_unscrub - Undo a cotable unscrub operation 161 1.1 riastrad * 162 1.1 riastrad * @res: Pointer to the cotable resource 163 1.1 riastrad * 164 1.1 riastrad * This function issues commands to (re)bind the cotable to 165 1.1 riastrad * its backing mob, which needs to be validated and reserved at this point. 166 1.1 riastrad * This is identical to bind() except the function interface looks different. 167 1.1 riastrad */ 168 1.1 riastrad static int vmw_cotable_unscrub(struct vmw_resource *res) 169 1.1 riastrad { 170 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 171 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 172 1.1 riastrad struct ttm_buffer_object *bo = &res->backup->base; 173 1.1 riastrad struct { 174 1.1 riastrad SVGA3dCmdHeader header; 175 1.1 riastrad SVGA3dCmdDXSetCOTable body; 176 1.1 riastrad } *cmd; 177 1.1 riastrad 178 1.1 riastrad WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); 179 1.3 riastrad dma_resv_assert_held(bo->base.resv); 180 1.1 riastrad 181 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 182 1.3 riastrad if (!cmd) 183 1.1 riastrad return -ENOMEM; 184 1.1 riastrad 185 1.1 riastrad WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID); 186 1.1 riastrad WARN_ON(bo->mem.mem_type != VMW_PL_MOB); 187 1.1 riastrad cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE; 188 1.1 riastrad cmd->header.size = sizeof(cmd->body); 189 1.1 riastrad cmd->body.cid = vcotbl->ctx->id; 190 1.1 riastrad cmd->body.type = vcotbl->type; 191 1.1 riastrad cmd->body.mobid = bo->mem.start; 192 1.1 riastrad cmd->body.validSizeInBytes = vcotbl->size_read_back; 193 1.1 riastrad 194 1.1 riastrad vmw_fifo_commit_flush(dev_priv, sizeof(*cmd)); 195 1.1 riastrad vcotbl->scrubbed = false; 196 1.1 riastrad 197 1.1 riastrad return 0; 198 1.1 riastrad } 199 1.1 riastrad 200 1.1 riastrad /** 201 1.1 riastrad * vmw_cotable_bind - Undo a cotable unscrub operation 202 1.1 riastrad * 203 1.1 riastrad * @res: Pointer to the cotable resource 204 1.1 riastrad * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller 205 1.1 riastrad * for convenience / fencing. 206 1.1 riastrad * 207 1.1 riastrad * This function issues commands to (re)bind the cotable to 208 1.1 riastrad * its backing mob, which needs to be validated and reserved at this point. 209 1.1 riastrad */ 210 1.1 riastrad static int vmw_cotable_bind(struct vmw_resource *res, 211 1.1 riastrad struct ttm_validate_buffer *val_buf) 212 1.1 riastrad { 213 1.1 riastrad /* 214 1.1 riastrad * The create() callback may have changed @res->backup without 215 1.1 riastrad * the caller noticing, and with val_buf->bo still pointing to 216 1.1 riastrad * the old backup buffer. Although hackish, and not used currently, 217 1.1 riastrad * take the opportunity to correct the value here so that it's not 218 1.1 riastrad * misused in the future. 219 1.1 riastrad */ 220 1.1 riastrad val_buf->bo = &res->backup->base; 221 1.1 riastrad 222 1.1 riastrad return vmw_cotable_unscrub(res); 223 1.1 riastrad } 224 1.1 riastrad 225 1.1 riastrad /** 226 1.1 riastrad * vmw_cotable_scrub - Scrub the cotable from the device. 227 1.1 riastrad * 228 1.1 riastrad * @res: Pointer to the cotable resource. 229 1.1 riastrad * @readback: Whether initiate a readback of the cotable data to the backup 230 1.1 riastrad * buffer. 231 1.1 riastrad * 232 1.1 riastrad * In some situations (context swapouts) it might be desirable to make the 233 1.1 riastrad * device forget about the cotable without performing a full unbind. A full 234 1.1 riastrad * unbind requires reserved backup buffers and it might not be possible to 235 1.1 riastrad * reserve them due to locking order violation issues. The vmw_cotable_scrub 236 1.1 riastrad * function implements a partial unbind() without that requirement but with the 237 1.1 riastrad * following restrictions. 238 1.1 riastrad * 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must 239 1.1 riastrad * be called. 240 1.1 riastrad * 2) Before the cotable backing buffer is used by the CPU, or during the 241 1.1 riastrad * resource destruction, vmw_cotable_unbind() must be called. 242 1.1 riastrad */ 243 1.1 riastrad int vmw_cotable_scrub(struct vmw_resource *res, bool readback) 244 1.1 riastrad { 245 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 246 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 247 1.1 riastrad size_t submit_size; 248 1.1 riastrad 249 1.1 riastrad struct { 250 1.1 riastrad SVGA3dCmdHeader header; 251 1.1 riastrad SVGA3dCmdDXReadbackCOTable body; 252 1.1 riastrad } *cmd0; 253 1.1 riastrad struct { 254 1.1 riastrad SVGA3dCmdHeader header; 255 1.1 riastrad SVGA3dCmdDXSetCOTable body; 256 1.1 riastrad } *cmd1; 257 1.1 riastrad 258 1.1 riastrad if (vcotbl->scrubbed) 259 1.1 riastrad return 0; 260 1.1 riastrad 261 1.1 riastrad if (co_info[vcotbl->type].unbind_func) 262 1.1 riastrad co_info[vcotbl->type].unbind_func(dev_priv, 263 1.1 riastrad &vcotbl->resource_list, 264 1.1 riastrad readback); 265 1.1 riastrad submit_size = sizeof(*cmd1); 266 1.1 riastrad if (readback) 267 1.1 riastrad submit_size += sizeof(*cmd0); 268 1.1 riastrad 269 1.3 riastrad cmd1 = VMW_FIFO_RESERVE(dev_priv, submit_size); 270 1.3 riastrad if (!cmd1) 271 1.1 riastrad return -ENOMEM; 272 1.1 riastrad 273 1.1 riastrad vcotbl->size_read_back = 0; 274 1.1 riastrad if (readback) { 275 1.1 riastrad cmd0 = (void *) cmd1; 276 1.1 riastrad cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE; 277 1.1 riastrad cmd0->header.size = sizeof(cmd0->body); 278 1.1 riastrad cmd0->body.cid = vcotbl->ctx->id; 279 1.1 riastrad cmd0->body.type = vcotbl->type; 280 1.1 riastrad cmd1 = (void *) &cmd0[1]; 281 1.1 riastrad vcotbl->size_read_back = res->backup_size; 282 1.1 riastrad } 283 1.1 riastrad cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE; 284 1.1 riastrad cmd1->header.size = sizeof(cmd1->body); 285 1.1 riastrad cmd1->body.cid = vcotbl->ctx->id; 286 1.1 riastrad cmd1->body.type = vcotbl->type; 287 1.1 riastrad cmd1->body.mobid = SVGA3D_INVALID_ID; 288 1.1 riastrad cmd1->body.validSizeInBytes = 0; 289 1.1 riastrad vmw_fifo_commit_flush(dev_priv, submit_size); 290 1.1 riastrad vcotbl->scrubbed = true; 291 1.1 riastrad 292 1.1 riastrad /* Trigger a create() on next validate. */ 293 1.1 riastrad res->id = -1; 294 1.1 riastrad 295 1.1 riastrad return 0; 296 1.1 riastrad } 297 1.1 riastrad 298 1.1 riastrad /** 299 1.1 riastrad * vmw_cotable_unbind - Cotable resource unbind callback 300 1.1 riastrad * 301 1.1 riastrad * @res: Pointer to the cotable resource. 302 1.1 riastrad * @readback: Whether to read back cotable data to the backup buffer. 303 1.1 riastrad * val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller 304 1.1 riastrad * for convenience / fencing. 305 1.1 riastrad * 306 1.1 riastrad * Unbinds the cotable from the device and fences the backup buffer. 307 1.1 riastrad */ 308 1.1 riastrad static int vmw_cotable_unbind(struct vmw_resource *res, 309 1.1 riastrad bool readback, 310 1.1 riastrad struct ttm_validate_buffer *val_buf) 311 1.1 riastrad { 312 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 313 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 314 1.1 riastrad struct ttm_buffer_object *bo = val_buf->bo; 315 1.1 riastrad struct vmw_fence_obj *fence; 316 1.1 riastrad 317 1.3 riastrad if (!vmw_resource_mob_attached(res)) 318 1.1 riastrad return 0; 319 1.1 riastrad 320 1.1 riastrad WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); 321 1.3 riastrad dma_resv_assert_held(bo->base.resv); 322 1.1 riastrad 323 1.1 riastrad mutex_lock(&dev_priv->binding_mutex); 324 1.1 riastrad if (!vcotbl->scrubbed) 325 1.1 riastrad vmw_dx_context_scrub_cotables(vcotbl->ctx, readback); 326 1.1 riastrad mutex_unlock(&dev_priv->binding_mutex); 327 1.1 riastrad (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 328 1.3 riastrad vmw_bo_fence_single(bo, fence); 329 1.1 riastrad if (likely(fence != NULL)) 330 1.1 riastrad vmw_fence_obj_unreference(&fence); 331 1.1 riastrad 332 1.1 riastrad return 0; 333 1.1 riastrad } 334 1.1 riastrad 335 1.1 riastrad /** 336 1.1 riastrad * vmw_cotable_readback - Read back a cotable without unbinding. 337 1.1 riastrad * 338 1.1 riastrad * @res: The cotable resource. 339 1.1 riastrad * 340 1.1 riastrad * Reads back a cotable to its backing mob without scrubbing the MOB from 341 1.1 riastrad * the cotable. The MOB is fenced for subsequent CPU access. 342 1.1 riastrad */ 343 1.1 riastrad static int vmw_cotable_readback(struct vmw_resource *res) 344 1.1 riastrad { 345 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 346 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 347 1.1 riastrad 348 1.1 riastrad struct { 349 1.1 riastrad SVGA3dCmdHeader header; 350 1.1 riastrad SVGA3dCmdDXReadbackCOTable body; 351 1.1 riastrad } *cmd; 352 1.1 riastrad struct vmw_fence_obj *fence; 353 1.1 riastrad 354 1.1 riastrad if (!vcotbl->scrubbed) { 355 1.3 riastrad cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 356 1.3 riastrad if (!cmd) 357 1.1 riastrad return -ENOMEM; 358 1.3 riastrad 359 1.1 riastrad cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE; 360 1.1 riastrad cmd->header.size = sizeof(cmd->body); 361 1.1 riastrad cmd->body.cid = vcotbl->ctx->id; 362 1.1 riastrad cmd->body.type = vcotbl->type; 363 1.1 riastrad vcotbl->size_read_back = res->backup_size; 364 1.1 riastrad vmw_fifo_commit(dev_priv, sizeof(*cmd)); 365 1.1 riastrad } 366 1.1 riastrad 367 1.1 riastrad (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 368 1.3 riastrad vmw_bo_fence_single(&res->backup->base, fence); 369 1.1 riastrad vmw_fence_obj_unreference(&fence); 370 1.1 riastrad 371 1.1 riastrad return 0; 372 1.1 riastrad } 373 1.1 riastrad 374 1.1 riastrad /** 375 1.1 riastrad * vmw_cotable_resize - Resize a cotable. 376 1.1 riastrad * 377 1.1 riastrad * @res: The cotable resource. 378 1.1 riastrad * @new_size: The new size. 379 1.1 riastrad * 380 1.1 riastrad * Resizes a cotable and binds the new backup buffer. 381 1.1 riastrad * On failure the cotable is left intact. 382 1.1 riastrad * Important! This function may not fail once the MOB switch has been 383 1.1 riastrad * committed to hardware. That would put the device context in an 384 1.1 riastrad * invalid state which we can't currently recover from. 385 1.1 riastrad */ 386 1.1 riastrad static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) 387 1.1 riastrad { 388 1.3 riastrad struct ttm_operation_ctx ctx = { false, false }; 389 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 390 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 391 1.3 riastrad struct vmw_buffer_object *buf, *old_buf = res->backup; 392 1.1 riastrad struct ttm_buffer_object *bo, *old_bo = &res->backup->base; 393 1.1 riastrad size_t old_size = res->backup_size; 394 1.1 riastrad size_t old_size_read_back = vcotbl->size_read_back; 395 1.1 riastrad size_t cur_size_read_back; 396 1.1 riastrad struct ttm_bo_kmap_obj old_map, new_map; 397 1.1 riastrad int ret; 398 1.1 riastrad size_t i; 399 1.1 riastrad 400 1.1 riastrad ret = vmw_cotable_readback(res); 401 1.1 riastrad if (ret) 402 1.1 riastrad return ret; 403 1.1 riastrad 404 1.1 riastrad cur_size_read_back = vcotbl->size_read_back; 405 1.1 riastrad vcotbl->size_read_back = old_size_read_back; 406 1.1 riastrad 407 1.1 riastrad /* 408 1.1 riastrad * While device is processing, Allocate and reserve a buffer object 409 1.1 riastrad * for the new COTable. Initially pin the buffer object to make sure 410 1.1 riastrad * we can use tryreserve without failure. 411 1.1 riastrad */ 412 1.1 riastrad buf = kzalloc(sizeof(*buf), GFP_KERNEL); 413 1.1 riastrad if (!buf) 414 1.1 riastrad return -ENOMEM; 415 1.1 riastrad 416 1.3 riastrad ret = vmw_bo_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, 417 1.3 riastrad true, vmw_bo_bo_free); 418 1.1 riastrad if (ret) { 419 1.1 riastrad DRM_ERROR("Failed initializing new cotable MOB.\n"); 420 1.1 riastrad return ret; 421 1.1 riastrad } 422 1.1 riastrad 423 1.1 riastrad bo = &buf->base; 424 1.3 riastrad WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, NULL)); 425 1.1 riastrad 426 1.3 riastrad ret = ttm_bo_wait(old_bo, false, false); 427 1.1 riastrad if (unlikely(ret != 0)) { 428 1.1 riastrad DRM_ERROR("Failed waiting for cotable unbind.\n"); 429 1.1 riastrad goto out_wait; 430 1.1 riastrad } 431 1.1 riastrad 432 1.1 riastrad /* 433 1.1 riastrad * Do a page by page copy of COTables. This eliminates slow vmap()s. 434 1.1 riastrad * This should really be a TTM utility. 435 1.1 riastrad */ 436 1.1 riastrad for (i = 0; i < old_bo->num_pages; ++i) { 437 1.1 riastrad bool dummy; 438 1.1 riastrad 439 1.1 riastrad ret = ttm_bo_kmap(old_bo, i, 1, &old_map); 440 1.1 riastrad if (unlikely(ret != 0)) { 441 1.1 riastrad DRM_ERROR("Failed mapping old COTable on resize.\n"); 442 1.1 riastrad goto out_wait; 443 1.1 riastrad } 444 1.1 riastrad ret = ttm_bo_kmap(bo, i, 1, &new_map); 445 1.1 riastrad if (unlikely(ret != 0)) { 446 1.1 riastrad DRM_ERROR("Failed mapping new COTable on resize.\n"); 447 1.1 riastrad goto out_map_new; 448 1.1 riastrad } 449 1.1 riastrad memcpy(ttm_kmap_obj_virtual(&new_map, &dummy), 450 1.1 riastrad ttm_kmap_obj_virtual(&old_map, &dummy), 451 1.1 riastrad PAGE_SIZE); 452 1.1 riastrad ttm_bo_kunmap(&new_map); 453 1.1 riastrad ttm_bo_kunmap(&old_map); 454 1.1 riastrad } 455 1.1 riastrad 456 1.1 riastrad /* Unpin new buffer, and switch backup buffers. */ 457 1.3 riastrad ret = ttm_bo_validate(bo, &vmw_mob_placement, &ctx); 458 1.1 riastrad if (unlikely(ret != 0)) { 459 1.1 riastrad DRM_ERROR("Failed validating new COTable backup buffer.\n"); 460 1.1 riastrad goto out_wait; 461 1.1 riastrad } 462 1.1 riastrad 463 1.3 riastrad vmw_resource_mob_detach(res); 464 1.1 riastrad res->backup = buf; 465 1.1 riastrad res->backup_size = new_size; 466 1.1 riastrad vcotbl->size_read_back = cur_size_read_back; 467 1.1 riastrad 468 1.1 riastrad /* 469 1.1 riastrad * Now tell the device to switch. If this fails, then we need to 470 1.1 riastrad * revert the full resize. 471 1.1 riastrad */ 472 1.1 riastrad ret = vmw_cotable_unscrub(res); 473 1.1 riastrad if (ret) { 474 1.1 riastrad DRM_ERROR("Failed switching COTable backup buffer.\n"); 475 1.1 riastrad res->backup = old_buf; 476 1.1 riastrad res->backup_size = old_size; 477 1.1 riastrad vcotbl->size_read_back = old_size_read_back; 478 1.3 riastrad vmw_resource_mob_attach(res); 479 1.1 riastrad goto out_wait; 480 1.1 riastrad } 481 1.1 riastrad 482 1.3 riastrad vmw_resource_mob_attach(res); 483 1.1 riastrad /* Let go of the old mob. */ 484 1.3 riastrad vmw_bo_unreference(&old_buf); 485 1.1 riastrad res->id = vcotbl->type; 486 1.1 riastrad 487 1.1 riastrad return 0; 488 1.1 riastrad 489 1.1 riastrad out_map_new: 490 1.1 riastrad ttm_bo_kunmap(&old_map); 491 1.1 riastrad out_wait: 492 1.1 riastrad ttm_bo_unreserve(bo); 493 1.3 riastrad vmw_bo_unreference(&buf); 494 1.1 riastrad 495 1.1 riastrad return ret; 496 1.1 riastrad } 497 1.1 riastrad 498 1.1 riastrad /** 499 1.1 riastrad * vmw_cotable_create - Cotable resource create callback 500 1.1 riastrad * 501 1.1 riastrad * @res: Pointer to a cotable resource. 502 1.1 riastrad * 503 1.1 riastrad * There is no separate create command for cotables, so this callback, which 504 1.1 riastrad * is called before bind() in the validation sequence is instead used for two 505 1.1 riastrad * things. 506 1.1 riastrad * 1) Unscrub the cotable if it is scrubbed and still attached to a backup 507 1.3 riastrad * buffer. 508 1.1 riastrad * 2) Resize the cotable if needed. 509 1.1 riastrad */ 510 1.1 riastrad static int vmw_cotable_create(struct vmw_resource *res) 511 1.1 riastrad { 512 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 513 1.1 riastrad size_t new_size = res->backup_size; 514 1.1 riastrad size_t needed_size; 515 1.1 riastrad int ret; 516 1.1 riastrad 517 1.1 riastrad /* Check whether we need to resize the cotable */ 518 1.1 riastrad needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size; 519 1.1 riastrad while (needed_size > new_size) 520 1.1 riastrad new_size *= 2; 521 1.1 riastrad 522 1.1 riastrad if (likely(new_size <= res->backup_size)) { 523 1.3 riastrad if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) { 524 1.1 riastrad ret = vmw_cotable_unscrub(res); 525 1.1 riastrad if (ret) 526 1.1 riastrad return ret; 527 1.1 riastrad } 528 1.1 riastrad res->id = vcotbl->type; 529 1.1 riastrad return 0; 530 1.1 riastrad } 531 1.1 riastrad 532 1.1 riastrad return vmw_cotable_resize(res, new_size); 533 1.1 riastrad } 534 1.1 riastrad 535 1.1 riastrad /** 536 1.1 riastrad * vmw_hw_cotable_destroy - Cotable hw_destroy callback 537 1.1 riastrad * 538 1.1 riastrad * @res: Pointer to a cotable resource. 539 1.1 riastrad * 540 1.1 riastrad * The final (part of resource destruction) destroy callback. 541 1.1 riastrad */ 542 1.1 riastrad static void vmw_hw_cotable_destroy(struct vmw_resource *res) 543 1.1 riastrad { 544 1.1 riastrad (void) vmw_cotable_destroy(res); 545 1.1 riastrad } 546 1.1 riastrad 547 1.1 riastrad static size_t cotable_acc_size; 548 1.1 riastrad 549 1.1 riastrad /** 550 1.1 riastrad * vmw_cotable_free - Cotable resource destructor 551 1.1 riastrad * 552 1.1 riastrad * @res: Pointer to a cotable resource. 553 1.1 riastrad */ 554 1.1 riastrad static void vmw_cotable_free(struct vmw_resource *res) 555 1.1 riastrad { 556 1.1 riastrad struct vmw_private *dev_priv = res->dev_priv; 557 1.1 riastrad 558 1.1 riastrad kfree(res); 559 1.1 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size); 560 1.1 riastrad } 561 1.1 riastrad 562 1.1 riastrad /** 563 1.1 riastrad * vmw_cotable_alloc - Create a cotable resource 564 1.1 riastrad * 565 1.1 riastrad * @dev_priv: Pointer to a device private struct. 566 1.1 riastrad * @ctx: Pointer to the context resource. 567 1.1 riastrad * The cotable resource will not add a refcount. 568 1.1 riastrad * @type: The cotable type. 569 1.1 riastrad */ 570 1.1 riastrad struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv, 571 1.1 riastrad struct vmw_resource *ctx, 572 1.1 riastrad u32 type) 573 1.1 riastrad { 574 1.1 riastrad struct vmw_cotable *vcotbl; 575 1.3 riastrad struct ttm_operation_ctx ttm_opt_ctx = { 576 1.3 riastrad .interruptible = true, 577 1.3 riastrad .no_wait_gpu = false 578 1.3 riastrad }; 579 1.1 riastrad int ret; 580 1.1 riastrad u32 num_entries; 581 1.1 riastrad 582 1.1 riastrad if (unlikely(cotable_acc_size == 0)) 583 1.1 riastrad cotable_acc_size = ttm_round_pot(sizeof(struct vmw_cotable)); 584 1.1 riastrad 585 1.1 riastrad ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 586 1.3 riastrad cotable_acc_size, &ttm_opt_ctx); 587 1.1 riastrad if (unlikely(ret)) 588 1.1 riastrad return ERR_PTR(ret); 589 1.1 riastrad 590 1.1 riastrad vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL); 591 1.3 riastrad if (unlikely(!vcotbl)) { 592 1.1 riastrad ret = -ENOMEM; 593 1.1 riastrad goto out_no_alloc; 594 1.1 riastrad } 595 1.1 riastrad 596 1.1 riastrad ret = vmw_resource_init(dev_priv, &vcotbl->res, true, 597 1.1 riastrad vmw_cotable_free, &vmw_cotable_func); 598 1.1 riastrad if (unlikely(ret != 0)) 599 1.1 riastrad goto out_no_init; 600 1.1 riastrad 601 1.1 riastrad INIT_LIST_HEAD(&vcotbl->resource_list); 602 1.1 riastrad vcotbl->res.id = type; 603 1.1 riastrad vcotbl->res.backup_size = PAGE_SIZE; 604 1.1 riastrad num_entries = PAGE_SIZE / co_info[type].size; 605 1.1 riastrad if (num_entries < co_info[type].min_initial_entries) { 606 1.1 riastrad vcotbl->res.backup_size = co_info[type].min_initial_entries * 607 1.1 riastrad co_info[type].size; 608 1.1 riastrad vcotbl->res.backup_size = 609 1.1 riastrad (vcotbl->res.backup_size + PAGE_SIZE - 1) & PAGE_MASK; 610 1.1 riastrad } 611 1.1 riastrad 612 1.1 riastrad vcotbl->scrubbed = true; 613 1.1 riastrad vcotbl->seen_entries = -1; 614 1.1 riastrad vcotbl->type = type; 615 1.1 riastrad vcotbl->ctx = ctx; 616 1.1 riastrad 617 1.3 riastrad vcotbl->res.hw_destroy = vmw_hw_cotable_destroy; 618 1.1 riastrad 619 1.1 riastrad return &vcotbl->res; 620 1.1 riastrad 621 1.1 riastrad out_no_init: 622 1.1 riastrad kfree(vcotbl); 623 1.1 riastrad out_no_alloc: 624 1.1 riastrad ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size); 625 1.1 riastrad return ERR_PTR(ret); 626 1.1 riastrad } 627 1.1 riastrad 628 1.1 riastrad /** 629 1.1 riastrad * vmw_cotable_notify - Notify the cotable about an item creation 630 1.1 riastrad * 631 1.1 riastrad * @res: Pointer to a cotable resource. 632 1.1 riastrad * @id: Item id. 633 1.1 riastrad */ 634 1.1 riastrad int vmw_cotable_notify(struct vmw_resource *res, int id) 635 1.1 riastrad { 636 1.1 riastrad struct vmw_cotable *vcotbl = vmw_cotable(res); 637 1.1 riastrad 638 1.1 riastrad if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) { 639 1.1 riastrad DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n", 640 1.1 riastrad (unsigned) vcotbl->type, id); 641 1.1 riastrad return -EINVAL; 642 1.1 riastrad } 643 1.1 riastrad 644 1.1 riastrad if (vcotbl->seen_entries < id) { 645 1.1 riastrad /* Trigger a call to create() on next validate */ 646 1.1 riastrad res->id = -1; 647 1.1 riastrad vcotbl->seen_entries = id; 648 1.1 riastrad } 649 1.1 riastrad 650 1.1 riastrad return 0; 651 1.1 riastrad } 652 1.1 riastrad 653 1.1 riastrad /** 654 1.1 riastrad * vmw_cotable_add_view - add a view to the cotable's list of active views. 655 1.1 riastrad * 656 1.1 riastrad * @res: pointer struct vmw_resource representing the cotable. 657 1.1 riastrad * @head: pointer to the struct list_head member of the resource, dedicated 658 1.1 riastrad * to the cotable active resource list. 659 1.1 riastrad */ 660 1.1 riastrad void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head) 661 1.1 riastrad { 662 1.1 riastrad struct vmw_cotable *vcotbl = 663 1.1 riastrad container_of(res, struct vmw_cotable, res); 664 1.1 riastrad 665 1.1 riastrad list_add_tail(head, &vcotbl->resource_list); 666 1.1 riastrad } 667