162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "vmwgfx_bo.h" 2962306a36Sopenharmony_ci#include "vmwgfx_drv.h" 3062306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h" 3162306a36Sopenharmony_ci#include "vmwgfx_so.h" 3262306a36Sopenharmony_ci#include "vmwgfx_binding.h" 3362306a36Sopenharmony_ci#include "vmw_surface_cache.h" 3462306a36Sopenharmony_ci#include "device_include/svga3d_surfacedefs.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) 3962306a36Sopenharmony_ci#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) 4062306a36Sopenharmony_ci#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ 4162306a36Sopenharmony_ci (svga3d_flags & ((uint64_t)U32_MAX)) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * struct vmw_user_surface - User-space visible surface resource 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * @prime: The TTM prime object. 4762306a36Sopenharmony_ci * @base: The TTM base object handling user-space visibility. 4862306a36Sopenharmony_ci * @srf: The surface metadata. 4962306a36Sopenharmony_ci * @master: Master of the creating client. Used for security check. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistruct vmw_user_surface { 5262306a36Sopenharmony_ci struct ttm_prime_object prime; 5362306a36Sopenharmony_ci struct vmw_surface srf; 5462306a36Sopenharmony_ci struct drm_master *master; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * struct vmw_surface_offset - Backing store mip level offset info 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * @face: Surface face. 6162306a36Sopenharmony_ci * @mip: Mip level. 6262306a36Sopenharmony_ci * @bo_offset: Offset into backing store of this mip level. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cistruct vmw_surface_offset { 6662306a36Sopenharmony_ci uint32_t face; 6762306a36Sopenharmony_ci uint32_t mip; 6862306a36Sopenharmony_ci uint32_t bo_offset; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/** 7262306a36Sopenharmony_ci * struct vmw_surface_dirty - Surface dirty-tracker 7362306a36Sopenharmony_ci * @cache: Cached layout information of the surface. 7462306a36Sopenharmony_ci * @num_subres: Number of subresources. 7562306a36Sopenharmony_ci * @boxes: Array of SVGA3dBoxes indicating dirty regions. One per subresource. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistruct vmw_surface_dirty { 7862306a36Sopenharmony_ci struct vmw_surface_cache cache; 7962306a36Sopenharmony_ci u32 num_subres; 8062306a36Sopenharmony_ci SVGA3dBox boxes[]; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void vmw_user_surface_free(struct vmw_resource *res); 8462306a36Sopenharmony_cistatic struct vmw_resource * 8562306a36Sopenharmony_civmw_user_surface_base_to_res(struct ttm_base_object *base); 8662306a36Sopenharmony_cistatic int vmw_legacy_srf_bind(struct vmw_resource *res, 8762306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 8862306a36Sopenharmony_cistatic int vmw_legacy_srf_unbind(struct vmw_resource *res, 8962306a36Sopenharmony_ci bool readback, 9062306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 9162306a36Sopenharmony_cistatic int vmw_legacy_srf_create(struct vmw_resource *res); 9262306a36Sopenharmony_cistatic int vmw_legacy_srf_destroy(struct vmw_resource *res); 9362306a36Sopenharmony_cistatic int vmw_gb_surface_create(struct vmw_resource *res); 9462306a36Sopenharmony_cistatic int vmw_gb_surface_bind(struct vmw_resource *res, 9562306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 9662306a36Sopenharmony_cistatic int vmw_gb_surface_unbind(struct vmw_resource *res, 9762306a36Sopenharmony_ci bool readback, 9862306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf); 9962306a36Sopenharmony_cistatic int vmw_gb_surface_destroy(struct vmw_resource *res); 10062306a36Sopenharmony_cistatic int 10162306a36Sopenharmony_civmw_gb_surface_define_internal(struct drm_device *dev, 10262306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req, 10362306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep, 10462306a36Sopenharmony_ci struct drm_file *file_priv); 10562306a36Sopenharmony_cistatic int 10662306a36Sopenharmony_civmw_gb_surface_reference_internal(struct drm_device *dev, 10762306a36Sopenharmony_ci struct drm_vmw_surface_arg *req, 10862306a36Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep, 10962306a36Sopenharmony_ci struct drm_file *file_priv); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void vmw_surface_dirty_free(struct vmw_resource *res); 11262306a36Sopenharmony_cistatic int vmw_surface_dirty_alloc(struct vmw_resource *res); 11362306a36Sopenharmony_cistatic int vmw_surface_dirty_sync(struct vmw_resource *res); 11462306a36Sopenharmony_cistatic void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 11562306a36Sopenharmony_ci size_t end); 11662306a36Sopenharmony_cistatic int vmw_surface_clean(struct vmw_resource *res); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const struct vmw_user_resource_conv user_surface_conv = { 11962306a36Sopenharmony_ci .object_type = VMW_RES_SURFACE, 12062306a36Sopenharmony_ci .base_obj_to_res = vmw_user_surface_base_to_res, 12162306a36Sopenharmony_ci .res_free = vmw_user_surface_free 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciconst struct vmw_user_resource_conv *user_surface_converter = 12562306a36Sopenharmony_ci &user_surface_conv; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const struct vmw_res_func vmw_legacy_surface_func = { 12862306a36Sopenharmony_ci .res_type = vmw_res_surface, 12962306a36Sopenharmony_ci .needs_guest_memory = false, 13062306a36Sopenharmony_ci .may_evict = true, 13162306a36Sopenharmony_ci .prio = 1, 13262306a36Sopenharmony_ci .dirty_prio = 1, 13362306a36Sopenharmony_ci .type_name = "legacy surfaces", 13462306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_GMR, 13562306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM, 13662306a36Sopenharmony_ci .create = &vmw_legacy_srf_create, 13762306a36Sopenharmony_ci .destroy = &vmw_legacy_srf_destroy, 13862306a36Sopenharmony_ci .bind = &vmw_legacy_srf_bind, 13962306a36Sopenharmony_ci .unbind = &vmw_legacy_srf_unbind 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic const struct vmw_res_func vmw_gb_surface_func = { 14362306a36Sopenharmony_ci .res_type = vmw_res_surface, 14462306a36Sopenharmony_ci .needs_guest_memory = true, 14562306a36Sopenharmony_ci .may_evict = true, 14662306a36Sopenharmony_ci .prio = 1, 14762306a36Sopenharmony_ci .dirty_prio = 2, 14862306a36Sopenharmony_ci .type_name = "guest backed surfaces", 14962306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_MOB, 15062306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_MOB, 15162306a36Sopenharmony_ci .create = vmw_gb_surface_create, 15262306a36Sopenharmony_ci .destroy = vmw_gb_surface_destroy, 15362306a36Sopenharmony_ci .bind = vmw_gb_surface_bind, 15462306a36Sopenharmony_ci .unbind = vmw_gb_surface_unbind, 15562306a36Sopenharmony_ci .dirty_alloc = vmw_surface_dirty_alloc, 15662306a36Sopenharmony_ci .dirty_free = vmw_surface_dirty_free, 15762306a36Sopenharmony_ci .dirty_sync = vmw_surface_dirty_sync, 15862306a36Sopenharmony_ci .dirty_range_add = vmw_surface_dirty_range_add, 15962306a36Sopenharmony_ci .clean = vmw_surface_clean, 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * struct vmw_surface_dma - SVGA3D DMA command 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistruct vmw_surface_dma { 16662306a36Sopenharmony_ci SVGA3dCmdHeader header; 16762306a36Sopenharmony_ci SVGA3dCmdSurfaceDMA body; 16862306a36Sopenharmony_ci SVGA3dCopyBox cb; 16962306a36Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix suffix; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * struct vmw_surface_define - SVGA3D Surface Define command 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistruct vmw_surface_define { 17662306a36Sopenharmony_ci SVGA3dCmdHeader header; 17762306a36Sopenharmony_ci SVGA3dCmdDefineSurface body; 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * struct vmw_surface_destroy - SVGA3D Surface Destroy command 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_cistruct vmw_surface_destroy { 18462306a36Sopenharmony_ci SVGA3dCmdHeader header; 18562306a36Sopenharmony_ci SVGA3dCmdDestroySurface body; 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * vmw_surface_dma_size - Compute fifo size for a dma command. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * @srf: Pointer to a struct vmw_surface 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * Computes the required size for a surface dma command for backup or 19562306a36Sopenharmony_ci * restoration of the surface represented by @srf. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_cistatic inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci return srf->metadata.num_sizes * sizeof(struct vmw_surface_dma); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * vmw_surface_define_size - Compute fifo size for a surface define command. 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * @srf: Pointer to a struct vmw_surface 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * Computes the required size for a surface define command for the definition 20962306a36Sopenharmony_ci * of the surface represented by @srf. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci return sizeof(struct vmw_surface_define) + srf->metadata.num_sizes * 21462306a36Sopenharmony_ci sizeof(SVGA3dSize); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/** 21962306a36Sopenharmony_ci * vmw_surface_destroy_size - Compute fifo size for a surface destroy command. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Computes the required size for a surface destroy command for the destruction 22262306a36Sopenharmony_ci * of a hw surface. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic inline uint32_t vmw_surface_destroy_size(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci return sizeof(struct vmw_surface_destroy); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/** 23062306a36Sopenharmony_ci * vmw_surface_destroy_encode - Encode a surface_destroy command. 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * @id: The surface id 23362306a36Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistatic void vmw_surface_destroy_encode(uint32_t id, 23662306a36Sopenharmony_ci void *cmd_space) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *) 23962306a36Sopenharmony_ci cmd_space; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY; 24262306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 24362306a36Sopenharmony_ci cmd->body.sid = id; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/** 24762306a36Sopenharmony_ci * vmw_surface_define_encode - Encode a surface_define command. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * @srf: Pointer to a struct vmw_surface object. 25062306a36Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic void vmw_surface_define_encode(const struct vmw_surface *srf, 25362306a36Sopenharmony_ci void *cmd_space) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct vmw_surface_define *cmd = (struct vmw_surface_define *) 25662306a36Sopenharmony_ci cmd_space; 25762306a36Sopenharmony_ci struct drm_vmw_size *src_size; 25862306a36Sopenharmony_ci SVGA3dSize *cmd_size; 25962306a36Sopenharmony_ci uint32_t cmd_len; 26062306a36Sopenharmony_ci int i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci cmd_len = sizeof(cmd->body) + srf->metadata.num_sizes * 26362306a36Sopenharmony_ci sizeof(SVGA3dSize); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE; 26662306a36Sopenharmony_ci cmd->header.size = cmd_len; 26762306a36Sopenharmony_ci cmd->body.sid = srf->res.id; 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * Downcast of surfaceFlags, was upcasted when received from user-space, 27062306a36Sopenharmony_ci * since driver internally stores as 64 bit. 27162306a36Sopenharmony_ci * For legacy surface define only 32 bit flag is supported. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci cmd->body.surfaceFlags = (SVGA3dSurface1Flags)srf->metadata.flags; 27462306a36Sopenharmony_ci cmd->body.format = srf->metadata.format; 27562306a36Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) 27662306a36Sopenharmony_ci cmd->body.face[i].numMipLevels = srf->metadata.mip_levels[i]; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci cmd += 1; 27962306a36Sopenharmony_ci cmd_size = (SVGA3dSize *) cmd; 28062306a36Sopenharmony_ci src_size = srf->metadata.sizes; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < srf->metadata.num_sizes; ++i, cmd_size++, src_size++) { 28362306a36Sopenharmony_ci cmd_size->width = src_size->width; 28462306a36Sopenharmony_ci cmd_size->height = src_size->height; 28562306a36Sopenharmony_ci cmd_size->depth = src_size->depth; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/** 29062306a36Sopenharmony_ci * vmw_surface_dma_encode - Encode a surface_dma command. 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * @srf: Pointer to a struct vmw_surface object. 29362306a36Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 29462306a36Sopenharmony_ci * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents 29562306a36Sopenharmony_ci * should be placed or read from. 29662306a36Sopenharmony_ci * @to_surface: Boolean whether to DMA to the surface or from the surface. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic void vmw_surface_dma_encode(struct vmw_surface *srf, 29962306a36Sopenharmony_ci void *cmd_space, 30062306a36Sopenharmony_ci const SVGAGuestPtr *ptr, 30162306a36Sopenharmony_ci bool to_surface) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci uint32_t i; 30462306a36Sopenharmony_ci struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space; 30562306a36Sopenharmony_ci const struct SVGA3dSurfaceDesc *desc = 30662306a36Sopenharmony_ci vmw_surface_get_desc(srf->metadata.format); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci for (i = 0; i < srf->metadata.num_sizes; ++i) { 30962306a36Sopenharmony_ci SVGA3dCmdHeader *header = &cmd->header; 31062306a36Sopenharmony_ci SVGA3dCmdSurfaceDMA *body = &cmd->body; 31162306a36Sopenharmony_ci SVGA3dCopyBox *cb = &cmd->cb; 31262306a36Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix; 31362306a36Sopenharmony_ci const struct vmw_surface_offset *cur_offset = &srf->offsets[i]; 31462306a36Sopenharmony_ci const struct drm_vmw_size *cur_size = &srf->metadata.sizes[i]; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci header->id = SVGA_3D_CMD_SURFACE_DMA; 31762306a36Sopenharmony_ci header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci body->guest.ptr = *ptr; 32062306a36Sopenharmony_ci body->guest.ptr.offset += cur_offset->bo_offset; 32162306a36Sopenharmony_ci body->guest.pitch = vmw_surface_calculate_pitch(desc, cur_size); 32262306a36Sopenharmony_ci body->host.sid = srf->res.id; 32362306a36Sopenharmony_ci body->host.face = cur_offset->face; 32462306a36Sopenharmony_ci body->host.mipmap = cur_offset->mip; 32562306a36Sopenharmony_ci body->transfer = ((to_surface) ? SVGA3D_WRITE_HOST_VRAM : 32662306a36Sopenharmony_ci SVGA3D_READ_HOST_VRAM); 32762306a36Sopenharmony_ci cb->x = 0; 32862306a36Sopenharmony_ci cb->y = 0; 32962306a36Sopenharmony_ci cb->z = 0; 33062306a36Sopenharmony_ci cb->srcx = 0; 33162306a36Sopenharmony_ci cb->srcy = 0; 33262306a36Sopenharmony_ci cb->srcz = 0; 33362306a36Sopenharmony_ci cb->w = cur_size->width; 33462306a36Sopenharmony_ci cb->h = cur_size->height; 33562306a36Sopenharmony_ci cb->d = cur_size->depth; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci suffix->suffixSize = sizeof(*suffix); 33862306a36Sopenharmony_ci suffix->maximumOffset = 33962306a36Sopenharmony_ci vmw_surface_get_image_buffer_size(desc, cur_size, 34062306a36Sopenharmony_ci body->guest.pitch); 34162306a36Sopenharmony_ci suffix->flags.discard = 0; 34262306a36Sopenharmony_ci suffix->flags.unsynchronized = 0; 34362306a36Sopenharmony_ci suffix->flags.reserved = 0; 34462306a36Sopenharmony_ci ++cmd; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * vmw_hw_surface_destroy - destroy a Device surface 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * @res: Pointer to a struct vmw_resource embedded in a struct 35362306a36Sopenharmony_ci * vmw_surface. 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Destroys a the device surface associated with a struct vmw_surface if 35662306a36Sopenharmony_ci * any, and adjusts resource count accordingly. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_cistatic void vmw_hw_surface_destroy(struct vmw_resource *res) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 36262306a36Sopenharmony_ci void *cmd; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (res->func->destroy == vmw_gb_surface_destroy) { 36562306a36Sopenharmony_ci (void) vmw_gb_surface_destroy(res); 36662306a36Sopenharmony_ci return; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (res->id != -1) { 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, vmw_surface_destroy_size()); 37262306a36Sopenharmony_ci if (unlikely(!cmd)) 37362306a36Sopenharmony_ci return; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci vmw_surface_destroy_encode(res->id, cmd); 37662306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, vmw_surface_destroy_size()); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * used_memory_size_atomic, or separate lock 38062306a36Sopenharmony_ci * to avoid taking dev_priv::cmdbuf_mutex in 38162306a36Sopenharmony_ci * the destroy path. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci mutex_lock(&dev_priv->cmdbuf_mutex); 38562306a36Sopenharmony_ci dev_priv->used_memory_size -= res->guest_memory_size; 38662306a36Sopenharmony_ci mutex_unlock(&dev_priv->cmdbuf_mutex); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/** 39162306a36Sopenharmony_ci * vmw_legacy_srf_create - Create a device surface as part of the 39262306a36Sopenharmony_ci * resource validation process. 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci * @res: Pointer to a struct vmw_surface. 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * If the surface doesn't have a hw id. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * Returns -EBUSY if there wasn't sufficient device resources to 39962306a36Sopenharmony_ci * complete the validation. Retry after freeing up resources. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * May return other errors if the kernel is out of guest resources. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_cistatic int vmw_legacy_srf_create(struct vmw_resource *res) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 40662306a36Sopenharmony_ci struct vmw_surface *srf; 40762306a36Sopenharmony_ci uint32_t submit_size; 40862306a36Sopenharmony_ci uint8_t *cmd; 40962306a36Sopenharmony_ci int ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (likely(res->id != -1)) 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci srf = vmw_res_to_srf(res); 41562306a36Sopenharmony_ci if (unlikely(dev_priv->used_memory_size + res->guest_memory_size >= 41662306a36Sopenharmony_ci dev_priv->memory_size)) 41762306a36Sopenharmony_ci return -EBUSY; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Alloc id for the resource. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ret = vmw_resource_alloc_id(res); 42462306a36Sopenharmony_ci if (unlikely(ret != 0)) { 42562306a36Sopenharmony_ci DRM_ERROR("Failed to allocate a surface id.\n"); 42662306a36Sopenharmony_ci goto out_no_id; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (unlikely(res->id >= SVGA3D_HB_MAX_SURFACE_IDS)) { 43062306a36Sopenharmony_ci ret = -EBUSY; 43162306a36Sopenharmony_ci goto out_no_fifo; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* 43562306a36Sopenharmony_ci * Encode surface define- commands. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci submit_size = vmw_surface_define_size(srf); 43962306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 44062306a36Sopenharmony_ci if (unlikely(!cmd)) { 44162306a36Sopenharmony_ci ret = -ENOMEM; 44262306a36Sopenharmony_ci goto out_no_fifo; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci vmw_surface_define_encode(srf, cmd); 44662306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 44762306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Surface memory usage accounting. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci dev_priv->used_memory_size += res->guest_memory_size; 45462306a36Sopenharmony_ci return 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciout_no_fifo: 45762306a36Sopenharmony_ci vmw_resource_release_id(res); 45862306a36Sopenharmony_ciout_no_id: 45962306a36Sopenharmony_ci return ret; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/** 46362306a36Sopenharmony_ci * vmw_legacy_srf_dma - Copy backup data to or from a legacy surface. 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 46662306a36Sopenharmony_ci * vmw_surface. 46762306a36Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 46862306a36Sopenharmony_ci * information about the backup buffer. 46962306a36Sopenharmony_ci * @bind: Boolean wether to DMA to the surface. 47062306a36Sopenharmony_ci * 47162306a36Sopenharmony_ci * Transfer backup data to or from a legacy surface as part of the 47262306a36Sopenharmony_ci * validation process. 47362306a36Sopenharmony_ci * May return other errors if the kernel is out of guest resources. 47462306a36Sopenharmony_ci * The backup buffer will be fenced or idle upon successful completion, 47562306a36Sopenharmony_ci * and if the surface needs persistent backup storage, the backup buffer 47662306a36Sopenharmony_ci * will also be returned reserved iff @bind is true. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic int vmw_legacy_srf_dma(struct vmw_resource *res, 47962306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf, 48062306a36Sopenharmony_ci bool bind) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci SVGAGuestPtr ptr; 48362306a36Sopenharmony_ci struct vmw_fence_obj *fence; 48462306a36Sopenharmony_ci uint32_t submit_size; 48562306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 48662306a36Sopenharmony_ci uint8_t *cmd; 48762306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci BUG_ON(!val_buf->bo); 49062306a36Sopenharmony_ci submit_size = vmw_surface_dma_size(srf); 49162306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 49262306a36Sopenharmony_ci if (unlikely(!cmd)) 49362306a36Sopenharmony_ci return -ENOMEM; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci vmw_bo_get_guest_ptr(val_buf->bo, &ptr); 49662306a36Sopenharmony_ci vmw_surface_dma_encode(srf, cmd, &ptr, bind); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* 50162306a36Sopenharmony_ci * Create a fence object and fence the backup buffer. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 50562306a36Sopenharmony_ci &fence, NULL); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci vmw_bo_fence_single(val_buf->bo, fence); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (likely(fence != NULL)) 51062306a36Sopenharmony_ci vmw_fence_obj_unreference(&fence); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * vmw_legacy_srf_bind - Perform a legacy surface bind as part of the 51762306a36Sopenharmony_ci * surface validation process. 51862306a36Sopenharmony_ci * 51962306a36Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 52062306a36Sopenharmony_ci * vmw_surface. 52162306a36Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 52262306a36Sopenharmony_ci * information about the backup buffer. 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * This function will copy backup data to the surface if the 52562306a36Sopenharmony_ci * backup buffer is dirty. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_cistatic int vmw_legacy_srf_bind(struct vmw_resource *res, 52862306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci if (!res->guest_memory_dirty) 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return vmw_legacy_srf_dma(res, val_buf, true); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/** 53862306a36Sopenharmony_ci * vmw_legacy_srf_unbind - Perform a legacy surface unbind as part of the 53962306a36Sopenharmony_ci * surface eviction process. 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 54262306a36Sopenharmony_ci * vmw_surface. 54362306a36Sopenharmony_ci * @readback: Readback - only true if dirty 54462306a36Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 54562306a36Sopenharmony_ci * information about the backup buffer. 54662306a36Sopenharmony_ci * 54762306a36Sopenharmony_ci * This function will copy backup data from the surface. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic int vmw_legacy_srf_unbind(struct vmw_resource *res, 55062306a36Sopenharmony_ci bool readback, 55162306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci if (unlikely(readback)) 55462306a36Sopenharmony_ci return vmw_legacy_srf_dma(res, val_buf, false); 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/** 55962306a36Sopenharmony_ci * vmw_legacy_srf_destroy - Destroy a device surface as part of a 56062306a36Sopenharmony_ci * resource eviction process. 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 56362306a36Sopenharmony_ci * vmw_surface. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic int vmw_legacy_srf_destroy(struct vmw_resource *res) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 56862306a36Sopenharmony_ci uint32_t submit_size; 56962306a36Sopenharmony_ci uint8_t *cmd; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci BUG_ON(res->id == -1); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * Encode the dma- and surface destroy commands. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci submit_size = vmw_surface_destroy_size(); 57862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 57962306a36Sopenharmony_ci if (unlikely(!cmd)) 58062306a36Sopenharmony_ci return -ENOMEM; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci vmw_surface_destroy_encode(res->id, cmd); 58362306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * Surface memory usage accounting. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci dev_priv->used_memory_size -= res->guest_memory_size; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * Release the surface ID. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci vmw_resource_release_id(res); 59662306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/** 60362306a36Sopenharmony_ci * vmw_surface_init - initialize a struct vmw_surface 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci * @dev_priv: Pointer to a device private struct. 60662306a36Sopenharmony_ci * @srf: Pointer to the struct vmw_surface to initialize. 60762306a36Sopenharmony_ci * @res_free: Pointer to a resource destructor used to free 60862306a36Sopenharmony_ci * the object. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_cistatic int vmw_surface_init(struct vmw_private *dev_priv, 61162306a36Sopenharmony_ci struct vmw_surface *srf, 61262306a36Sopenharmony_ci void (*res_free) (struct vmw_resource *res)) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci int ret; 61562306a36Sopenharmony_ci struct vmw_resource *res = &srf->res; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci BUG_ON(!res_free); 61862306a36Sopenharmony_ci ret = vmw_resource_init(dev_priv, res, true, res_free, 61962306a36Sopenharmony_ci (dev_priv->has_mob) ? &vmw_gb_surface_func : 62062306a36Sopenharmony_ci &vmw_legacy_surface_func); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (unlikely(ret != 0)) { 62362306a36Sopenharmony_ci res_free(res); 62462306a36Sopenharmony_ci return ret; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* 62862306a36Sopenharmony_ci * The surface won't be visible to hardware until a 62962306a36Sopenharmony_ci * surface validate. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci INIT_LIST_HEAD(&srf->view_list); 63362306a36Sopenharmony_ci res->hw_destroy = vmw_hw_surface_destroy; 63462306a36Sopenharmony_ci return ret; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** 63862306a36Sopenharmony_ci * vmw_user_surface_base_to_res - TTM base object to resource converter for 63962306a36Sopenharmony_ci * user visible surfaces 64062306a36Sopenharmony_ci * 64162306a36Sopenharmony_ci * @base: Pointer to a TTM base object 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * Returns the struct vmw_resource embedded in a struct vmw_surface 64462306a36Sopenharmony_ci * for the user-visible object identified by the TTM base object @base. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_cistatic struct vmw_resource * 64762306a36Sopenharmony_civmw_user_surface_base_to_res(struct ttm_base_object *base) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci return &(container_of(base, struct vmw_user_surface, 65062306a36Sopenharmony_ci prime.base)->srf.res); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci/** 65462306a36Sopenharmony_ci * vmw_user_surface_free - User visible surface resource destructor 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * @res: A struct vmw_resource embedded in a struct vmw_surface. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_cistatic void vmw_user_surface_free(struct vmw_resource *res) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 66162306a36Sopenharmony_ci struct vmw_user_surface *user_srf = 66262306a36Sopenharmony_ci container_of(srf, struct vmw_user_surface, srf); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci WARN_ON_ONCE(res->dirty); 66562306a36Sopenharmony_ci if (user_srf->master) 66662306a36Sopenharmony_ci drm_master_put(&user_srf->master); 66762306a36Sopenharmony_ci kfree(srf->offsets); 66862306a36Sopenharmony_ci kfree(srf->metadata.sizes); 66962306a36Sopenharmony_ci kfree(srf->snooper.image); 67062306a36Sopenharmony_ci ttm_prime_object_kfree(user_srf, prime); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/** 67462306a36Sopenharmony_ci * vmw_user_surface_base_release - User visible surface TTM base object destructor 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * @p_base: Pointer to a pointer to a TTM base object 67762306a36Sopenharmony_ci * embedded in a struct vmw_user_surface. 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * Drops the base object's reference on its resource, and the 68062306a36Sopenharmony_ci * pointer pointed to by *p_base is set to NULL. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_cistatic void vmw_user_surface_base_release(struct ttm_base_object **p_base) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct ttm_base_object *base = *p_base; 68562306a36Sopenharmony_ci struct vmw_user_surface *user_srf = 68662306a36Sopenharmony_ci container_of(base, struct vmw_user_surface, prime.base); 68762306a36Sopenharmony_ci struct vmw_resource *res = &user_srf->srf.res; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci *p_base = NULL; 69062306a36Sopenharmony_ci vmw_resource_unreference(&res); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * vmw_surface_destroy_ioctl - Ioctl function implementing 69562306a36Sopenharmony_ci * the user surface destroy functionality. 69662306a36Sopenharmony_ci * 69762306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 69862306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 69962306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ciint vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, 70262306a36Sopenharmony_ci struct drm_file *file_priv) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; 70562306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return ttm_ref_object_base_unref(tfile, arg->sid); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci/** 71162306a36Sopenharmony_ci * vmw_surface_define_ioctl - Ioctl function implementing 71262306a36Sopenharmony_ci * the user surface define functionality. 71362306a36Sopenharmony_ci * 71462306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 71562306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 71662306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ciint vmw_surface_define_ioctl(struct drm_device *dev, void *data, 71962306a36Sopenharmony_ci struct drm_file *file_priv) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 72262306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 72362306a36Sopenharmony_ci struct vmw_surface *srf; 72462306a36Sopenharmony_ci struct vmw_surface_metadata *metadata; 72562306a36Sopenharmony_ci struct vmw_resource *res; 72662306a36Sopenharmony_ci struct vmw_resource *tmp; 72762306a36Sopenharmony_ci union drm_vmw_surface_create_arg *arg = 72862306a36Sopenharmony_ci (union drm_vmw_surface_create_arg *)data; 72962306a36Sopenharmony_ci struct drm_vmw_surface_create_req *req = &arg->req; 73062306a36Sopenharmony_ci struct drm_vmw_surface_arg *rep = &arg->rep; 73162306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 73262306a36Sopenharmony_ci int ret; 73362306a36Sopenharmony_ci int i, j; 73462306a36Sopenharmony_ci uint32_t cur_bo_offset; 73562306a36Sopenharmony_ci struct drm_vmw_size *cur_size; 73662306a36Sopenharmony_ci struct vmw_surface_offset *cur_offset; 73762306a36Sopenharmony_ci uint32_t num_sizes; 73862306a36Sopenharmony_ci const SVGA3dSurfaceDesc *desc; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci num_sizes = 0; 74162306a36Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 74262306a36Sopenharmony_ci if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS) 74362306a36Sopenharmony_ci return -EINVAL; 74462306a36Sopenharmony_ci num_sizes += req->mip_levels[i]; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS || 74862306a36Sopenharmony_ci num_sizes == 0) 74962306a36Sopenharmony_ci return -EINVAL; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci desc = vmw_surface_get_desc(req->format); 75262306a36Sopenharmony_ci if (unlikely(desc->blockDesc == SVGA3DBLOCKDESC_NONE)) { 75362306a36Sopenharmony_ci VMW_DEBUG_USER("Invalid format %d for surface creation.\n", 75462306a36Sopenharmony_ci req->format); 75562306a36Sopenharmony_ci return -EINVAL; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); 75962306a36Sopenharmony_ci if (unlikely(!user_srf)) { 76062306a36Sopenharmony_ci ret = -ENOMEM; 76162306a36Sopenharmony_ci goto out_unlock; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci srf = &user_srf->srf; 76562306a36Sopenharmony_ci metadata = &srf->metadata; 76662306a36Sopenharmony_ci res = &srf->res; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Driver internally stores as 64-bit flags */ 76962306a36Sopenharmony_ci metadata->flags = (SVGA3dSurfaceAllFlags)req->flags; 77062306a36Sopenharmony_ci metadata->format = req->format; 77162306a36Sopenharmony_ci metadata->scanout = req->scanout; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci memcpy(metadata->mip_levels, req->mip_levels, 77462306a36Sopenharmony_ci sizeof(metadata->mip_levels)); 77562306a36Sopenharmony_ci metadata->num_sizes = num_sizes; 77662306a36Sopenharmony_ci metadata->sizes = 77762306a36Sopenharmony_ci memdup_array_user((struct drm_vmw_size __user *)(unsigned long) 77862306a36Sopenharmony_ci req->size_addr, 77962306a36Sopenharmony_ci metadata->num_sizes, sizeof(*metadata->sizes)); 78062306a36Sopenharmony_ci if (IS_ERR(metadata->sizes)) { 78162306a36Sopenharmony_ci ret = PTR_ERR(metadata->sizes); 78262306a36Sopenharmony_ci goto out_no_sizes; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci srf->offsets = kmalloc_array(metadata->num_sizes, sizeof(*srf->offsets), 78562306a36Sopenharmony_ci GFP_KERNEL); 78662306a36Sopenharmony_ci if (unlikely(!srf->offsets)) { 78762306a36Sopenharmony_ci ret = -ENOMEM; 78862306a36Sopenharmony_ci goto out_no_offsets; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci metadata->base_size = *srf->metadata.sizes; 79262306a36Sopenharmony_ci metadata->autogen_filter = SVGA3D_TEX_FILTER_NONE; 79362306a36Sopenharmony_ci metadata->multisample_count = 0; 79462306a36Sopenharmony_ci metadata->multisample_pattern = SVGA3D_MS_PATTERN_NONE; 79562306a36Sopenharmony_ci metadata->quality_level = SVGA3D_MS_QUALITY_NONE; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci cur_bo_offset = 0; 79862306a36Sopenharmony_ci cur_offset = srf->offsets; 79962306a36Sopenharmony_ci cur_size = metadata->sizes; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 80262306a36Sopenharmony_ci for (j = 0; j < metadata->mip_levels[i]; ++j) { 80362306a36Sopenharmony_ci uint32_t stride = vmw_surface_calculate_pitch( 80462306a36Sopenharmony_ci desc, cur_size); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci cur_offset->face = i; 80762306a36Sopenharmony_ci cur_offset->mip = j; 80862306a36Sopenharmony_ci cur_offset->bo_offset = cur_bo_offset; 80962306a36Sopenharmony_ci cur_bo_offset += vmw_surface_get_image_buffer_size 81062306a36Sopenharmony_ci (desc, cur_size, stride); 81162306a36Sopenharmony_ci ++cur_offset; 81262306a36Sopenharmony_ci ++cur_size; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci res->guest_memory_size = cur_bo_offset; 81662306a36Sopenharmony_ci if (metadata->scanout && 81762306a36Sopenharmony_ci metadata->num_sizes == 1 && 81862306a36Sopenharmony_ci metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 81962306a36Sopenharmony_ci metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && 82062306a36Sopenharmony_ci metadata->format == VMW_CURSOR_SNOOP_FORMAT) { 82162306a36Sopenharmony_ci const struct SVGA3dSurfaceDesc *desc = 82262306a36Sopenharmony_ci vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 82362306a36Sopenharmony_ci const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * 82462306a36Sopenharmony_ci VMW_CURSOR_SNOOP_HEIGHT * 82562306a36Sopenharmony_ci desc->pitchBytesPerBlock; 82662306a36Sopenharmony_ci srf->snooper.image = kzalloc(cursor_size_bytes, GFP_KERNEL); 82762306a36Sopenharmony_ci if (!srf->snooper.image) { 82862306a36Sopenharmony_ci DRM_ERROR("Failed to allocate cursor_image\n"); 82962306a36Sopenharmony_ci ret = -ENOMEM; 83062306a36Sopenharmony_ci goto out_no_copy; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci } else { 83362306a36Sopenharmony_ci srf->snooper.image = NULL; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci user_srf->prime.base.shareable = false; 83762306a36Sopenharmony_ci user_srf->prime.base.tfile = NULL; 83862306a36Sopenharmony_ci if (drm_is_primary_client(file_priv)) 83962306a36Sopenharmony_ci user_srf->master = drm_file_get_master(file_priv); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /** 84262306a36Sopenharmony_ci * From this point, the generic resource management functions 84362306a36Sopenharmony_ci * destroy the object on failure. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); 84762306a36Sopenharmony_ci if (unlikely(ret != 0)) 84862306a36Sopenharmony_ci goto out_unlock; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* 85162306a36Sopenharmony_ci * A gb-aware client referencing a shared surface will 85262306a36Sopenharmony_ci * expect a backup buffer to be present. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci if (dev_priv->has_mob && req->shareable) { 85562306a36Sopenharmony_ci struct vmw_bo_params params = { 85662306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_SYS, 85762306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_SYS, 85862306a36Sopenharmony_ci .bo_type = ttm_bo_type_device, 85962306a36Sopenharmony_ci .size = res->guest_memory_size, 86062306a36Sopenharmony_ci .pin = false 86162306a36Sopenharmony_ci }; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci ret = vmw_gem_object_create(dev_priv, 86462306a36Sopenharmony_ci ¶ms, 86562306a36Sopenharmony_ci &res->guest_memory_bo); 86662306a36Sopenharmony_ci if (unlikely(ret != 0)) { 86762306a36Sopenharmony_ci vmw_resource_unreference(&res); 86862306a36Sopenharmony_ci goto out_unlock; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci tmp = vmw_resource_reference(&srf->res); 87362306a36Sopenharmony_ci ret = ttm_prime_object_init(tfile, res->guest_memory_size, &user_srf->prime, 87462306a36Sopenharmony_ci req->shareable, VMW_RES_SURFACE, 87562306a36Sopenharmony_ci &vmw_user_surface_base_release); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (unlikely(ret != 0)) { 87862306a36Sopenharmony_ci vmw_resource_unreference(&tmp); 87962306a36Sopenharmony_ci vmw_resource_unreference(&res); 88062306a36Sopenharmony_ci goto out_unlock; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci rep->sid = user_srf->prime.base.handle; 88462306a36Sopenharmony_ci vmw_resource_unreference(&res); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ciout_no_copy: 88862306a36Sopenharmony_ci kfree(srf->offsets); 88962306a36Sopenharmony_ciout_no_offsets: 89062306a36Sopenharmony_ci kfree(metadata->sizes); 89162306a36Sopenharmony_ciout_no_sizes: 89262306a36Sopenharmony_ci ttm_prime_object_kfree(user_srf, prime); 89362306a36Sopenharmony_ciout_unlock: 89462306a36Sopenharmony_ci return ret; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int 89962306a36Sopenharmony_civmw_surface_handle_reference(struct vmw_private *dev_priv, 90062306a36Sopenharmony_ci struct drm_file *file_priv, 90162306a36Sopenharmony_ci uint32_t u_handle, 90262306a36Sopenharmony_ci enum drm_vmw_handle_type handle_type, 90362306a36Sopenharmony_ci struct ttm_base_object **base_p) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 90662306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 90762306a36Sopenharmony_ci uint32_t handle; 90862306a36Sopenharmony_ci struct ttm_base_object *base; 90962306a36Sopenharmony_ci int ret; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (handle_type == DRM_VMW_HANDLE_PRIME) { 91262306a36Sopenharmony_ci ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); 91362306a36Sopenharmony_ci if (unlikely(ret != 0)) 91462306a36Sopenharmony_ci return ret; 91562306a36Sopenharmony_ci } else { 91662306a36Sopenharmony_ci handle = u_handle; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci ret = -EINVAL; 92062306a36Sopenharmony_ci base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle); 92162306a36Sopenharmony_ci if (unlikely(!base)) { 92262306a36Sopenharmony_ci VMW_DEBUG_USER("Could not find surface to reference.\n"); 92362306a36Sopenharmony_ci goto out_no_lookup; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) { 92762306a36Sopenharmony_ci VMW_DEBUG_USER("Referenced object is not a surface.\n"); 92862306a36Sopenharmony_ci goto out_bad_resource; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci if (handle_type != DRM_VMW_HANDLE_PRIME) { 93162306a36Sopenharmony_ci bool require_exist = false; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, 93462306a36Sopenharmony_ci prime.base); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Error out if we are unauthenticated primary */ 93762306a36Sopenharmony_ci if (drm_is_primary_client(file_priv) && 93862306a36Sopenharmony_ci !file_priv->authenticated) { 93962306a36Sopenharmony_ci ret = -EACCES; 94062306a36Sopenharmony_ci goto out_bad_resource; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * Make sure the surface creator has the same 94562306a36Sopenharmony_ci * authenticating master, or is already registered with us. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci if (drm_is_primary_client(file_priv) && 94862306a36Sopenharmony_ci user_srf->master != file_priv->master) 94962306a36Sopenharmony_ci require_exist = true; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (unlikely(drm_is_render_client(file_priv))) 95262306a36Sopenharmony_ci require_exist = true; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci ret = ttm_ref_object_add(tfile, base, NULL, require_exist); 95562306a36Sopenharmony_ci if (unlikely(ret != 0)) { 95662306a36Sopenharmony_ci DRM_ERROR("Could not add a reference to a surface.\n"); 95762306a36Sopenharmony_ci goto out_bad_resource; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci *base_p = base; 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ciout_bad_resource: 96562306a36Sopenharmony_ci ttm_base_object_unref(&base); 96662306a36Sopenharmony_ciout_no_lookup: 96762306a36Sopenharmony_ci if (handle_type == DRM_VMW_HANDLE_PRIME) 96862306a36Sopenharmony_ci (void) ttm_ref_object_base_unref(tfile, handle); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci return ret; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/** 97462306a36Sopenharmony_ci * vmw_surface_reference_ioctl - Ioctl function implementing 97562306a36Sopenharmony_ci * the user surface reference functionality. 97662306a36Sopenharmony_ci * 97762306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 97862306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 97962306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ciint vmw_surface_reference_ioctl(struct drm_device *dev, void *data, 98262306a36Sopenharmony_ci struct drm_file *file_priv) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 98562306a36Sopenharmony_ci union drm_vmw_surface_reference_arg *arg = 98662306a36Sopenharmony_ci (union drm_vmw_surface_reference_arg *)data; 98762306a36Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 98862306a36Sopenharmony_ci struct drm_vmw_surface_create_req *rep = &arg->rep; 98962306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 99062306a36Sopenharmony_ci struct vmw_surface *srf; 99162306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 99262306a36Sopenharmony_ci struct drm_vmw_size __user *user_sizes; 99362306a36Sopenharmony_ci struct ttm_base_object *base; 99462306a36Sopenharmony_ci int ret; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, 99762306a36Sopenharmony_ci req->handle_type, &base); 99862306a36Sopenharmony_ci if (unlikely(ret != 0)) 99962306a36Sopenharmony_ci return ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, prime.base); 100262306a36Sopenharmony_ci srf = &user_srf->srf; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Downcast of flags when sending back to user space */ 100562306a36Sopenharmony_ci rep->flags = (uint32_t)srf->metadata.flags; 100662306a36Sopenharmony_ci rep->format = srf->metadata.format; 100762306a36Sopenharmony_ci memcpy(rep->mip_levels, srf->metadata.mip_levels, 100862306a36Sopenharmony_ci sizeof(srf->metadata.mip_levels)); 100962306a36Sopenharmony_ci user_sizes = (struct drm_vmw_size __user *)(unsigned long) 101062306a36Sopenharmony_ci rep->size_addr; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (user_sizes) 101362306a36Sopenharmony_ci ret = copy_to_user(user_sizes, &srf->metadata.base_size, 101462306a36Sopenharmony_ci sizeof(srf->metadata.base_size)); 101562306a36Sopenharmony_ci if (unlikely(ret != 0)) { 101662306a36Sopenharmony_ci VMW_DEBUG_USER("copy_to_user failed %p %u\n", user_sizes, 101762306a36Sopenharmony_ci srf->metadata.num_sizes); 101862306a36Sopenharmony_ci ttm_ref_object_base_unref(tfile, base->handle); 101962306a36Sopenharmony_ci ret = -EFAULT; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci ttm_base_object_unref(&base); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return ret; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci/** 102862306a36Sopenharmony_ci * vmw_gb_surface_create - Encode a surface_define command. 102962306a36Sopenharmony_ci * 103062306a36Sopenharmony_ci * @res: Pointer to a struct vmw_resource embedded in a struct 103162306a36Sopenharmony_ci * vmw_surface. 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_cistatic int vmw_gb_surface_create(struct vmw_resource *res) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 103662306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 103762306a36Sopenharmony_ci struct vmw_surface_metadata *metadata = &srf->metadata; 103862306a36Sopenharmony_ci uint32_t cmd_len, cmd_id, submit_len; 103962306a36Sopenharmony_ci int ret; 104062306a36Sopenharmony_ci struct { 104162306a36Sopenharmony_ci SVGA3dCmdHeader header; 104262306a36Sopenharmony_ci SVGA3dCmdDefineGBSurface body; 104362306a36Sopenharmony_ci } *cmd; 104462306a36Sopenharmony_ci struct { 104562306a36Sopenharmony_ci SVGA3dCmdHeader header; 104662306a36Sopenharmony_ci SVGA3dCmdDefineGBSurface_v2 body; 104762306a36Sopenharmony_ci } *cmd2; 104862306a36Sopenharmony_ci struct { 104962306a36Sopenharmony_ci SVGA3dCmdHeader header; 105062306a36Sopenharmony_ci SVGA3dCmdDefineGBSurface_v3 body; 105162306a36Sopenharmony_ci } *cmd3; 105262306a36Sopenharmony_ci struct { 105362306a36Sopenharmony_ci SVGA3dCmdHeader header; 105462306a36Sopenharmony_ci SVGA3dCmdDefineGBSurface_v4 body; 105562306a36Sopenharmony_ci } *cmd4; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (likely(res->id != -1)) 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 106162306a36Sopenharmony_ci ret = vmw_resource_alloc_id(res); 106262306a36Sopenharmony_ci if (unlikely(ret != 0)) { 106362306a36Sopenharmony_ci DRM_ERROR("Failed to allocate a surface id.\n"); 106462306a36Sopenharmony_ci goto out_no_id; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) { 106862306a36Sopenharmony_ci ret = -EBUSY; 106962306a36Sopenharmony_ci goto out_no_fifo; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (has_sm5_context(dev_priv) && metadata->array_size > 0) { 107362306a36Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V4; 107462306a36Sopenharmony_ci cmd_len = sizeof(cmd4->body); 107562306a36Sopenharmony_ci submit_len = sizeof(*cmd4); 107662306a36Sopenharmony_ci } else if (has_sm4_1_context(dev_priv) && metadata->array_size > 0) { 107762306a36Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V3; 107862306a36Sopenharmony_ci cmd_len = sizeof(cmd3->body); 107962306a36Sopenharmony_ci submit_len = sizeof(*cmd3); 108062306a36Sopenharmony_ci } else if (metadata->array_size > 0) { 108162306a36Sopenharmony_ci /* VMW_SM_4 support verified at creation time. */ 108262306a36Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2; 108362306a36Sopenharmony_ci cmd_len = sizeof(cmd2->body); 108462306a36Sopenharmony_ci submit_len = sizeof(*cmd2); 108562306a36Sopenharmony_ci } else { 108662306a36Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE; 108762306a36Sopenharmony_ci cmd_len = sizeof(cmd->body); 108862306a36Sopenharmony_ci submit_len = sizeof(*cmd); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_len); 109262306a36Sopenharmony_ci cmd2 = (typeof(cmd2))cmd; 109362306a36Sopenharmony_ci cmd3 = (typeof(cmd3))cmd; 109462306a36Sopenharmony_ci cmd4 = (typeof(cmd4))cmd; 109562306a36Sopenharmony_ci if (unlikely(!cmd)) { 109662306a36Sopenharmony_ci ret = -ENOMEM; 109762306a36Sopenharmony_ci goto out_no_fifo; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (has_sm5_context(dev_priv) && metadata->array_size > 0) { 110162306a36Sopenharmony_ci cmd4->header.id = cmd_id; 110262306a36Sopenharmony_ci cmd4->header.size = cmd_len; 110362306a36Sopenharmony_ci cmd4->body.sid = srf->res.id; 110462306a36Sopenharmony_ci cmd4->body.surfaceFlags = metadata->flags; 110562306a36Sopenharmony_ci cmd4->body.format = metadata->format; 110662306a36Sopenharmony_ci cmd4->body.numMipLevels = metadata->mip_levels[0]; 110762306a36Sopenharmony_ci cmd4->body.multisampleCount = metadata->multisample_count; 110862306a36Sopenharmony_ci cmd4->body.multisamplePattern = metadata->multisample_pattern; 110962306a36Sopenharmony_ci cmd4->body.qualityLevel = metadata->quality_level; 111062306a36Sopenharmony_ci cmd4->body.autogenFilter = metadata->autogen_filter; 111162306a36Sopenharmony_ci cmd4->body.size.width = metadata->base_size.width; 111262306a36Sopenharmony_ci cmd4->body.size.height = metadata->base_size.height; 111362306a36Sopenharmony_ci cmd4->body.size.depth = metadata->base_size.depth; 111462306a36Sopenharmony_ci cmd4->body.arraySize = metadata->array_size; 111562306a36Sopenharmony_ci cmd4->body.bufferByteStride = metadata->buffer_byte_stride; 111662306a36Sopenharmony_ci } else if (has_sm4_1_context(dev_priv) && metadata->array_size > 0) { 111762306a36Sopenharmony_ci cmd3->header.id = cmd_id; 111862306a36Sopenharmony_ci cmd3->header.size = cmd_len; 111962306a36Sopenharmony_ci cmd3->body.sid = srf->res.id; 112062306a36Sopenharmony_ci cmd3->body.surfaceFlags = metadata->flags; 112162306a36Sopenharmony_ci cmd3->body.format = metadata->format; 112262306a36Sopenharmony_ci cmd3->body.numMipLevels = metadata->mip_levels[0]; 112362306a36Sopenharmony_ci cmd3->body.multisampleCount = metadata->multisample_count; 112462306a36Sopenharmony_ci cmd3->body.multisamplePattern = metadata->multisample_pattern; 112562306a36Sopenharmony_ci cmd3->body.qualityLevel = metadata->quality_level; 112662306a36Sopenharmony_ci cmd3->body.autogenFilter = metadata->autogen_filter; 112762306a36Sopenharmony_ci cmd3->body.size.width = metadata->base_size.width; 112862306a36Sopenharmony_ci cmd3->body.size.height = metadata->base_size.height; 112962306a36Sopenharmony_ci cmd3->body.size.depth = metadata->base_size.depth; 113062306a36Sopenharmony_ci cmd3->body.arraySize = metadata->array_size; 113162306a36Sopenharmony_ci } else if (metadata->array_size > 0) { 113262306a36Sopenharmony_ci cmd2->header.id = cmd_id; 113362306a36Sopenharmony_ci cmd2->header.size = cmd_len; 113462306a36Sopenharmony_ci cmd2->body.sid = srf->res.id; 113562306a36Sopenharmony_ci cmd2->body.surfaceFlags = metadata->flags; 113662306a36Sopenharmony_ci cmd2->body.format = metadata->format; 113762306a36Sopenharmony_ci cmd2->body.numMipLevels = metadata->mip_levels[0]; 113862306a36Sopenharmony_ci cmd2->body.multisampleCount = metadata->multisample_count; 113962306a36Sopenharmony_ci cmd2->body.autogenFilter = metadata->autogen_filter; 114062306a36Sopenharmony_ci cmd2->body.size.width = metadata->base_size.width; 114162306a36Sopenharmony_ci cmd2->body.size.height = metadata->base_size.height; 114262306a36Sopenharmony_ci cmd2->body.size.depth = metadata->base_size.depth; 114362306a36Sopenharmony_ci cmd2->body.arraySize = metadata->array_size; 114462306a36Sopenharmony_ci } else { 114562306a36Sopenharmony_ci cmd->header.id = cmd_id; 114662306a36Sopenharmony_ci cmd->header.size = cmd_len; 114762306a36Sopenharmony_ci cmd->body.sid = srf->res.id; 114862306a36Sopenharmony_ci cmd->body.surfaceFlags = metadata->flags; 114962306a36Sopenharmony_ci cmd->body.format = metadata->format; 115062306a36Sopenharmony_ci cmd->body.numMipLevels = metadata->mip_levels[0]; 115162306a36Sopenharmony_ci cmd->body.multisampleCount = metadata->multisample_count; 115262306a36Sopenharmony_ci cmd->body.autogenFilter = metadata->autogen_filter; 115362306a36Sopenharmony_ci cmd->body.size.width = metadata->base_size.width; 115462306a36Sopenharmony_ci cmd->body.size.height = metadata->base_size.height; 115562306a36Sopenharmony_ci cmd->body.size.depth = metadata->base_size.depth; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_len); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ciout_no_fifo: 116362306a36Sopenharmony_ci vmw_resource_release_id(res); 116462306a36Sopenharmony_ciout_no_id: 116562306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 116662306a36Sopenharmony_ci return ret; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int vmw_gb_surface_bind(struct vmw_resource *res, 117162306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 117462306a36Sopenharmony_ci struct { 117562306a36Sopenharmony_ci SVGA3dCmdHeader header; 117662306a36Sopenharmony_ci SVGA3dCmdBindGBSurface body; 117762306a36Sopenharmony_ci } *cmd1; 117862306a36Sopenharmony_ci struct { 117962306a36Sopenharmony_ci SVGA3dCmdHeader header; 118062306a36Sopenharmony_ci SVGA3dCmdUpdateGBSurface body; 118162306a36Sopenharmony_ci } *cmd2; 118262306a36Sopenharmony_ci uint32_t submit_size; 118362306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci submit_size = sizeof(*cmd1) + (res->guest_memory_dirty ? sizeof(*cmd2) : 0); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci cmd1 = VMW_CMD_RESERVE(dev_priv, submit_size); 119062306a36Sopenharmony_ci if (unlikely(!cmd1)) 119162306a36Sopenharmony_ci return -ENOMEM; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; 119462306a36Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 119562306a36Sopenharmony_ci cmd1->body.sid = res->id; 119662306a36Sopenharmony_ci cmd1->body.mobid = bo->resource->start; 119762306a36Sopenharmony_ci if (res->guest_memory_dirty) { 119862306a36Sopenharmony_ci cmd2 = (void *) &cmd1[1]; 119962306a36Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; 120062306a36Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 120162306a36Sopenharmony_ci cmd2->body.sid = res->id; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (res->guest_memory_bo->dirty && res->guest_memory_dirty) { 120662306a36Sopenharmony_ci /* We've just made a full upload. Cear dirty regions. */ 120762306a36Sopenharmony_ci vmw_bo_dirty_clear_res(res); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci res->guest_memory_dirty = false; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci return 0; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int vmw_gb_surface_unbind(struct vmw_resource *res, 121662306a36Sopenharmony_ci bool readback, 121762306a36Sopenharmony_ci struct ttm_validate_buffer *val_buf) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 122062306a36Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 122162306a36Sopenharmony_ci struct vmw_fence_obj *fence; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci struct { 122462306a36Sopenharmony_ci SVGA3dCmdHeader header; 122562306a36Sopenharmony_ci SVGA3dCmdReadbackGBSurface body; 122662306a36Sopenharmony_ci } *cmd1; 122762306a36Sopenharmony_ci struct { 122862306a36Sopenharmony_ci SVGA3dCmdHeader header; 122962306a36Sopenharmony_ci SVGA3dCmdInvalidateGBSurface body; 123062306a36Sopenharmony_ci } *cmd2; 123162306a36Sopenharmony_ci struct { 123262306a36Sopenharmony_ci SVGA3dCmdHeader header; 123362306a36Sopenharmony_ci SVGA3dCmdBindGBSurface body; 123462306a36Sopenharmony_ci } *cmd3; 123562306a36Sopenharmony_ci uint32_t submit_size; 123662306a36Sopenharmony_ci uint8_t *cmd; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2)); 124262306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, submit_size); 124362306a36Sopenharmony_ci if (unlikely(!cmd)) 124462306a36Sopenharmony_ci return -ENOMEM; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci if (readback) { 124762306a36Sopenharmony_ci cmd1 = (void *) cmd; 124862306a36Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; 124962306a36Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 125062306a36Sopenharmony_ci cmd1->body.sid = res->id; 125162306a36Sopenharmony_ci cmd3 = (void *) &cmd1[1]; 125262306a36Sopenharmony_ci } else { 125362306a36Sopenharmony_ci cmd2 = (void *) cmd; 125462306a36Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE; 125562306a36Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 125662306a36Sopenharmony_ci cmd2->body.sid = res->id; 125762306a36Sopenharmony_ci cmd3 = (void *) &cmd2[1]; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; 126162306a36Sopenharmony_ci cmd3->header.size = sizeof(cmd3->body); 126262306a36Sopenharmony_ci cmd3->body.sid = res->id; 126362306a36Sopenharmony_ci cmd3->body.mobid = SVGA3D_INVALID_ID; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, submit_size); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* 126862306a36Sopenharmony_ci * Create a fence object and fence the backup buffer. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 127262306a36Sopenharmony_ci &fence, NULL); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci vmw_bo_fence_single(val_buf->bo, fence); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (likely(fence != NULL)) 127762306a36Sopenharmony_ci vmw_fence_obj_unreference(&fence); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_cistatic int vmw_gb_surface_destroy(struct vmw_resource *res) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 128562306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 128662306a36Sopenharmony_ci struct { 128762306a36Sopenharmony_ci SVGA3dCmdHeader header; 128862306a36Sopenharmony_ci SVGA3dCmdDestroyGBSurface body; 128962306a36Sopenharmony_ci } *cmd; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (likely(res->id == -1)) 129262306a36Sopenharmony_ci return 0; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci mutex_lock(&dev_priv->binding_mutex); 129562306a36Sopenharmony_ci vmw_view_surface_list_destroy(dev_priv, &srf->view_list); 129662306a36Sopenharmony_ci vmw_binding_res_list_scrub(&res->binding_head); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 129962306a36Sopenharmony_ci if (unlikely(!cmd)) { 130062306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 130162306a36Sopenharmony_ci return -ENOMEM; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE; 130562306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 130662306a36Sopenharmony_ci cmd->body.sid = res->id; 130762306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 130862306a36Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 130962306a36Sopenharmony_ci vmw_resource_release_id(res); 131062306a36Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci return 0; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci/** 131662306a36Sopenharmony_ci * vmw_gb_surface_define_ioctl - Ioctl function implementing 131762306a36Sopenharmony_ci * the user surface define functionality. 131862306a36Sopenharmony_ci * 131962306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 132062306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 132162306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 132262306a36Sopenharmony_ci */ 132362306a36Sopenharmony_ciint vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, 132462306a36Sopenharmony_ci struct drm_file *file_priv) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci union drm_vmw_gb_surface_create_arg *arg = 132762306a36Sopenharmony_ci (union drm_vmw_gb_surface_create_arg *)data; 132862306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; 132962306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req req_ext; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci req_ext.base = arg->req; 133262306a36Sopenharmony_ci req_ext.version = drm_vmw_gb_surface_v1; 133362306a36Sopenharmony_ci req_ext.svga3d_flags_upper_32_bits = 0; 133462306a36Sopenharmony_ci req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; 133562306a36Sopenharmony_ci req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; 133662306a36Sopenharmony_ci req_ext.buffer_byte_stride = 0; 133762306a36Sopenharmony_ci req_ext.must_be_zero = 0; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci/** 134362306a36Sopenharmony_ci * vmw_gb_surface_reference_ioctl - Ioctl function implementing 134462306a36Sopenharmony_ci * the user surface reference functionality. 134562306a36Sopenharmony_ci * 134662306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 134762306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 134862306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 134962306a36Sopenharmony_ci */ 135062306a36Sopenharmony_ciint vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, 135162306a36Sopenharmony_ci struct drm_file *file_priv) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci union drm_vmw_gb_surface_reference_arg *arg = 135462306a36Sopenharmony_ci (union drm_vmw_gb_surface_reference_arg *)data; 135562306a36Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 135662306a36Sopenharmony_ci struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; 135762306a36Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep rep_ext; 135862306a36Sopenharmony_ci int ret; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (unlikely(ret != 0)) 136362306a36Sopenharmony_ci return ret; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci rep->creq = rep_ext.creq.base; 136662306a36Sopenharmony_ci rep->crep = rep_ext.crep; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci return ret; 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci/** 137262306a36Sopenharmony_ci * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing 137362306a36Sopenharmony_ci * the user surface define functionality. 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 137662306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 137762306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_ciint vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, 138062306a36Sopenharmony_ci struct drm_file *file_priv) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci union drm_vmw_gb_surface_create_ext_arg *arg = 138362306a36Sopenharmony_ci (union drm_vmw_gb_surface_create_ext_arg *)data; 138462306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; 138562306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci return vmw_gb_surface_define_internal(dev, req, rep, file_priv); 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci/** 139162306a36Sopenharmony_ci * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing 139262306a36Sopenharmony_ci * the user surface reference functionality. 139362306a36Sopenharmony_ci * 139462306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 139562306a36Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 139662306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 139762306a36Sopenharmony_ci */ 139862306a36Sopenharmony_ciint vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, 139962306a36Sopenharmony_ci struct drm_file *file_priv) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci union drm_vmw_gb_surface_reference_ext_arg *arg = 140262306a36Sopenharmony_ci (union drm_vmw_gb_surface_reference_ext_arg *)data; 140362306a36Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 140462306a36Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci/** 141062306a36Sopenharmony_ci * vmw_gb_surface_define_internal - Ioctl function implementing 141162306a36Sopenharmony_ci * the user surface define functionality. 141262306a36Sopenharmony_ci * 141362306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 141462306a36Sopenharmony_ci * @req: Request argument from user-space. 141562306a36Sopenharmony_ci * @rep: Response argument to user-space. 141662306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_cistatic int 141962306a36Sopenharmony_civmw_gb_surface_define_internal(struct drm_device *dev, 142062306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req, 142162306a36Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep, 142262306a36Sopenharmony_ci struct drm_file *file_priv) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 142562306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 142662306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 142762306a36Sopenharmony_ci struct vmw_surface_metadata metadata = {0}; 142862306a36Sopenharmony_ci struct vmw_surface *srf; 142962306a36Sopenharmony_ci struct vmw_resource *res; 143062306a36Sopenharmony_ci struct vmw_resource *tmp; 143162306a36Sopenharmony_ci int ret = 0; 143262306a36Sopenharmony_ci uint32_t backup_handle = 0; 143362306a36Sopenharmony_ci SVGA3dSurfaceAllFlags svga3d_flags_64 = 143462306a36Sopenharmony_ci SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, 143562306a36Sopenharmony_ci req->base.svga3d_flags); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* array_size must be null for non-GL3 host. */ 143862306a36Sopenharmony_ci if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) { 143962306a36Sopenharmony_ci VMW_DEBUG_USER("SM4 surface not supported.\n"); 144062306a36Sopenharmony_ci return -EINVAL; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (!has_sm4_1_context(dev_priv)) { 144462306a36Sopenharmony_ci if (req->svga3d_flags_upper_32_bits != 0) 144562306a36Sopenharmony_ci ret = -EINVAL; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (req->base.multisample_count != 0) 144862306a36Sopenharmony_ci ret = -EINVAL; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) 145162306a36Sopenharmony_ci ret = -EINVAL; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (req->quality_level != SVGA3D_MS_QUALITY_NONE) 145462306a36Sopenharmony_ci ret = -EINVAL; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (ret) { 145762306a36Sopenharmony_ci VMW_DEBUG_USER("SM4.1 surface not supported.\n"); 145862306a36Sopenharmony_ci return ret; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (req->buffer_byte_stride > 0 && !has_sm5_context(dev_priv)) { 146362306a36Sopenharmony_ci VMW_DEBUG_USER("SM5 surface not supported.\n"); 146462306a36Sopenharmony_ci return -EINVAL; 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if ((svga3d_flags_64 & SVGA3D_SURFACE_MULTISAMPLE) && 146862306a36Sopenharmony_ci req->base.multisample_count == 0) { 146962306a36Sopenharmony_ci VMW_DEBUG_USER("Invalid sample count.\n"); 147062306a36Sopenharmony_ci return -EINVAL; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) { 147462306a36Sopenharmony_ci VMW_DEBUG_USER("Invalid mip level.\n"); 147562306a36Sopenharmony_ci return -EINVAL; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci metadata.flags = svga3d_flags_64; 147962306a36Sopenharmony_ci metadata.format = req->base.format; 148062306a36Sopenharmony_ci metadata.mip_levels[0] = req->base.mip_levels; 148162306a36Sopenharmony_ci metadata.multisample_count = req->base.multisample_count; 148262306a36Sopenharmony_ci metadata.multisample_pattern = req->multisample_pattern; 148362306a36Sopenharmony_ci metadata.quality_level = req->quality_level; 148462306a36Sopenharmony_ci metadata.array_size = req->base.array_size; 148562306a36Sopenharmony_ci metadata.buffer_byte_stride = req->buffer_byte_stride; 148662306a36Sopenharmony_ci metadata.num_sizes = 1; 148762306a36Sopenharmony_ci metadata.base_size = req->base.base_size; 148862306a36Sopenharmony_ci metadata.scanout = req->base.drm_surface_flags & 148962306a36Sopenharmony_ci drm_vmw_surface_flag_scanout; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci /* Define a surface based on the parameters. */ 149262306a36Sopenharmony_ci ret = vmw_gb_surface_define(dev_priv, &metadata, &srf); 149362306a36Sopenharmony_ci if (ret != 0) { 149462306a36Sopenharmony_ci VMW_DEBUG_USER("Failed to define surface.\n"); 149562306a36Sopenharmony_ci return ret; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci user_srf = container_of(srf, struct vmw_user_surface, srf); 149962306a36Sopenharmony_ci if (drm_is_primary_client(file_priv)) 150062306a36Sopenharmony_ci user_srf->master = drm_file_get_master(file_priv); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci res = &user_srf->srf.res; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (req->base.buffer_handle != SVGA3D_INVALID_ID) { 150562306a36Sopenharmony_ci ret = vmw_user_bo_lookup(file_priv, req->base.buffer_handle, 150662306a36Sopenharmony_ci &res->guest_memory_bo); 150762306a36Sopenharmony_ci if (ret == 0) { 150862306a36Sopenharmony_ci if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) { 150962306a36Sopenharmony_ci VMW_DEBUG_USER("Surface backup buffer too small.\n"); 151062306a36Sopenharmony_ci vmw_user_bo_unref(&res->guest_memory_bo); 151162306a36Sopenharmony_ci ret = -EINVAL; 151262306a36Sopenharmony_ci goto out_unlock; 151362306a36Sopenharmony_ci } else { 151462306a36Sopenharmony_ci backup_handle = req->base.buffer_handle; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci } else if (req->base.drm_surface_flags & 151862306a36Sopenharmony_ci (drm_vmw_surface_flag_create_buffer | 151962306a36Sopenharmony_ci drm_vmw_surface_flag_coherent)) { 152062306a36Sopenharmony_ci ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, 152162306a36Sopenharmony_ci res->guest_memory_size, 152262306a36Sopenharmony_ci &backup_handle, 152362306a36Sopenharmony_ci &res->guest_memory_bo); 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (unlikely(ret != 0)) { 152762306a36Sopenharmony_ci vmw_resource_unreference(&res); 152862306a36Sopenharmony_ci goto out_unlock; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (req->base.drm_surface_flags & drm_vmw_surface_flag_coherent) { 153262306a36Sopenharmony_ci struct vmw_bo *backup = res->guest_memory_bo; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci ttm_bo_reserve(&backup->tbo, false, false, NULL); 153562306a36Sopenharmony_ci if (!res->func->dirty_alloc) 153662306a36Sopenharmony_ci ret = -EINVAL; 153762306a36Sopenharmony_ci if (!ret) 153862306a36Sopenharmony_ci ret = vmw_bo_dirty_add(backup); 153962306a36Sopenharmony_ci if (!ret) { 154062306a36Sopenharmony_ci res->coherent = true; 154162306a36Sopenharmony_ci ret = res->func->dirty_alloc(res); 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci ttm_bo_unreserve(&backup->tbo); 154462306a36Sopenharmony_ci if (ret) { 154562306a36Sopenharmony_ci vmw_resource_unreference(&res); 154662306a36Sopenharmony_ci goto out_unlock; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci tmp = vmw_resource_reference(res); 155262306a36Sopenharmony_ci ret = ttm_prime_object_init(tfile, res->guest_memory_size, &user_srf->prime, 155362306a36Sopenharmony_ci req->base.drm_surface_flags & 155462306a36Sopenharmony_ci drm_vmw_surface_flag_shareable, 155562306a36Sopenharmony_ci VMW_RES_SURFACE, 155662306a36Sopenharmony_ci &vmw_user_surface_base_release); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (unlikely(ret != 0)) { 155962306a36Sopenharmony_ci vmw_resource_unreference(&tmp); 156062306a36Sopenharmony_ci vmw_resource_unreference(&res); 156162306a36Sopenharmony_ci goto out_unlock; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci rep->handle = user_srf->prime.base.handle; 156562306a36Sopenharmony_ci rep->backup_size = res->guest_memory_size; 156662306a36Sopenharmony_ci if (res->guest_memory_bo) { 156762306a36Sopenharmony_ci rep->buffer_map_handle = 156862306a36Sopenharmony_ci drm_vma_node_offset_addr(&res->guest_memory_bo->tbo.base.vma_node); 156962306a36Sopenharmony_ci rep->buffer_size = res->guest_memory_bo->tbo.base.size; 157062306a36Sopenharmony_ci rep->buffer_handle = backup_handle; 157162306a36Sopenharmony_ci } else { 157262306a36Sopenharmony_ci rep->buffer_map_handle = 0; 157362306a36Sopenharmony_ci rep->buffer_size = 0; 157462306a36Sopenharmony_ci rep->buffer_handle = SVGA3D_INVALID_ID; 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci vmw_resource_unreference(&res); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ciout_unlock: 157962306a36Sopenharmony_ci return ret; 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci/** 158362306a36Sopenharmony_ci * vmw_gb_surface_reference_internal - Ioctl function implementing 158462306a36Sopenharmony_ci * the user surface reference functionality. 158562306a36Sopenharmony_ci * 158662306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device. 158762306a36Sopenharmony_ci * @req: Pointer to user-space request surface arg. 158862306a36Sopenharmony_ci * @rep: Pointer to response to user-space. 158962306a36Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_cistatic int 159262306a36Sopenharmony_civmw_gb_surface_reference_internal(struct drm_device *dev, 159362306a36Sopenharmony_ci struct drm_vmw_surface_arg *req, 159462306a36Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep, 159562306a36Sopenharmony_ci struct drm_file *file_priv) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 159862306a36Sopenharmony_ci struct vmw_surface *srf; 159962306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 160062306a36Sopenharmony_ci struct vmw_surface_metadata *metadata; 160162306a36Sopenharmony_ci struct ttm_base_object *base; 160262306a36Sopenharmony_ci u32 backup_handle; 160362306a36Sopenharmony_ci int ret; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, 160662306a36Sopenharmony_ci req->handle_type, &base); 160762306a36Sopenharmony_ci if (unlikely(ret != 0)) 160862306a36Sopenharmony_ci return ret; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, prime.base); 161162306a36Sopenharmony_ci srf = &user_srf->srf; 161262306a36Sopenharmony_ci if (!srf->res.guest_memory_bo) { 161362306a36Sopenharmony_ci DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); 161462306a36Sopenharmony_ci goto out_bad_resource; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci metadata = &srf->metadata; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ 161962306a36Sopenharmony_ci ret = drm_gem_handle_create(file_priv, &srf->res.guest_memory_bo->tbo.base, 162062306a36Sopenharmony_ci &backup_handle); 162162306a36Sopenharmony_ci mutex_unlock(&dev_priv->cmdbuf_mutex); 162262306a36Sopenharmony_ci if (ret != 0) { 162362306a36Sopenharmony_ci drm_err(dev, "Wasn't able to create a backing handle for surface sid = %u.\n", 162462306a36Sopenharmony_ci req->sid); 162562306a36Sopenharmony_ci goto out_bad_resource; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(metadata->flags); 162962306a36Sopenharmony_ci rep->creq.base.format = metadata->format; 163062306a36Sopenharmony_ci rep->creq.base.mip_levels = metadata->mip_levels[0]; 163162306a36Sopenharmony_ci rep->creq.base.drm_surface_flags = 0; 163262306a36Sopenharmony_ci rep->creq.base.multisample_count = metadata->multisample_count; 163362306a36Sopenharmony_ci rep->creq.base.autogen_filter = metadata->autogen_filter; 163462306a36Sopenharmony_ci rep->creq.base.array_size = metadata->array_size; 163562306a36Sopenharmony_ci rep->creq.base.buffer_handle = backup_handle; 163662306a36Sopenharmony_ci rep->creq.base.base_size = metadata->base_size; 163762306a36Sopenharmony_ci rep->crep.handle = user_srf->prime.base.handle; 163862306a36Sopenharmony_ci rep->crep.backup_size = srf->res.guest_memory_size; 163962306a36Sopenharmony_ci rep->crep.buffer_handle = backup_handle; 164062306a36Sopenharmony_ci rep->crep.buffer_map_handle = 164162306a36Sopenharmony_ci drm_vma_node_offset_addr(&srf->res.guest_memory_bo->tbo.base.vma_node); 164262306a36Sopenharmony_ci rep->crep.buffer_size = srf->res.guest_memory_bo->tbo.base.size; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci rep->creq.version = drm_vmw_gb_surface_v1; 164562306a36Sopenharmony_ci rep->creq.svga3d_flags_upper_32_bits = 164662306a36Sopenharmony_ci SVGA3D_FLAGS_UPPER_32(metadata->flags); 164762306a36Sopenharmony_ci rep->creq.multisample_pattern = metadata->multisample_pattern; 164862306a36Sopenharmony_ci rep->creq.quality_level = metadata->quality_level; 164962306a36Sopenharmony_ci rep->creq.must_be_zero = 0; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ciout_bad_resource: 165262306a36Sopenharmony_ci ttm_base_object_unref(&base); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci return ret; 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci/** 165862306a36Sopenharmony_ci * vmw_subres_dirty_add - Add a dirty region to a subresource 165962306a36Sopenharmony_ci * @dirty: The surfaces's dirty tracker. 166062306a36Sopenharmony_ci * @loc_start: The location corresponding to the start of the region. 166162306a36Sopenharmony_ci * @loc_end: The location corresponding to the end of the region. 166262306a36Sopenharmony_ci * 166362306a36Sopenharmony_ci * As we are assuming that @loc_start and @loc_end represent a sequential 166462306a36Sopenharmony_ci * range of backing store memory, if the region spans multiple lines then 166562306a36Sopenharmony_ci * regardless of the x coordinate, the full lines are dirtied. 166662306a36Sopenharmony_ci * Correspondingly if the region spans multiple z slices, then full rather 166762306a36Sopenharmony_ci * than partial z slices are dirtied. 166862306a36Sopenharmony_ci */ 166962306a36Sopenharmony_cistatic void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty, 167062306a36Sopenharmony_ci const struct vmw_surface_loc *loc_start, 167162306a36Sopenharmony_ci const struct vmw_surface_loc *loc_end) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci const struct vmw_surface_cache *cache = &dirty->cache; 167462306a36Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[loc_start->sub_resource]; 167562306a36Sopenharmony_ci u32 mip = loc_start->sub_resource % cache->num_mip_levels; 167662306a36Sopenharmony_ci const struct drm_vmw_size *size = &cache->mip[mip].size; 167762306a36Sopenharmony_ci u32 box_c2 = box->z + box->d; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci if (WARN_ON(loc_start->sub_resource >= dirty->num_subres)) 168062306a36Sopenharmony_ci return; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (box->d == 0 || box->z > loc_start->z) 168362306a36Sopenharmony_ci box->z = loc_start->z; 168462306a36Sopenharmony_ci if (box_c2 < loc_end->z) 168562306a36Sopenharmony_ci box->d = loc_end->z - box->z; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (loc_start->z + 1 == loc_end->z) { 168862306a36Sopenharmony_ci box_c2 = box->y + box->h; 168962306a36Sopenharmony_ci if (box->h == 0 || box->y > loc_start->y) 169062306a36Sopenharmony_ci box->y = loc_start->y; 169162306a36Sopenharmony_ci if (box_c2 < loc_end->y) 169262306a36Sopenharmony_ci box->h = loc_end->y - box->y; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci if (loc_start->y + 1 == loc_end->y) { 169562306a36Sopenharmony_ci box_c2 = box->x + box->w; 169662306a36Sopenharmony_ci if (box->w == 0 || box->x > loc_start->x) 169762306a36Sopenharmony_ci box->x = loc_start->x; 169862306a36Sopenharmony_ci if (box_c2 < loc_end->x) 169962306a36Sopenharmony_ci box->w = loc_end->x - box->x; 170062306a36Sopenharmony_ci } else { 170162306a36Sopenharmony_ci box->x = 0; 170262306a36Sopenharmony_ci box->w = size->width; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci } else { 170562306a36Sopenharmony_ci box->y = 0; 170662306a36Sopenharmony_ci box->h = size->height; 170762306a36Sopenharmony_ci box->x = 0; 170862306a36Sopenharmony_ci box->w = size->width; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci/** 171362306a36Sopenharmony_ci * vmw_subres_dirty_full - Mark a full subresource as dirty 171462306a36Sopenharmony_ci * @dirty: The surface's dirty tracker. 171562306a36Sopenharmony_ci * @subres: The subresource 171662306a36Sopenharmony_ci */ 171762306a36Sopenharmony_cistatic void vmw_subres_dirty_full(struct vmw_surface_dirty *dirty, u32 subres) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci const struct vmw_surface_cache *cache = &dirty->cache; 172062306a36Sopenharmony_ci u32 mip = subres % cache->num_mip_levels; 172162306a36Sopenharmony_ci const struct drm_vmw_size *size = &cache->mip[mip].size; 172262306a36Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[subres]; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci box->x = 0; 172562306a36Sopenharmony_ci box->y = 0; 172662306a36Sopenharmony_ci box->z = 0; 172762306a36Sopenharmony_ci box->w = size->width; 172862306a36Sopenharmony_ci box->h = size->height; 172962306a36Sopenharmony_ci box->d = size->depth; 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci/* 173362306a36Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for texture 173462306a36Sopenharmony_ci * surfaces. 173562306a36Sopenharmony_ci */ 173662306a36Sopenharmony_cistatic void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, 173762306a36Sopenharmony_ci size_t start, size_t end) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct vmw_surface_dirty *dirty = 174062306a36Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 174162306a36Sopenharmony_ci size_t backup_end = res->guest_memory_offset + res->guest_memory_size; 174262306a36Sopenharmony_ci struct vmw_surface_loc loc1, loc2; 174362306a36Sopenharmony_ci const struct vmw_surface_cache *cache; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci start = max_t(size_t, start, res->guest_memory_offset) - res->guest_memory_offset; 174662306a36Sopenharmony_ci end = min(end, backup_end) - res->guest_memory_offset; 174762306a36Sopenharmony_ci cache = &dirty->cache; 174862306a36Sopenharmony_ci vmw_surface_get_loc(cache, &loc1, start); 174962306a36Sopenharmony_ci vmw_surface_get_loc(cache, &loc2, end - 1); 175062306a36Sopenharmony_ci vmw_surface_inc_loc(cache, &loc2); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (loc1.sheet != loc2.sheet) { 175362306a36Sopenharmony_ci u32 sub_res; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci /* 175662306a36Sopenharmony_ci * Multiple multisample sheets. To do this in an optimized 175762306a36Sopenharmony_ci * fashion, compute the dirty region for each sheet and the 175862306a36Sopenharmony_ci * resulting union. Since this is not a common case, just dirty 175962306a36Sopenharmony_ci * the whole surface. 176062306a36Sopenharmony_ci */ 176162306a36Sopenharmony_ci for (sub_res = 0; sub_res < dirty->num_subres; ++sub_res) 176262306a36Sopenharmony_ci vmw_subres_dirty_full(dirty, sub_res); 176362306a36Sopenharmony_ci return; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci if (loc1.sub_resource + 1 == loc2.sub_resource) { 176662306a36Sopenharmony_ci /* Dirty range covers a single sub-resource */ 176762306a36Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc1, &loc2); 176862306a36Sopenharmony_ci } else { 176962306a36Sopenharmony_ci /* Dirty range covers multiple sub-resources */ 177062306a36Sopenharmony_ci struct vmw_surface_loc loc_min, loc_max; 177162306a36Sopenharmony_ci u32 sub_res; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci vmw_surface_max_loc(cache, loc1.sub_resource, &loc_max); 177462306a36Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc1, &loc_max); 177562306a36Sopenharmony_ci vmw_surface_min_loc(cache, loc2.sub_resource - 1, &loc_min); 177662306a36Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc_min, &loc2); 177762306a36Sopenharmony_ci for (sub_res = loc1.sub_resource + 1; 177862306a36Sopenharmony_ci sub_res < loc2.sub_resource - 1; ++sub_res) 177962306a36Sopenharmony_ci vmw_subres_dirty_full(dirty, sub_res); 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci/* 178462306a36Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for buffer 178562306a36Sopenharmony_ci * surfaces. 178662306a36Sopenharmony_ci */ 178762306a36Sopenharmony_cistatic void vmw_surface_buf_dirty_range_add(struct vmw_resource *res, 178862306a36Sopenharmony_ci size_t start, size_t end) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci struct vmw_surface_dirty *dirty = 179162306a36Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 179262306a36Sopenharmony_ci const struct vmw_surface_cache *cache = &dirty->cache; 179362306a36Sopenharmony_ci size_t backup_end = res->guest_memory_offset + cache->mip_chain_bytes; 179462306a36Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[0]; 179562306a36Sopenharmony_ci u32 box_c2; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci box->h = box->d = 1; 179862306a36Sopenharmony_ci start = max_t(size_t, start, res->guest_memory_offset) - res->guest_memory_offset; 179962306a36Sopenharmony_ci end = min(end, backup_end) - res->guest_memory_offset; 180062306a36Sopenharmony_ci box_c2 = box->x + box->w; 180162306a36Sopenharmony_ci if (box->w == 0 || box->x > start) 180262306a36Sopenharmony_ci box->x = start; 180362306a36Sopenharmony_ci if (box_c2 < end) 180462306a36Sopenharmony_ci box->w = end - box->x; 180562306a36Sopenharmony_ci} 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci/* 180862306a36Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for surfaces 180962306a36Sopenharmony_ci */ 181062306a36Sopenharmony_cistatic void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 181162306a36Sopenharmony_ci size_t end) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (WARN_ON(end <= res->guest_memory_offset || 181662306a36Sopenharmony_ci start >= res->guest_memory_offset + res->guest_memory_size)) 181762306a36Sopenharmony_ci return; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci if (srf->metadata.format == SVGA3D_BUFFER) 182062306a36Sopenharmony_ci vmw_surface_buf_dirty_range_add(res, start, end); 182162306a36Sopenharmony_ci else 182262306a36Sopenharmony_ci vmw_surface_tex_dirty_range_add(res, start, end); 182362306a36Sopenharmony_ci} 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci/* 182662306a36Sopenharmony_ci * vmw_surface_dirty_sync - The surface's dirty_sync callback. 182762306a36Sopenharmony_ci */ 182862306a36Sopenharmony_cistatic int vmw_surface_dirty_sync(struct vmw_resource *res) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 183162306a36Sopenharmony_ci u32 i, num_dirty; 183262306a36Sopenharmony_ci struct vmw_surface_dirty *dirty = 183362306a36Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 183462306a36Sopenharmony_ci size_t alloc_size; 183562306a36Sopenharmony_ci const struct vmw_surface_cache *cache = &dirty->cache; 183662306a36Sopenharmony_ci struct { 183762306a36Sopenharmony_ci SVGA3dCmdHeader header; 183862306a36Sopenharmony_ci SVGA3dCmdDXUpdateSubResource body; 183962306a36Sopenharmony_ci } *cmd1; 184062306a36Sopenharmony_ci struct { 184162306a36Sopenharmony_ci SVGA3dCmdHeader header; 184262306a36Sopenharmony_ci SVGA3dCmdUpdateGBImage body; 184362306a36Sopenharmony_ci } *cmd2; 184462306a36Sopenharmony_ci void *cmd; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci num_dirty = 0; 184762306a36Sopenharmony_ci for (i = 0; i < dirty->num_subres; ++i) { 184862306a36Sopenharmony_ci const SVGA3dBox *box = &dirty->boxes[i]; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci if (box->d) 185162306a36Sopenharmony_ci num_dirty++; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (!num_dirty) 185562306a36Sopenharmony_ci goto out; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci alloc_size = num_dirty * ((has_sm4_context(dev_priv)) ? sizeof(*cmd1) : sizeof(*cmd2)); 185862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, alloc_size); 185962306a36Sopenharmony_ci if (!cmd) 186062306a36Sopenharmony_ci return -ENOMEM; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci cmd1 = cmd; 186362306a36Sopenharmony_ci cmd2 = cmd; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci for (i = 0; i < dirty->num_subres; ++i) { 186662306a36Sopenharmony_ci const SVGA3dBox *box = &dirty->boxes[i]; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if (!box->d) 186962306a36Sopenharmony_ci continue; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* 187262306a36Sopenharmony_ci * DX_UPDATE_SUBRESOURCE is aware of array surfaces. 187362306a36Sopenharmony_ci * UPDATE_GB_IMAGE is not. 187462306a36Sopenharmony_ci */ 187562306a36Sopenharmony_ci if (has_sm4_context(dev_priv)) { 187662306a36Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE; 187762306a36Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 187862306a36Sopenharmony_ci cmd1->body.sid = res->id; 187962306a36Sopenharmony_ci cmd1->body.subResource = i; 188062306a36Sopenharmony_ci cmd1->body.box = *box; 188162306a36Sopenharmony_ci cmd1++; 188262306a36Sopenharmony_ci } else { 188362306a36Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 188462306a36Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 188562306a36Sopenharmony_ci cmd2->body.image.sid = res->id; 188662306a36Sopenharmony_ci cmd2->body.image.face = i / cache->num_mip_levels; 188762306a36Sopenharmony_ci cmd2->body.image.mipmap = i - 188862306a36Sopenharmony_ci (cache->num_mip_levels * cmd2->body.image.face); 188962306a36Sopenharmony_ci cmd2->body.box = *box; 189062306a36Sopenharmony_ci cmd2++; 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, alloc_size); 189562306a36Sopenharmony_ci out: 189662306a36Sopenharmony_ci memset(&dirty->boxes[0], 0, sizeof(dirty->boxes[0]) * 189762306a36Sopenharmony_ci dirty->num_subres); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci return 0; 190062306a36Sopenharmony_ci} 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci/* 190362306a36Sopenharmony_ci * vmw_surface_dirty_alloc - The surface's dirty_alloc callback. 190462306a36Sopenharmony_ci */ 190562306a36Sopenharmony_cistatic int vmw_surface_dirty_alloc(struct vmw_resource *res) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 190862306a36Sopenharmony_ci const struct vmw_surface_metadata *metadata = &srf->metadata; 190962306a36Sopenharmony_ci struct vmw_surface_dirty *dirty; 191062306a36Sopenharmony_ci u32 num_layers = 1; 191162306a36Sopenharmony_ci u32 num_mip; 191262306a36Sopenharmony_ci u32 num_subres; 191362306a36Sopenharmony_ci u32 num_samples; 191462306a36Sopenharmony_ci size_t dirty_size; 191562306a36Sopenharmony_ci int ret; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (metadata->array_size) 191862306a36Sopenharmony_ci num_layers = metadata->array_size; 191962306a36Sopenharmony_ci else if (metadata->flags & SVGA3D_SURFACE_CUBEMAP) 192062306a36Sopenharmony_ci num_layers *= SVGA3D_MAX_SURFACE_FACES; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci num_mip = metadata->mip_levels[0]; 192362306a36Sopenharmony_ci if (!num_mip) 192462306a36Sopenharmony_ci num_mip = 1; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci num_subres = num_layers * num_mip; 192762306a36Sopenharmony_ci dirty_size = struct_size(dirty, boxes, num_subres); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci dirty = kvzalloc(dirty_size, GFP_KERNEL); 193062306a36Sopenharmony_ci if (!dirty) { 193162306a36Sopenharmony_ci ret = -ENOMEM; 193262306a36Sopenharmony_ci goto out_no_dirty; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci num_samples = max_t(u32, 1, metadata->multisample_count); 193662306a36Sopenharmony_ci ret = vmw_surface_setup_cache(&metadata->base_size, metadata->format, 193762306a36Sopenharmony_ci num_mip, num_layers, num_samples, 193862306a36Sopenharmony_ci &dirty->cache); 193962306a36Sopenharmony_ci if (ret) 194062306a36Sopenharmony_ci goto out_no_cache; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci dirty->num_subres = num_subres; 194362306a36Sopenharmony_ci res->dirty = (struct vmw_resource_dirty *) dirty; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci return 0; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ciout_no_cache: 194862306a36Sopenharmony_ci kvfree(dirty); 194962306a36Sopenharmony_ciout_no_dirty: 195062306a36Sopenharmony_ci return ret; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci/* 195462306a36Sopenharmony_ci * vmw_surface_dirty_free - The surface's dirty_free callback 195562306a36Sopenharmony_ci */ 195662306a36Sopenharmony_cistatic void vmw_surface_dirty_free(struct vmw_resource *res) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci struct vmw_surface_dirty *dirty = 195962306a36Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci kvfree(dirty); 196262306a36Sopenharmony_ci res->dirty = NULL; 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci/* 196662306a36Sopenharmony_ci * vmw_surface_clean - The surface's clean callback 196762306a36Sopenharmony_ci */ 196862306a36Sopenharmony_cistatic int vmw_surface_clean(struct vmw_resource *res) 196962306a36Sopenharmony_ci{ 197062306a36Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 197162306a36Sopenharmony_ci size_t alloc_size; 197262306a36Sopenharmony_ci struct { 197362306a36Sopenharmony_ci SVGA3dCmdHeader header; 197462306a36Sopenharmony_ci SVGA3dCmdReadbackGBSurface body; 197562306a36Sopenharmony_ci } *cmd; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci alloc_size = sizeof(*cmd); 197862306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, alloc_size); 197962306a36Sopenharmony_ci if (!cmd) 198062306a36Sopenharmony_ci return -ENOMEM; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; 198362306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 198462306a36Sopenharmony_ci cmd->body.sid = res->id; 198562306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, alloc_size); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci return 0; 198862306a36Sopenharmony_ci} 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci/* 199162306a36Sopenharmony_ci * vmw_gb_surface_define - Define a private GB surface 199262306a36Sopenharmony_ci * 199362306a36Sopenharmony_ci * @dev_priv: Pointer to a device private. 199462306a36Sopenharmony_ci * @metadata: Metadata representing the surface to create. 199562306a36Sopenharmony_ci * @user_srf_out: allocated user_srf. Set to NULL on failure. 199662306a36Sopenharmony_ci * 199762306a36Sopenharmony_ci * GB surfaces allocated by this function will not have a user mode handle, and 199862306a36Sopenharmony_ci * thus will only be visible to vmwgfx. For optimization reasons the 199962306a36Sopenharmony_ci * surface may later be given a user mode handle by another function to make 200062306a36Sopenharmony_ci * it available to user mode drivers. 200162306a36Sopenharmony_ci */ 200262306a36Sopenharmony_ciint vmw_gb_surface_define(struct vmw_private *dev_priv, 200362306a36Sopenharmony_ci const struct vmw_surface_metadata *req, 200462306a36Sopenharmony_ci struct vmw_surface **srf_out) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci struct vmw_surface_metadata *metadata; 200762306a36Sopenharmony_ci struct vmw_user_surface *user_srf; 200862306a36Sopenharmony_ci struct vmw_surface *srf; 200962306a36Sopenharmony_ci u32 sample_count = 1; 201062306a36Sopenharmony_ci u32 num_layers = 1; 201162306a36Sopenharmony_ci int ret; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci *srf_out = NULL; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci if (req->scanout) { 201662306a36Sopenharmony_ci if (!vmw_surface_is_screen_target_format(req->format)) { 201762306a36Sopenharmony_ci VMW_DEBUG_USER("Invalid Screen Target surface format."); 201862306a36Sopenharmony_ci return -EINVAL; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci if (req->base_size.width > dev_priv->texture_max_width || 202262306a36Sopenharmony_ci req->base_size.height > dev_priv->texture_max_height) { 202362306a36Sopenharmony_ci VMW_DEBUG_USER("%ux%u\n, exceed max surface size %ux%u", 202462306a36Sopenharmony_ci req->base_size.width, 202562306a36Sopenharmony_ci req->base_size.height, 202662306a36Sopenharmony_ci dev_priv->texture_max_width, 202762306a36Sopenharmony_ci dev_priv->texture_max_height); 202862306a36Sopenharmony_ci return -EINVAL; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci } else { 203162306a36Sopenharmony_ci const SVGA3dSurfaceDesc *desc = 203262306a36Sopenharmony_ci vmw_surface_get_desc(req->format); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (desc->blockDesc == SVGA3DBLOCKDESC_NONE) { 203562306a36Sopenharmony_ci VMW_DEBUG_USER("Invalid surface format.\n"); 203662306a36Sopenharmony_ci return -EINVAL; 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (req->autogen_filter != SVGA3D_TEX_FILTER_NONE) 204162306a36Sopenharmony_ci return -EINVAL; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (req->num_sizes != 1) 204462306a36Sopenharmony_ci return -EINVAL; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci if (req->sizes != NULL) 204762306a36Sopenharmony_ci return -EINVAL; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); 205062306a36Sopenharmony_ci if (unlikely(!user_srf)) { 205162306a36Sopenharmony_ci ret = -ENOMEM; 205262306a36Sopenharmony_ci goto out_unlock; 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci *srf_out = &user_srf->srf; 205662306a36Sopenharmony_ci user_srf->prime.base.shareable = false; 205762306a36Sopenharmony_ci user_srf->prime.base.tfile = NULL; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci srf = &user_srf->srf; 206062306a36Sopenharmony_ci srf->metadata = *req; 206162306a36Sopenharmony_ci srf->offsets = NULL; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci metadata = &srf->metadata; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci if (metadata->array_size) 206662306a36Sopenharmony_ci num_layers = req->array_size; 206762306a36Sopenharmony_ci else if (metadata->flags & SVGA3D_SURFACE_CUBEMAP) 206862306a36Sopenharmony_ci num_layers = SVGA3D_MAX_SURFACE_FACES; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci if (metadata->flags & SVGA3D_SURFACE_MULTISAMPLE) 207162306a36Sopenharmony_ci sample_count = metadata->multisample_count; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci srf->res.guest_memory_size = 207462306a36Sopenharmony_ci vmw_surface_get_serialized_size_extended( 207562306a36Sopenharmony_ci metadata->format, 207662306a36Sopenharmony_ci metadata->base_size, 207762306a36Sopenharmony_ci metadata->mip_levels[0], 207862306a36Sopenharmony_ci num_layers, 207962306a36Sopenharmony_ci sample_count); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci if (metadata->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) 208262306a36Sopenharmony_ci srf->res.guest_memory_size += sizeof(SVGA3dDXSOState); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* 208562306a36Sopenharmony_ci * Don't set SVGA3D_SURFACE_SCREENTARGET flag for a scanout surface with 208662306a36Sopenharmony_ci * size greater than STDU max width/height. This is really a workaround 208762306a36Sopenharmony_ci * to support creation of big framebuffer requested by some user-space 208862306a36Sopenharmony_ci * for whole topology. That big framebuffer won't really be used for 208962306a36Sopenharmony_ci * binding with screen target as during prepare_fb a separate surface is 209062306a36Sopenharmony_ci * created so it's safe to ignore SVGA3D_SURFACE_SCREENTARGET flag. 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci if (dev_priv->active_display_unit == vmw_du_screen_target && 209362306a36Sopenharmony_ci metadata->scanout && 209462306a36Sopenharmony_ci metadata->base_size.width <= dev_priv->stdu_max_width && 209562306a36Sopenharmony_ci metadata->base_size.height <= dev_priv->stdu_max_height) 209662306a36Sopenharmony_ci metadata->flags |= SVGA3D_SURFACE_SCREENTARGET; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci /* 209962306a36Sopenharmony_ci * From this point, the generic resource management functions 210062306a36Sopenharmony_ci * destroy the object on failure. 210162306a36Sopenharmony_ci */ 210262306a36Sopenharmony_ci ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci return ret; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ciout_unlock: 210762306a36Sopenharmony_ci return ret; 210862306a36Sopenharmony_ci} 2109