18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 128c2ecf20Sopenharmony_ci * the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 168c2ecf20Sopenharmony_ci * of the Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci **************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_placement.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h" 318c2ecf20Sopenharmony_ci#include "vmwgfx_resource_priv.h" 328c2ecf20Sopenharmony_ci#include "vmwgfx_so.h" 338c2ecf20Sopenharmony_ci#include "vmwgfx_binding.h" 348c2ecf20Sopenharmony_ci#include "device_include/svga3d_surfacedefs.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) 378c2ecf20Sopenharmony_ci#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) 388c2ecf20Sopenharmony_ci#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ 398c2ecf20Sopenharmony_ci (svga3d_flags & ((uint64_t)U32_MAX)) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * struct vmw_user_surface - User-space visible surface resource 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * @base: The TTM base object handling user-space visibility. 458c2ecf20Sopenharmony_ci * @srf: The surface metadata. 468c2ecf20Sopenharmony_ci * @size: TTM accounting size for the surface. 478c2ecf20Sopenharmony_ci * @master: master of the creating client. Used for security check. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_cistruct vmw_user_surface { 508c2ecf20Sopenharmony_ci struct ttm_prime_object prime; 518c2ecf20Sopenharmony_ci struct vmw_surface srf; 528c2ecf20Sopenharmony_ci uint32_t size; 538c2ecf20Sopenharmony_ci struct drm_master *master; 548c2ecf20Sopenharmony_ci struct ttm_base_object *backup_base; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * struct vmw_surface_offset - Backing store mip level offset info 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * @face: Surface face. 618c2ecf20Sopenharmony_ci * @mip: Mip level. 628c2ecf20Sopenharmony_ci * @bo_offset: Offset into backing store of this mip level. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistruct vmw_surface_offset { 668c2ecf20Sopenharmony_ci uint32_t face; 678c2ecf20Sopenharmony_ci uint32_t mip; 688c2ecf20Sopenharmony_ci uint32_t bo_offset; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/** 728c2ecf20Sopenharmony_ci * vmw_surface_dirty - Surface dirty-tracker 738c2ecf20Sopenharmony_ci * @cache: Cached layout information of the surface. 748c2ecf20Sopenharmony_ci * @size: Accounting size for the struct vmw_surface_dirty. 758c2ecf20Sopenharmony_ci * @num_subres: Number of subresources. 768c2ecf20Sopenharmony_ci * @boxes: Array of SVGA3dBoxes indicating dirty regions. One per subresource. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistruct vmw_surface_dirty { 798c2ecf20Sopenharmony_ci struct svga3dsurface_cache cache; 808c2ecf20Sopenharmony_ci size_t size; 818c2ecf20Sopenharmony_ci u32 num_subres; 828c2ecf20Sopenharmony_ci SVGA3dBox boxes[]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void vmw_user_surface_free(struct vmw_resource *res); 868c2ecf20Sopenharmony_cistatic struct vmw_resource * 878c2ecf20Sopenharmony_civmw_user_surface_base_to_res(struct ttm_base_object *base); 888c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_bind(struct vmw_resource *res, 898c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf); 908c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_unbind(struct vmw_resource *res, 918c2ecf20Sopenharmony_ci bool readback, 928c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf); 938c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_create(struct vmw_resource *res); 948c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_destroy(struct vmw_resource *res); 958c2ecf20Sopenharmony_cistatic int vmw_gb_surface_create(struct vmw_resource *res); 968c2ecf20Sopenharmony_cistatic int vmw_gb_surface_bind(struct vmw_resource *res, 978c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf); 988c2ecf20Sopenharmony_cistatic int vmw_gb_surface_unbind(struct vmw_resource *res, 998c2ecf20Sopenharmony_ci bool readback, 1008c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf); 1018c2ecf20Sopenharmony_cistatic int vmw_gb_surface_destroy(struct vmw_resource *res); 1028c2ecf20Sopenharmony_cistatic int 1038c2ecf20Sopenharmony_civmw_gb_surface_define_internal(struct drm_device *dev, 1048c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req, 1058c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep, 1068c2ecf20Sopenharmony_ci struct drm_file *file_priv); 1078c2ecf20Sopenharmony_cistatic int 1088c2ecf20Sopenharmony_civmw_gb_surface_reference_internal(struct drm_device *dev, 1098c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *req, 1108c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep, 1118c2ecf20Sopenharmony_ci struct drm_file *file_priv); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void vmw_surface_dirty_free(struct vmw_resource *res); 1148c2ecf20Sopenharmony_cistatic int vmw_surface_dirty_alloc(struct vmw_resource *res); 1158c2ecf20Sopenharmony_cistatic int vmw_surface_dirty_sync(struct vmw_resource *res); 1168c2ecf20Sopenharmony_cistatic void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 1178c2ecf20Sopenharmony_ci size_t end); 1188c2ecf20Sopenharmony_cistatic int vmw_surface_clean(struct vmw_resource *res); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const struct vmw_user_resource_conv user_surface_conv = { 1218c2ecf20Sopenharmony_ci .object_type = VMW_RES_SURFACE, 1228c2ecf20Sopenharmony_ci .base_obj_to_res = vmw_user_surface_base_to_res, 1238c2ecf20Sopenharmony_ci .res_free = vmw_user_surface_free 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciconst struct vmw_user_resource_conv *user_surface_converter = 1278c2ecf20Sopenharmony_ci &user_surface_conv; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic uint64_t vmw_user_surface_size; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_legacy_surface_func = { 1338c2ecf20Sopenharmony_ci .res_type = vmw_res_surface, 1348c2ecf20Sopenharmony_ci .needs_backup = false, 1358c2ecf20Sopenharmony_ci .may_evict = true, 1368c2ecf20Sopenharmony_ci .prio = 1, 1378c2ecf20Sopenharmony_ci .dirty_prio = 1, 1388c2ecf20Sopenharmony_ci .type_name = "legacy surfaces", 1398c2ecf20Sopenharmony_ci .backup_placement = &vmw_srf_placement, 1408c2ecf20Sopenharmony_ci .create = &vmw_legacy_srf_create, 1418c2ecf20Sopenharmony_ci .destroy = &vmw_legacy_srf_destroy, 1428c2ecf20Sopenharmony_ci .bind = &vmw_legacy_srf_bind, 1438c2ecf20Sopenharmony_ci .unbind = &vmw_legacy_srf_unbind 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const struct vmw_res_func vmw_gb_surface_func = { 1478c2ecf20Sopenharmony_ci .res_type = vmw_res_surface, 1488c2ecf20Sopenharmony_ci .needs_backup = true, 1498c2ecf20Sopenharmony_ci .may_evict = true, 1508c2ecf20Sopenharmony_ci .prio = 1, 1518c2ecf20Sopenharmony_ci .dirty_prio = 2, 1528c2ecf20Sopenharmony_ci .type_name = "guest backed surfaces", 1538c2ecf20Sopenharmony_ci .backup_placement = &vmw_mob_placement, 1548c2ecf20Sopenharmony_ci .create = vmw_gb_surface_create, 1558c2ecf20Sopenharmony_ci .destroy = vmw_gb_surface_destroy, 1568c2ecf20Sopenharmony_ci .bind = vmw_gb_surface_bind, 1578c2ecf20Sopenharmony_ci .unbind = vmw_gb_surface_unbind, 1588c2ecf20Sopenharmony_ci .dirty_alloc = vmw_surface_dirty_alloc, 1598c2ecf20Sopenharmony_ci .dirty_free = vmw_surface_dirty_free, 1608c2ecf20Sopenharmony_ci .dirty_sync = vmw_surface_dirty_sync, 1618c2ecf20Sopenharmony_ci .dirty_range_add = vmw_surface_dirty_range_add, 1628c2ecf20Sopenharmony_ci .clean = vmw_surface_clean, 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * struct vmw_surface_dma - SVGA3D DMA command 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistruct vmw_surface_dma { 1698c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 1708c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMA body; 1718c2ecf20Sopenharmony_ci SVGA3dCopyBox cb; 1728c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix suffix; 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * struct vmw_surface_define - SVGA3D Surface Define command 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cistruct vmw_surface_define { 1798c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 1808c2ecf20Sopenharmony_ci SVGA3dCmdDefineSurface body; 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * struct vmw_surface_destroy - SVGA3D Surface Destroy command 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistruct vmw_surface_destroy { 1878c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 1888c2ecf20Sopenharmony_ci SVGA3dCmdDestroySurface body; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * vmw_surface_dma_size - Compute fifo size for a dma command. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * @srf: Pointer to a struct vmw_surface 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Computes the required size for a surface dma command for backup or 1988c2ecf20Sopenharmony_ci * restoration of the surface represented by @srf. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return srf->metadata.num_sizes * sizeof(struct vmw_surface_dma); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * vmw_surface_define_size - Compute fifo size for a surface define command. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * @srf: Pointer to a struct vmw_surface 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * Computes the required size for a surface define command for the definition 2128c2ecf20Sopenharmony_ci * of the surface represented by @srf. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return sizeof(struct vmw_surface_define) + srf->metadata.num_sizes * 2178c2ecf20Sopenharmony_ci sizeof(SVGA3dSize); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * vmw_surface_destroy_size - Compute fifo size for a surface destroy command. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * Computes the required size for a surface destroy command for the destruction 2258c2ecf20Sopenharmony_ci * of a hw surface. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic inline uint32_t vmw_surface_destroy_size(void) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci return sizeof(struct vmw_surface_destroy); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * vmw_surface_destroy_encode - Encode a surface_destroy command. 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci * @id: The surface id 2368c2ecf20Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_cistatic void vmw_surface_destroy_encode(uint32_t id, 2398c2ecf20Sopenharmony_ci void *cmd_space) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *) 2428c2ecf20Sopenharmony_ci cmd_space; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY; 2458c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 2468c2ecf20Sopenharmony_ci cmd->body.sid = id; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/** 2508c2ecf20Sopenharmony_ci * vmw_surface_define_encode - Encode a surface_define command. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * @srf: Pointer to a struct vmw_surface object. 2538c2ecf20Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_cistatic void vmw_surface_define_encode(const struct vmw_surface *srf, 2568c2ecf20Sopenharmony_ci void *cmd_space) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct vmw_surface_define *cmd = (struct vmw_surface_define *) 2598c2ecf20Sopenharmony_ci cmd_space; 2608c2ecf20Sopenharmony_ci struct drm_vmw_size *src_size; 2618c2ecf20Sopenharmony_ci SVGA3dSize *cmd_size; 2628c2ecf20Sopenharmony_ci uint32_t cmd_len; 2638c2ecf20Sopenharmony_ci int i; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci cmd_len = sizeof(cmd->body) + srf->metadata.num_sizes * 2668c2ecf20Sopenharmony_ci sizeof(SVGA3dSize); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE; 2698c2ecf20Sopenharmony_ci cmd->header.size = cmd_len; 2708c2ecf20Sopenharmony_ci cmd->body.sid = srf->res.id; 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * Downcast of surfaceFlags, was upcasted when received from user-space, 2738c2ecf20Sopenharmony_ci * since driver internally stores as 64 bit. 2748c2ecf20Sopenharmony_ci * For legacy surface define only 32 bit flag is supported. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci cmd->body.surfaceFlags = (SVGA3dSurface1Flags)srf->metadata.flags; 2778c2ecf20Sopenharmony_ci cmd->body.format = srf->metadata.format; 2788c2ecf20Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) 2798c2ecf20Sopenharmony_ci cmd->body.face[i].numMipLevels = srf->metadata.mip_levels[i]; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci cmd += 1; 2828c2ecf20Sopenharmony_ci cmd_size = (SVGA3dSize *) cmd; 2838c2ecf20Sopenharmony_ci src_size = srf->metadata.sizes; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci for (i = 0; i < srf->metadata.num_sizes; ++i, cmd_size++, src_size++) { 2868c2ecf20Sopenharmony_ci cmd_size->width = src_size->width; 2878c2ecf20Sopenharmony_ci cmd_size->height = src_size->height; 2888c2ecf20Sopenharmony_ci cmd_size->depth = src_size->depth; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * vmw_surface_dma_encode - Encode a surface_dma command. 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * @srf: Pointer to a struct vmw_surface object. 2968c2ecf20Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 2978c2ecf20Sopenharmony_ci * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents 2988c2ecf20Sopenharmony_ci * should be placed or read from. 2998c2ecf20Sopenharmony_ci * @to_surface: Boolean whether to DMA to the surface or from the surface. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_cistatic void vmw_surface_dma_encode(struct vmw_surface *srf, 3028c2ecf20Sopenharmony_ci void *cmd_space, 3038c2ecf20Sopenharmony_ci const SVGAGuestPtr *ptr, 3048c2ecf20Sopenharmony_ci bool to_surface) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci uint32_t i; 3078c2ecf20Sopenharmony_ci struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space; 3088c2ecf20Sopenharmony_ci const struct svga3d_surface_desc *desc = 3098c2ecf20Sopenharmony_ci svga3dsurface_get_desc(srf->metadata.format); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci for (i = 0; i < srf->metadata.num_sizes; ++i) { 3128c2ecf20Sopenharmony_ci SVGA3dCmdHeader *header = &cmd->header; 3138c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMA *body = &cmd->body; 3148c2ecf20Sopenharmony_ci SVGA3dCopyBox *cb = &cmd->cb; 3158c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix; 3168c2ecf20Sopenharmony_ci const struct vmw_surface_offset *cur_offset = &srf->offsets[i]; 3178c2ecf20Sopenharmony_ci const struct drm_vmw_size *cur_size = &srf->metadata.sizes[i]; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci header->id = SVGA_3D_CMD_SURFACE_DMA; 3208c2ecf20Sopenharmony_ci header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci body->guest.ptr = *ptr; 3238c2ecf20Sopenharmony_ci body->guest.ptr.offset += cur_offset->bo_offset; 3248c2ecf20Sopenharmony_ci body->guest.pitch = svga3dsurface_calculate_pitch(desc, 3258c2ecf20Sopenharmony_ci cur_size); 3268c2ecf20Sopenharmony_ci body->host.sid = srf->res.id; 3278c2ecf20Sopenharmony_ci body->host.face = cur_offset->face; 3288c2ecf20Sopenharmony_ci body->host.mipmap = cur_offset->mip; 3298c2ecf20Sopenharmony_ci body->transfer = ((to_surface) ? SVGA3D_WRITE_HOST_VRAM : 3308c2ecf20Sopenharmony_ci SVGA3D_READ_HOST_VRAM); 3318c2ecf20Sopenharmony_ci cb->x = 0; 3328c2ecf20Sopenharmony_ci cb->y = 0; 3338c2ecf20Sopenharmony_ci cb->z = 0; 3348c2ecf20Sopenharmony_ci cb->srcx = 0; 3358c2ecf20Sopenharmony_ci cb->srcy = 0; 3368c2ecf20Sopenharmony_ci cb->srcz = 0; 3378c2ecf20Sopenharmony_ci cb->w = cur_size->width; 3388c2ecf20Sopenharmony_ci cb->h = cur_size->height; 3398c2ecf20Sopenharmony_ci cb->d = cur_size->depth; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci suffix->suffixSize = sizeof(*suffix); 3428c2ecf20Sopenharmony_ci suffix->maximumOffset = 3438c2ecf20Sopenharmony_ci svga3dsurface_get_image_buffer_size(desc, cur_size, 3448c2ecf20Sopenharmony_ci body->guest.pitch); 3458c2ecf20Sopenharmony_ci suffix->flags.discard = 0; 3468c2ecf20Sopenharmony_ci suffix->flags.unsynchronized = 0; 3478c2ecf20Sopenharmony_ci suffix->flags.reserved = 0; 3488c2ecf20Sopenharmony_ci ++cmd; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/** 3548c2ecf20Sopenharmony_ci * vmw_hw_surface_destroy - destroy a Device surface 3558c2ecf20Sopenharmony_ci * 3568c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_resource embedded in a struct 3578c2ecf20Sopenharmony_ci * vmw_surface. 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Destroys a the device surface associated with a struct vmw_surface if 3608c2ecf20Sopenharmony_ci * any, and adjusts accounting and resource count accordingly. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_cistatic void vmw_hw_surface_destroy(struct vmw_resource *res) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 3668c2ecf20Sopenharmony_ci void *cmd; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (res->func->destroy == vmw_gb_surface_destroy) { 3698c2ecf20Sopenharmony_ci (void) vmw_gb_surface_destroy(res); 3708c2ecf20Sopenharmony_ci return; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (res->id != -1) { 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, vmw_surface_destroy_size()); 3768c2ecf20Sopenharmony_ci if (unlikely(!cmd)) 3778c2ecf20Sopenharmony_ci return; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci vmw_surface_destroy_encode(res->id, cmd); 3808c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, vmw_surface_destroy_size()); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * used_memory_size_atomic, or separate lock 3848c2ecf20Sopenharmony_ci * to avoid taking dev_priv::cmdbuf_mutex in 3858c2ecf20Sopenharmony_ci * the destroy path. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci mutex_lock(&dev_priv->cmdbuf_mutex); 3898c2ecf20Sopenharmony_ci dev_priv->used_memory_size -= res->backup_size; 3908c2ecf20Sopenharmony_ci mutex_unlock(&dev_priv->cmdbuf_mutex); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * vmw_legacy_srf_create - Create a device surface as part of the 3968c2ecf20Sopenharmony_ci * resource validation process. 3978c2ecf20Sopenharmony_ci * 3988c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_surface. 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * If the surface doesn't have a hw id. 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * Returns -EBUSY if there wasn't sufficient device resources to 4038c2ecf20Sopenharmony_ci * complete the validation. Retry after freeing up resources. 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * May return other errors if the kernel is out of guest resources. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_create(struct vmw_resource *res) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 4108c2ecf20Sopenharmony_ci struct vmw_surface *srf; 4118c2ecf20Sopenharmony_ci uint32_t submit_size; 4128c2ecf20Sopenharmony_ci uint8_t *cmd; 4138c2ecf20Sopenharmony_ci int ret; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (likely(res->id != -1)) 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci srf = vmw_res_to_srf(res); 4198c2ecf20Sopenharmony_ci if (unlikely(dev_priv->used_memory_size + res->backup_size >= 4208c2ecf20Sopenharmony_ci dev_priv->memory_size)) 4218c2ecf20Sopenharmony_ci return -EBUSY; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * Alloc id for the resource. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = vmw_resource_alloc_id(res); 4288c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 4298c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate a surface id.\n"); 4308c2ecf20Sopenharmony_ci goto out_no_id; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) { 4348c2ecf20Sopenharmony_ci ret = -EBUSY; 4358c2ecf20Sopenharmony_ci goto out_no_fifo; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* 4398c2ecf20Sopenharmony_ci * Encode surface define- commands. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci submit_size = vmw_surface_define_size(srf); 4438c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, submit_size); 4448c2ecf20Sopenharmony_ci if (unlikely(!cmd)) { 4458c2ecf20Sopenharmony_ci ret = -ENOMEM; 4468c2ecf20Sopenharmony_ci goto out_no_fifo; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci vmw_surface_define_encode(srf, cmd); 4508c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_size); 4518c2ecf20Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * Surface memory usage accounting. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dev_priv->used_memory_size += res->backup_size; 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciout_no_fifo: 4618c2ecf20Sopenharmony_ci vmw_resource_release_id(res); 4628c2ecf20Sopenharmony_ciout_no_id: 4638c2ecf20Sopenharmony_ci return ret; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/** 4678c2ecf20Sopenharmony_ci * vmw_legacy_srf_dma - Copy backup data to or from a legacy surface. 4688c2ecf20Sopenharmony_ci * 4698c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 4708c2ecf20Sopenharmony_ci * vmw_surface. 4718c2ecf20Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 4728c2ecf20Sopenharmony_ci * information about the backup buffer. 4738c2ecf20Sopenharmony_ci * @bind: Boolean wether to DMA to the surface. 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci * Transfer backup data to or from a legacy surface as part of the 4768c2ecf20Sopenharmony_ci * validation process. 4778c2ecf20Sopenharmony_ci * May return other errors if the kernel is out of guest resources. 4788c2ecf20Sopenharmony_ci * The backup buffer will be fenced or idle upon successful completion, 4798c2ecf20Sopenharmony_ci * and if the surface needs persistent backup storage, the backup buffer 4808c2ecf20Sopenharmony_ci * will also be returned reserved iff @bind is true. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_dma(struct vmw_resource *res, 4838c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf, 4848c2ecf20Sopenharmony_ci bool bind) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci SVGAGuestPtr ptr; 4878c2ecf20Sopenharmony_ci struct vmw_fence_obj *fence; 4888c2ecf20Sopenharmony_ci uint32_t submit_size; 4898c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 4908c2ecf20Sopenharmony_ci uint8_t *cmd; 4918c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci BUG_ON(!val_buf->bo); 4948c2ecf20Sopenharmony_ci submit_size = vmw_surface_dma_size(srf); 4958c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, submit_size); 4968c2ecf20Sopenharmony_ci if (unlikely(!cmd)) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(val_buf->bo, &ptr); 5008c2ecf20Sopenharmony_ci vmw_surface_dma_encode(srf, cmd, &ptr, bind); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_size); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* 5058c2ecf20Sopenharmony_ci * Create a fence object and fence the backup buffer. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 5098c2ecf20Sopenharmony_ci &fence, NULL); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci vmw_bo_fence_single(val_buf->bo, fence); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (likely(fence != NULL)) 5148c2ecf20Sopenharmony_ci vmw_fence_obj_unreference(&fence); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/** 5208c2ecf20Sopenharmony_ci * vmw_legacy_srf_bind - Perform a legacy surface bind as part of the 5218c2ecf20Sopenharmony_ci * surface validation process. 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 5248c2ecf20Sopenharmony_ci * vmw_surface. 5258c2ecf20Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 5268c2ecf20Sopenharmony_ci * information about the backup buffer. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * This function will copy backup data to the surface if the 5298c2ecf20Sopenharmony_ci * backup buffer is dirty. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_bind(struct vmw_resource *res, 5328c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci if (!res->backup_dirty) 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return vmw_legacy_srf_dma(res, val_buf, true); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/** 5428c2ecf20Sopenharmony_ci * vmw_legacy_srf_unbind - Perform a legacy surface unbind as part of the 5438c2ecf20Sopenharmony_ci * surface eviction process. 5448c2ecf20Sopenharmony_ci * 5458c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 5468c2ecf20Sopenharmony_ci * vmw_surface. 5478c2ecf20Sopenharmony_ci * @val_buf: Pointer to a struct ttm_validate_buffer containing 5488c2ecf20Sopenharmony_ci * information about the backup buffer. 5498c2ecf20Sopenharmony_ci * 5508c2ecf20Sopenharmony_ci * This function will copy backup data from the surface. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_unbind(struct vmw_resource *res, 5538c2ecf20Sopenharmony_ci bool readback, 5548c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci if (unlikely(readback)) 5578c2ecf20Sopenharmony_ci return vmw_legacy_srf_dma(res, val_buf, false); 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * vmw_legacy_srf_destroy - Destroy a device surface as part of a 5638c2ecf20Sopenharmony_ci * resource eviction process. 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * @res: Pointer to a struct vmw_res embedded in a struct 5668c2ecf20Sopenharmony_ci * vmw_surface. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_cistatic int vmw_legacy_srf_destroy(struct vmw_resource *res) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 5718c2ecf20Sopenharmony_ci uint32_t submit_size; 5728c2ecf20Sopenharmony_ci uint8_t *cmd; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci BUG_ON(res->id == -1); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * Encode the dma- and surface destroy commands. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci submit_size = vmw_surface_destroy_size(); 5818c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, submit_size); 5828c2ecf20Sopenharmony_ci if (unlikely(!cmd)) 5838c2ecf20Sopenharmony_ci return -ENOMEM; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci vmw_surface_destroy_encode(res->id, cmd); 5868c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_size); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* 5898c2ecf20Sopenharmony_ci * Surface memory usage accounting. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci dev_priv->used_memory_size -= res->backup_size; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * Release the surface ID. 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci vmw_resource_release_id(res); 5998c2ecf20Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci/** 6068c2ecf20Sopenharmony_ci * vmw_surface_init - initialize a struct vmw_surface 6078c2ecf20Sopenharmony_ci * 6088c2ecf20Sopenharmony_ci * @dev_priv: Pointer to a device private struct. 6098c2ecf20Sopenharmony_ci * @srf: Pointer to the struct vmw_surface to initialize. 6108c2ecf20Sopenharmony_ci * @res_free: Pointer to a resource destructor used to free 6118c2ecf20Sopenharmony_ci * the object. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_cistatic int vmw_surface_init(struct vmw_private *dev_priv, 6148c2ecf20Sopenharmony_ci struct vmw_surface *srf, 6158c2ecf20Sopenharmony_ci void (*res_free) (struct vmw_resource *res)) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int ret; 6188c2ecf20Sopenharmony_ci struct vmw_resource *res = &srf->res; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci BUG_ON(!res_free); 6218c2ecf20Sopenharmony_ci ret = vmw_resource_init(dev_priv, res, true, res_free, 6228c2ecf20Sopenharmony_ci (dev_priv->has_mob) ? &vmw_gb_surface_func : 6238c2ecf20Sopenharmony_ci &vmw_legacy_surface_func); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 6268c2ecf20Sopenharmony_ci res_free(res); 6278c2ecf20Sopenharmony_ci return ret; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * The surface won't be visible to hardware until a 6328c2ecf20Sopenharmony_ci * surface validate. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&srf->view_list); 6368c2ecf20Sopenharmony_ci res->hw_destroy = vmw_hw_surface_destroy; 6378c2ecf20Sopenharmony_ci return ret; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci/** 6418c2ecf20Sopenharmony_ci * vmw_user_surface_base_to_res - TTM base object to resource converter for 6428c2ecf20Sopenharmony_ci * user visible surfaces 6438c2ecf20Sopenharmony_ci * 6448c2ecf20Sopenharmony_ci * @base: Pointer to a TTM base object 6458c2ecf20Sopenharmony_ci * 6468c2ecf20Sopenharmony_ci * Returns the struct vmw_resource embedded in a struct vmw_surface 6478c2ecf20Sopenharmony_ci * for the user-visible object identified by the TTM base object @base. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_cistatic struct vmw_resource * 6508c2ecf20Sopenharmony_civmw_user_surface_base_to_res(struct ttm_base_object *base) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci return &(container_of(base, struct vmw_user_surface, 6538c2ecf20Sopenharmony_ci prime.base)->srf.res); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/** 6578c2ecf20Sopenharmony_ci * vmw_user_surface_free - User visible surface resource destructor 6588c2ecf20Sopenharmony_ci * 6598c2ecf20Sopenharmony_ci * @res: A struct vmw_resource embedded in a struct vmw_surface. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_cistatic void vmw_user_surface_free(struct vmw_resource *res) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 6648c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf = 6658c2ecf20Sopenharmony_ci container_of(srf, struct vmw_user_surface, srf); 6668c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = srf->res.dev_priv; 6678c2ecf20Sopenharmony_ci uint32_t size = user_srf->size; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci WARN_ON_ONCE(res->dirty); 6708c2ecf20Sopenharmony_ci if (user_srf->master) 6718c2ecf20Sopenharmony_ci drm_master_put(&user_srf->master); 6728c2ecf20Sopenharmony_ci kfree(srf->offsets); 6738c2ecf20Sopenharmony_ci kfree(srf->metadata.sizes); 6748c2ecf20Sopenharmony_ci kfree(srf->snooper.image); 6758c2ecf20Sopenharmony_ci ttm_prime_object_kfree(user_srf, prime); 6768c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(dev_priv), size); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci/** 6808c2ecf20Sopenharmony_ci * vmw_user_surface_free - User visible surface TTM base object destructor 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * @p_base: Pointer to a pointer to a TTM base object 6838c2ecf20Sopenharmony_ci * embedded in a struct vmw_user_surface. 6848c2ecf20Sopenharmony_ci * 6858c2ecf20Sopenharmony_ci * Drops the base object's reference on its resource, and the 6868c2ecf20Sopenharmony_ci * pointer pointed to by *p_base is set to NULL. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_cistatic void vmw_user_surface_base_release(struct ttm_base_object **p_base) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct ttm_base_object *base = *p_base; 6918c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf = 6928c2ecf20Sopenharmony_ci container_of(base, struct vmw_user_surface, prime.base); 6938c2ecf20Sopenharmony_ci struct vmw_resource *res = &user_srf->srf.res; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci *p_base = NULL; 6968c2ecf20Sopenharmony_ci if (user_srf->backup_base) 6978c2ecf20Sopenharmony_ci ttm_base_object_unref(&user_srf->backup_base); 6988c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/** 7028c2ecf20Sopenharmony_ci * vmw_user_surface_destroy_ioctl - Ioctl function implementing 7038c2ecf20Sopenharmony_ci * the user surface destroy functionality. 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 7068c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 7078c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ciint vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, 7108c2ecf20Sopenharmony_ci struct drm_file *file_priv) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; 7138c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci/** 7198c2ecf20Sopenharmony_ci * vmw_user_surface_define_ioctl - Ioctl function implementing 7208c2ecf20Sopenharmony_ci * the user surface define functionality. 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 7238c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 7248c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 7258c2ecf20Sopenharmony_ci */ 7268c2ecf20Sopenharmony_ciint vmw_surface_define_ioctl(struct drm_device *dev, void *data, 7278c2ecf20Sopenharmony_ci struct drm_file *file_priv) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 7308c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 7318c2ecf20Sopenharmony_ci struct vmw_surface *srf; 7328c2ecf20Sopenharmony_ci struct vmw_surface_metadata *metadata; 7338c2ecf20Sopenharmony_ci struct vmw_resource *res; 7348c2ecf20Sopenharmony_ci struct vmw_resource *tmp; 7358c2ecf20Sopenharmony_ci union drm_vmw_surface_create_arg *arg = 7368c2ecf20Sopenharmony_ci (union drm_vmw_surface_create_arg *)data; 7378c2ecf20Sopenharmony_ci struct drm_vmw_surface_create_req *req = &arg->req; 7388c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *rep = &arg->rep; 7398c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 7408c2ecf20Sopenharmony_ci struct ttm_operation_ctx ctx = { 7418c2ecf20Sopenharmony_ci .interruptible = true, 7428c2ecf20Sopenharmony_ci .no_wait_gpu = false 7438c2ecf20Sopenharmony_ci }; 7448c2ecf20Sopenharmony_ci int ret; 7458c2ecf20Sopenharmony_ci int i, j; 7468c2ecf20Sopenharmony_ci uint32_t cur_bo_offset; 7478c2ecf20Sopenharmony_ci struct drm_vmw_size *cur_size; 7488c2ecf20Sopenharmony_ci struct vmw_surface_offset *cur_offset; 7498c2ecf20Sopenharmony_ci uint32_t num_sizes; 7508c2ecf20Sopenharmony_ci uint32_t size; 7518c2ecf20Sopenharmony_ci const struct svga3d_surface_desc *desc; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (unlikely(vmw_user_surface_size == 0)) 7548c2ecf20Sopenharmony_ci vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + 7558c2ecf20Sopenharmony_ci VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci num_sizes = 0; 7588c2ecf20Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 7598c2ecf20Sopenharmony_ci if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS) 7608c2ecf20Sopenharmony_ci return -EINVAL; 7618c2ecf20Sopenharmony_ci num_sizes += req->mip_levels[i]; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS || 7658c2ecf20Sopenharmony_ci num_sizes == 0) 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci size = vmw_user_surface_size + 7698c2ecf20Sopenharmony_ci ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) + 7708c2ecf20Sopenharmony_ci ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset)); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci desc = svga3dsurface_get_desc(req->format); 7738c2ecf20Sopenharmony_ci if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { 7748c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid format %d for surface creation.\n", 7758c2ecf20Sopenharmony_ci req->format); 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 7808c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 7848c2ecf20Sopenharmony_ci size, &ctx); 7858c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 7868c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 7878c2ecf20Sopenharmony_ci DRM_ERROR("Out of graphics memory for surface.\n"); 7888c2ecf20Sopenharmony_ci goto out_unlock; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); 7928c2ecf20Sopenharmony_ci if (unlikely(!user_srf)) { 7938c2ecf20Sopenharmony_ci ret = -ENOMEM; 7948c2ecf20Sopenharmony_ci goto out_no_user_srf; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci srf = &user_srf->srf; 7988c2ecf20Sopenharmony_ci metadata = &srf->metadata; 7998c2ecf20Sopenharmony_ci res = &srf->res; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* Driver internally stores as 64-bit flags */ 8028c2ecf20Sopenharmony_ci metadata->flags = (SVGA3dSurfaceAllFlags)req->flags; 8038c2ecf20Sopenharmony_ci metadata->format = req->format; 8048c2ecf20Sopenharmony_ci metadata->scanout = req->scanout; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci memcpy(metadata->mip_levels, req->mip_levels, 8078c2ecf20Sopenharmony_ci sizeof(metadata->mip_levels)); 8088c2ecf20Sopenharmony_ci metadata->num_sizes = num_sizes; 8098c2ecf20Sopenharmony_ci user_srf->size = size; 8108c2ecf20Sopenharmony_ci metadata->sizes = 8118c2ecf20Sopenharmony_ci memdup_user((struct drm_vmw_size __user *)(unsigned long) 8128c2ecf20Sopenharmony_ci req->size_addr, 8138c2ecf20Sopenharmony_ci sizeof(*metadata->sizes) * metadata->num_sizes); 8148c2ecf20Sopenharmony_ci if (IS_ERR(metadata->sizes)) { 8158c2ecf20Sopenharmony_ci ret = PTR_ERR(metadata->sizes); 8168c2ecf20Sopenharmony_ci goto out_no_sizes; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci srf->offsets = kmalloc_array(metadata->num_sizes, sizeof(*srf->offsets), 8198c2ecf20Sopenharmony_ci GFP_KERNEL); 8208c2ecf20Sopenharmony_ci if (unlikely(!srf->offsets)) { 8218c2ecf20Sopenharmony_ci ret = -ENOMEM; 8228c2ecf20Sopenharmony_ci goto out_no_offsets; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci metadata->base_size = *srf->metadata.sizes; 8268c2ecf20Sopenharmony_ci metadata->autogen_filter = SVGA3D_TEX_FILTER_NONE; 8278c2ecf20Sopenharmony_ci metadata->multisample_count = 0; 8288c2ecf20Sopenharmony_ci metadata->multisample_pattern = SVGA3D_MS_PATTERN_NONE; 8298c2ecf20Sopenharmony_ci metadata->quality_level = SVGA3D_MS_QUALITY_NONE; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci cur_bo_offset = 0; 8328c2ecf20Sopenharmony_ci cur_offset = srf->offsets; 8338c2ecf20Sopenharmony_ci cur_size = metadata->sizes; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 8368c2ecf20Sopenharmony_ci for (j = 0; j < metadata->mip_levels[i]; ++j) { 8378c2ecf20Sopenharmony_ci uint32_t stride = svga3dsurface_calculate_pitch 8388c2ecf20Sopenharmony_ci (desc, cur_size); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci cur_offset->face = i; 8418c2ecf20Sopenharmony_ci cur_offset->mip = j; 8428c2ecf20Sopenharmony_ci cur_offset->bo_offset = cur_bo_offset; 8438c2ecf20Sopenharmony_ci cur_bo_offset += svga3dsurface_get_image_buffer_size 8448c2ecf20Sopenharmony_ci (desc, cur_size, stride); 8458c2ecf20Sopenharmony_ci ++cur_offset; 8468c2ecf20Sopenharmony_ci ++cur_size; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci res->backup_size = cur_bo_offset; 8508c2ecf20Sopenharmony_ci if (metadata->scanout && 8518c2ecf20Sopenharmony_ci metadata->num_sizes == 1 && 8528c2ecf20Sopenharmony_ci metadata->sizes[0].width == 64 && 8538c2ecf20Sopenharmony_ci metadata->sizes[0].height == 64 && 8548c2ecf20Sopenharmony_ci metadata->format == SVGA3D_A8R8G8B8) { 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL); 8578c2ecf20Sopenharmony_ci if (!srf->snooper.image) { 8588c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate cursor_image\n"); 8598c2ecf20Sopenharmony_ci ret = -ENOMEM; 8608c2ecf20Sopenharmony_ci goto out_no_copy; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } else { 8638c2ecf20Sopenharmony_ci srf->snooper.image = NULL; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci user_srf->prime.base.shareable = false; 8678c2ecf20Sopenharmony_ci user_srf->prime.base.tfile = NULL; 8688c2ecf20Sopenharmony_ci if (drm_is_primary_client(file_priv)) 8698c2ecf20Sopenharmony_ci user_srf->master = drm_file_get_master(file_priv); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /** 8728c2ecf20Sopenharmony_ci * From this point, the generic resource management functions 8738c2ecf20Sopenharmony_ci * destroy the object on failure. 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); 8778c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 8788c2ecf20Sopenharmony_ci goto out_unlock; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* 8818c2ecf20Sopenharmony_ci * A gb-aware client referencing a shared surface will 8828c2ecf20Sopenharmony_ci * expect a backup buffer to be present. 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ci if (dev_priv->has_mob && req->shareable) { 8858c2ecf20Sopenharmony_ci uint32_t backup_handle; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci ret = vmw_user_bo_alloc(dev_priv, tfile, 8888c2ecf20Sopenharmony_ci res->backup_size, 8898c2ecf20Sopenharmony_ci true, 8908c2ecf20Sopenharmony_ci &backup_handle, 8918c2ecf20Sopenharmony_ci &res->backup, 8928c2ecf20Sopenharmony_ci &user_srf->backup_base); 8938c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 8948c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 8958c2ecf20Sopenharmony_ci goto out_unlock; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci tmp = vmw_resource_reference(&srf->res); 9008c2ecf20Sopenharmony_ci ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, 9018c2ecf20Sopenharmony_ci req->shareable, VMW_RES_SURFACE, 9028c2ecf20Sopenharmony_ci &vmw_user_surface_base_release, NULL); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 9058c2ecf20Sopenharmony_ci vmw_resource_unreference(&tmp); 9068c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 9078c2ecf20Sopenharmony_ci goto out_unlock; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci rep->sid = user_srf->prime.base.handle; 9118c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ciout_no_copy: 9168c2ecf20Sopenharmony_ci kfree(srf->offsets); 9178c2ecf20Sopenharmony_ciout_no_offsets: 9188c2ecf20Sopenharmony_ci kfree(metadata->sizes); 9198c2ecf20Sopenharmony_ciout_no_sizes: 9208c2ecf20Sopenharmony_ci ttm_prime_object_kfree(user_srf, prime); 9218c2ecf20Sopenharmony_ciout_no_user_srf: 9228c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(dev_priv), size); 9238c2ecf20Sopenharmony_ciout_unlock: 9248c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 9258c2ecf20Sopenharmony_ci return ret; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int 9308c2ecf20Sopenharmony_civmw_surface_handle_reference(struct vmw_private *dev_priv, 9318c2ecf20Sopenharmony_ci struct drm_file *file_priv, 9328c2ecf20Sopenharmony_ci uint32_t u_handle, 9338c2ecf20Sopenharmony_ci enum drm_vmw_handle_type handle_type, 9348c2ecf20Sopenharmony_ci struct ttm_base_object **base_p) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 9378c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 9388c2ecf20Sopenharmony_ci uint32_t handle; 9398c2ecf20Sopenharmony_ci struct ttm_base_object *base; 9408c2ecf20Sopenharmony_ci int ret; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (handle_type == DRM_VMW_HANDLE_PRIME) { 9438c2ecf20Sopenharmony_ci ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); 9448c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 9458c2ecf20Sopenharmony_ci return ret; 9468c2ecf20Sopenharmony_ci } else { 9478c2ecf20Sopenharmony_ci handle = u_handle; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci ret = -EINVAL; 9518c2ecf20Sopenharmony_ci base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle); 9528c2ecf20Sopenharmony_ci if (unlikely(!base)) { 9538c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Could not find surface to reference.\n"); 9548c2ecf20Sopenharmony_ci goto out_no_lookup; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) { 9588c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Referenced object is not a surface.\n"); 9598c2ecf20Sopenharmony_ci goto out_bad_resource; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (handle_type != DRM_VMW_HANDLE_PRIME) { 9638c2ecf20Sopenharmony_ci bool require_exist = false; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, 9668c2ecf20Sopenharmony_ci prime.base); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Error out if we are unauthenticated primary */ 9698c2ecf20Sopenharmony_ci if (drm_is_primary_client(file_priv) && 9708c2ecf20Sopenharmony_ci !file_priv->authenticated) { 9718c2ecf20Sopenharmony_ci ret = -EACCES; 9728c2ecf20Sopenharmony_ci goto out_bad_resource; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* 9768c2ecf20Sopenharmony_ci * Make sure the surface creator has the same 9778c2ecf20Sopenharmony_ci * authenticating master, or is already registered with us. 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci if (drm_is_primary_client(file_priv) && 9808c2ecf20Sopenharmony_ci user_srf->master != file_priv->master) 9818c2ecf20Sopenharmony_ci require_exist = true; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (unlikely(drm_is_render_client(file_priv))) 9848c2ecf20Sopenharmony_ci require_exist = true; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, 9878c2ecf20Sopenharmony_ci require_exist); 9888c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 9898c2ecf20Sopenharmony_ci DRM_ERROR("Could not add a reference to a surface.\n"); 9908c2ecf20Sopenharmony_ci goto out_bad_resource; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci *base_p = base; 9958c2ecf20Sopenharmony_ci return 0; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ciout_bad_resource: 9988c2ecf20Sopenharmony_ci ttm_base_object_unref(&base); 9998c2ecf20Sopenharmony_ciout_no_lookup: 10008c2ecf20Sopenharmony_ci if (handle_type == DRM_VMW_HANDLE_PRIME) 10018c2ecf20Sopenharmony_ci (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return ret; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/** 10078c2ecf20Sopenharmony_ci * vmw_user_surface_define_ioctl - Ioctl function implementing 10088c2ecf20Sopenharmony_ci * the user surface reference functionality. 10098c2ecf20Sopenharmony_ci * 10108c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 10118c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 10128c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_ciint vmw_surface_reference_ioctl(struct drm_device *dev, void *data, 10158c2ecf20Sopenharmony_ci struct drm_file *file_priv) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 10188c2ecf20Sopenharmony_ci union drm_vmw_surface_reference_arg *arg = 10198c2ecf20Sopenharmony_ci (union drm_vmw_surface_reference_arg *)data; 10208c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 10218c2ecf20Sopenharmony_ci struct drm_vmw_surface_create_req *rep = &arg->rep; 10228c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 10238c2ecf20Sopenharmony_ci struct vmw_surface *srf; 10248c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 10258c2ecf20Sopenharmony_ci struct drm_vmw_size __user *user_sizes; 10268c2ecf20Sopenharmony_ci struct ttm_base_object *base; 10278c2ecf20Sopenharmony_ci int ret; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, 10308c2ecf20Sopenharmony_ci req->handle_type, &base); 10318c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 10328c2ecf20Sopenharmony_ci return ret; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, prime.base); 10358c2ecf20Sopenharmony_ci srf = &user_srf->srf; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Downcast of flags when sending back to user space */ 10388c2ecf20Sopenharmony_ci rep->flags = (uint32_t)srf->metadata.flags; 10398c2ecf20Sopenharmony_ci rep->format = srf->metadata.format; 10408c2ecf20Sopenharmony_ci memcpy(rep->mip_levels, srf->metadata.mip_levels, 10418c2ecf20Sopenharmony_ci sizeof(srf->metadata.mip_levels)); 10428c2ecf20Sopenharmony_ci user_sizes = (struct drm_vmw_size __user *)(unsigned long) 10438c2ecf20Sopenharmony_ci rep->size_addr; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (user_sizes) 10468c2ecf20Sopenharmony_ci ret = copy_to_user(user_sizes, &srf->metadata.base_size, 10478c2ecf20Sopenharmony_ci sizeof(srf->metadata.base_size)); 10488c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 10498c2ecf20Sopenharmony_ci VMW_DEBUG_USER("copy_to_user failed %p %u\n", user_sizes, 10508c2ecf20Sopenharmony_ci srf->metadata.num_sizes); 10518c2ecf20Sopenharmony_ci ttm_ref_object_base_unref(tfile, base->handle, TTM_REF_USAGE); 10528c2ecf20Sopenharmony_ci ret = -EFAULT; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ttm_base_object_unref(&base); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return ret; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/** 10618c2ecf20Sopenharmony_ci * vmw_surface_define_encode - Encode a surface_define command. 10628c2ecf20Sopenharmony_ci * 10638c2ecf20Sopenharmony_ci * @srf: Pointer to a struct vmw_surface object. 10648c2ecf20Sopenharmony_ci * @cmd_space: Pointer to memory area in which the commands should be encoded. 10658c2ecf20Sopenharmony_ci */ 10668c2ecf20Sopenharmony_cistatic int vmw_gb_surface_create(struct vmw_resource *res) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 10698c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 10708c2ecf20Sopenharmony_ci struct vmw_surface_metadata *metadata = &srf->metadata; 10718c2ecf20Sopenharmony_ci uint32_t cmd_len, cmd_id, submit_len; 10728c2ecf20Sopenharmony_ci int ret; 10738c2ecf20Sopenharmony_ci struct { 10748c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 10758c2ecf20Sopenharmony_ci SVGA3dCmdDefineGBSurface body; 10768c2ecf20Sopenharmony_ci } *cmd; 10778c2ecf20Sopenharmony_ci struct { 10788c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 10798c2ecf20Sopenharmony_ci SVGA3dCmdDefineGBSurface_v2 body; 10808c2ecf20Sopenharmony_ci } *cmd2; 10818c2ecf20Sopenharmony_ci struct { 10828c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 10838c2ecf20Sopenharmony_ci SVGA3dCmdDefineGBSurface_v3 body; 10848c2ecf20Sopenharmony_ci } *cmd3; 10858c2ecf20Sopenharmony_ci struct { 10868c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 10878c2ecf20Sopenharmony_ci SVGA3dCmdDefineGBSurface_v4 body; 10888c2ecf20Sopenharmony_ci } *cmd4; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (likely(res->id != -1)) 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci vmw_fifo_resource_inc(dev_priv); 10948c2ecf20Sopenharmony_ci ret = vmw_resource_alloc_id(res); 10958c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 10968c2ecf20Sopenharmony_ci DRM_ERROR("Failed to allocate a surface id.\n"); 10978c2ecf20Sopenharmony_ci goto out_no_id; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) { 11018c2ecf20Sopenharmony_ci ret = -EBUSY; 11028c2ecf20Sopenharmony_ci goto out_no_fifo; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (has_sm5_context(dev_priv) && metadata->array_size > 0) { 11068c2ecf20Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V4; 11078c2ecf20Sopenharmony_ci cmd_len = sizeof(cmd4->body); 11088c2ecf20Sopenharmony_ci submit_len = sizeof(*cmd4); 11098c2ecf20Sopenharmony_ci } else if (has_sm4_1_context(dev_priv) && metadata->array_size > 0) { 11108c2ecf20Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V3; 11118c2ecf20Sopenharmony_ci cmd_len = sizeof(cmd3->body); 11128c2ecf20Sopenharmony_ci submit_len = sizeof(*cmd3); 11138c2ecf20Sopenharmony_ci } else if (metadata->array_size > 0) { 11148c2ecf20Sopenharmony_ci /* VMW_SM_4 support verified at creation time. */ 11158c2ecf20Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2; 11168c2ecf20Sopenharmony_ci cmd_len = sizeof(cmd2->body); 11178c2ecf20Sopenharmony_ci submit_len = sizeof(*cmd2); 11188c2ecf20Sopenharmony_ci } else { 11198c2ecf20Sopenharmony_ci cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE; 11208c2ecf20Sopenharmony_ci cmd_len = sizeof(cmd->body); 11218c2ecf20Sopenharmony_ci submit_len = sizeof(*cmd); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, submit_len); 11258c2ecf20Sopenharmony_ci cmd2 = (typeof(cmd2))cmd; 11268c2ecf20Sopenharmony_ci cmd3 = (typeof(cmd3))cmd; 11278c2ecf20Sopenharmony_ci cmd4 = (typeof(cmd4))cmd; 11288c2ecf20Sopenharmony_ci if (unlikely(!cmd)) { 11298c2ecf20Sopenharmony_ci ret = -ENOMEM; 11308c2ecf20Sopenharmony_ci goto out_no_fifo; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (has_sm5_context(dev_priv) && metadata->array_size > 0) { 11348c2ecf20Sopenharmony_ci cmd4->header.id = cmd_id; 11358c2ecf20Sopenharmony_ci cmd4->header.size = cmd_len; 11368c2ecf20Sopenharmony_ci cmd4->body.sid = srf->res.id; 11378c2ecf20Sopenharmony_ci cmd4->body.surfaceFlags = metadata->flags; 11388c2ecf20Sopenharmony_ci cmd4->body.format = metadata->format; 11398c2ecf20Sopenharmony_ci cmd4->body.numMipLevels = metadata->mip_levels[0]; 11408c2ecf20Sopenharmony_ci cmd4->body.multisampleCount = metadata->multisample_count; 11418c2ecf20Sopenharmony_ci cmd4->body.multisamplePattern = metadata->multisample_pattern; 11428c2ecf20Sopenharmony_ci cmd4->body.qualityLevel = metadata->quality_level; 11438c2ecf20Sopenharmony_ci cmd4->body.autogenFilter = metadata->autogen_filter; 11448c2ecf20Sopenharmony_ci cmd4->body.size.width = metadata->base_size.width; 11458c2ecf20Sopenharmony_ci cmd4->body.size.height = metadata->base_size.height; 11468c2ecf20Sopenharmony_ci cmd4->body.size.depth = metadata->base_size.depth; 11478c2ecf20Sopenharmony_ci cmd4->body.arraySize = metadata->array_size; 11488c2ecf20Sopenharmony_ci cmd4->body.bufferByteStride = metadata->buffer_byte_stride; 11498c2ecf20Sopenharmony_ci } else if (has_sm4_1_context(dev_priv) && metadata->array_size > 0) { 11508c2ecf20Sopenharmony_ci cmd3->header.id = cmd_id; 11518c2ecf20Sopenharmony_ci cmd3->header.size = cmd_len; 11528c2ecf20Sopenharmony_ci cmd3->body.sid = srf->res.id; 11538c2ecf20Sopenharmony_ci cmd3->body.surfaceFlags = metadata->flags; 11548c2ecf20Sopenharmony_ci cmd3->body.format = metadata->format; 11558c2ecf20Sopenharmony_ci cmd3->body.numMipLevels = metadata->mip_levels[0]; 11568c2ecf20Sopenharmony_ci cmd3->body.multisampleCount = metadata->multisample_count; 11578c2ecf20Sopenharmony_ci cmd3->body.multisamplePattern = metadata->multisample_pattern; 11588c2ecf20Sopenharmony_ci cmd3->body.qualityLevel = metadata->quality_level; 11598c2ecf20Sopenharmony_ci cmd3->body.autogenFilter = metadata->autogen_filter; 11608c2ecf20Sopenharmony_ci cmd3->body.size.width = metadata->base_size.width; 11618c2ecf20Sopenharmony_ci cmd3->body.size.height = metadata->base_size.height; 11628c2ecf20Sopenharmony_ci cmd3->body.size.depth = metadata->base_size.depth; 11638c2ecf20Sopenharmony_ci cmd3->body.arraySize = metadata->array_size; 11648c2ecf20Sopenharmony_ci } else if (metadata->array_size > 0) { 11658c2ecf20Sopenharmony_ci cmd2->header.id = cmd_id; 11668c2ecf20Sopenharmony_ci cmd2->header.size = cmd_len; 11678c2ecf20Sopenharmony_ci cmd2->body.sid = srf->res.id; 11688c2ecf20Sopenharmony_ci cmd2->body.surfaceFlags = metadata->flags; 11698c2ecf20Sopenharmony_ci cmd2->body.format = metadata->format; 11708c2ecf20Sopenharmony_ci cmd2->body.numMipLevels = metadata->mip_levels[0]; 11718c2ecf20Sopenharmony_ci cmd2->body.multisampleCount = metadata->multisample_count; 11728c2ecf20Sopenharmony_ci cmd2->body.autogenFilter = metadata->autogen_filter; 11738c2ecf20Sopenharmony_ci cmd2->body.size.width = metadata->base_size.width; 11748c2ecf20Sopenharmony_ci cmd2->body.size.height = metadata->base_size.height; 11758c2ecf20Sopenharmony_ci cmd2->body.size.depth = metadata->base_size.depth; 11768c2ecf20Sopenharmony_ci cmd2->body.arraySize = metadata->array_size; 11778c2ecf20Sopenharmony_ci } else { 11788c2ecf20Sopenharmony_ci cmd->header.id = cmd_id; 11798c2ecf20Sopenharmony_ci cmd->header.size = cmd_len; 11808c2ecf20Sopenharmony_ci cmd->body.sid = srf->res.id; 11818c2ecf20Sopenharmony_ci cmd->body.surfaceFlags = metadata->flags; 11828c2ecf20Sopenharmony_ci cmd->body.format = metadata->format; 11838c2ecf20Sopenharmony_ci cmd->body.numMipLevels = metadata->mip_levels[0]; 11848c2ecf20Sopenharmony_ci cmd->body.multisampleCount = metadata->multisample_count; 11858c2ecf20Sopenharmony_ci cmd->body.autogenFilter = metadata->autogen_filter; 11868c2ecf20Sopenharmony_ci cmd->body.size.width = metadata->base_size.width; 11878c2ecf20Sopenharmony_ci cmd->body.size.height = metadata->base_size.height; 11888c2ecf20Sopenharmony_ci cmd->body.size.depth = metadata->base_size.depth; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_len); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ciout_no_fifo: 11968c2ecf20Sopenharmony_ci vmw_resource_release_id(res); 11978c2ecf20Sopenharmony_ciout_no_id: 11988c2ecf20Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 11998c2ecf20Sopenharmony_ci return ret; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int vmw_gb_surface_bind(struct vmw_resource *res, 12048c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 12078c2ecf20Sopenharmony_ci struct { 12088c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 12098c2ecf20Sopenharmony_ci SVGA3dCmdBindGBSurface body; 12108c2ecf20Sopenharmony_ci } *cmd1; 12118c2ecf20Sopenharmony_ci struct { 12128c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 12138c2ecf20Sopenharmony_ci SVGA3dCmdUpdateGBSurface body; 12148c2ecf20Sopenharmony_ci } *cmd2; 12158c2ecf20Sopenharmony_ci uint32_t submit_size; 12168c2ecf20Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci cmd1 = VMW_FIFO_RESERVE(dev_priv, submit_size); 12238c2ecf20Sopenharmony_ci if (unlikely(!cmd1)) 12248c2ecf20Sopenharmony_ci return -ENOMEM; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; 12278c2ecf20Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 12288c2ecf20Sopenharmony_ci cmd1->body.sid = res->id; 12298c2ecf20Sopenharmony_ci cmd1->body.mobid = bo->mem.start; 12308c2ecf20Sopenharmony_ci if (res->backup_dirty) { 12318c2ecf20Sopenharmony_ci cmd2 = (void *) &cmd1[1]; 12328c2ecf20Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; 12338c2ecf20Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 12348c2ecf20Sopenharmony_ci cmd2->body.sid = res->id; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_size); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (res->backup->dirty && res->backup_dirty) { 12398c2ecf20Sopenharmony_ci /* We've just made a full upload. Cear dirty regions. */ 12408c2ecf20Sopenharmony_ci vmw_bo_dirty_clear_res(res); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci res->backup_dirty = false; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int vmw_gb_surface_unbind(struct vmw_resource *res, 12498c2ecf20Sopenharmony_ci bool readback, 12508c2ecf20Sopenharmony_ci struct ttm_validate_buffer *val_buf) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 12538c2ecf20Sopenharmony_ci struct ttm_buffer_object *bo = val_buf->bo; 12548c2ecf20Sopenharmony_ci struct vmw_fence_obj *fence; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci struct { 12578c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 12588c2ecf20Sopenharmony_ci SVGA3dCmdReadbackGBSurface body; 12598c2ecf20Sopenharmony_ci } *cmd1; 12608c2ecf20Sopenharmony_ci struct { 12618c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 12628c2ecf20Sopenharmony_ci SVGA3dCmdInvalidateGBSurface body; 12638c2ecf20Sopenharmony_ci } *cmd2; 12648c2ecf20Sopenharmony_ci struct { 12658c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 12668c2ecf20Sopenharmony_ci SVGA3dCmdBindGBSurface body; 12678c2ecf20Sopenharmony_ci } *cmd3; 12688c2ecf20Sopenharmony_ci uint32_t submit_size; 12698c2ecf20Sopenharmony_ci uint8_t *cmd; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2)); 12758c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, submit_size); 12768c2ecf20Sopenharmony_ci if (unlikely(!cmd)) 12778c2ecf20Sopenharmony_ci return -ENOMEM; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (readback) { 12808c2ecf20Sopenharmony_ci cmd1 = (void *) cmd; 12818c2ecf20Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; 12828c2ecf20Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 12838c2ecf20Sopenharmony_ci cmd1->body.sid = res->id; 12848c2ecf20Sopenharmony_ci cmd3 = (void *) &cmd1[1]; 12858c2ecf20Sopenharmony_ci } else { 12868c2ecf20Sopenharmony_ci cmd2 = (void *) cmd; 12878c2ecf20Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE; 12888c2ecf20Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 12898c2ecf20Sopenharmony_ci cmd2->body.sid = res->id; 12908c2ecf20Sopenharmony_ci cmd3 = (void *) &cmd2[1]; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE; 12948c2ecf20Sopenharmony_ci cmd3->header.size = sizeof(cmd3->body); 12958c2ecf20Sopenharmony_ci cmd3->body.sid = res->id; 12968c2ecf20Sopenharmony_ci cmd3->body.mobid = SVGA3D_INVALID_ID; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, submit_size); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* 13018c2ecf20Sopenharmony_ci * Create a fence object and fence the backup buffer. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci (void) vmw_execbuf_fence_commands(NULL, dev_priv, 13058c2ecf20Sopenharmony_ci &fence, NULL); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci vmw_bo_fence_single(val_buf->bo, fence); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (likely(fence != NULL)) 13108c2ecf20Sopenharmony_ci vmw_fence_obj_unreference(&fence); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return 0; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int vmw_gb_surface_destroy(struct vmw_resource *res) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 13188c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 13198c2ecf20Sopenharmony_ci struct { 13208c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 13218c2ecf20Sopenharmony_ci SVGA3dCmdDestroyGBSurface body; 13228c2ecf20Sopenharmony_ci } *cmd; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (likely(res->id == -1)) 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci mutex_lock(&dev_priv->binding_mutex); 13288c2ecf20Sopenharmony_ci vmw_view_surface_list_destroy(dev_priv, &srf->view_list); 13298c2ecf20Sopenharmony_ci vmw_binding_res_list_scrub(&res->binding_head); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 13328c2ecf20Sopenharmony_ci if (unlikely(!cmd)) { 13338c2ecf20Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 13348c2ecf20Sopenharmony_ci return -ENOMEM; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE; 13388c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 13398c2ecf20Sopenharmony_ci cmd->body.sid = res->id; 13408c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 13418c2ecf20Sopenharmony_ci mutex_unlock(&dev_priv->binding_mutex); 13428c2ecf20Sopenharmony_ci vmw_resource_release_id(res); 13438c2ecf20Sopenharmony_ci vmw_fifo_resource_dec(dev_priv); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci return 0; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci/** 13498c2ecf20Sopenharmony_ci * vmw_gb_surface_define_ioctl - Ioctl function implementing 13508c2ecf20Sopenharmony_ci * the user surface define functionality. 13518c2ecf20Sopenharmony_ci * 13528c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 13538c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 13548c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 13558c2ecf20Sopenharmony_ci */ 13568c2ecf20Sopenharmony_ciint vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, 13578c2ecf20Sopenharmony_ci struct drm_file *file_priv) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci union drm_vmw_gb_surface_create_arg *arg = 13608c2ecf20Sopenharmony_ci (union drm_vmw_gb_surface_create_arg *)data; 13618c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; 13628c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req req_ext; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci req_ext.base = arg->req; 13658c2ecf20Sopenharmony_ci req_ext.version = drm_vmw_gb_surface_v1; 13668c2ecf20Sopenharmony_ci req_ext.svga3d_flags_upper_32_bits = 0; 13678c2ecf20Sopenharmony_ci req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; 13688c2ecf20Sopenharmony_ci req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; 13698c2ecf20Sopenharmony_ci req_ext.buffer_byte_stride = 0; 13708c2ecf20Sopenharmony_ci req_ext.must_be_zero = 0; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci/** 13768c2ecf20Sopenharmony_ci * vmw_gb_surface_reference_ioctl - Ioctl function implementing 13778c2ecf20Sopenharmony_ci * the user surface reference functionality. 13788c2ecf20Sopenharmony_ci * 13798c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 13808c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 13818c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 13828c2ecf20Sopenharmony_ci */ 13838c2ecf20Sopenharmony_ciint vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, 13848c2ecf20Sopenharmony_ci struct drm_file *file_priv) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci union drm_vmw_gb_surface_reference_arg *arg = 13878c2ecf20Sopenharmony_ci (union drm_vmw_gb_surface_reference_arg *)data; 13888c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 13898c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; 13908c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep rep_ext; 13918c2ecf20Sopenharmony_ci int ret; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 13968c2ecf20Sopenharmony_ci return ret; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci rep->creq = rep_ext.creq.base; 13998c2ecf20Sopenharmony_ci rep->crep = rep_ext.crep; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci return ret; 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci/** 14058c2ecf20Sopenharmony_ci * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing 14068c2ecf20Sopenharmony_ci * the user surface define functionality. 14078c2ecf20Sopenharmony_ci * 14088c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 14098c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 14108c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_ciint vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, 14138c2ecf20Sopenharmony_ci struct drm_file *file_priv) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci union drm_vmw_gb_surface_create_ext_arg *arg = 14168c2ecf20Sopenharmony_ci (union drm_vmw_gb_surface_create_ext_arg *)data; 14178c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; 14188c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci return vmw_gb_surface_define_internal(dev, req, rep, file_priv); 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci/** 14248c2ecf20Sopenharmony_ci * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing 14258c2ecf20Sopenharmony_ci * the user surface reference functionality. 14268c2ecf20Sopenharmony_ci * 14278c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 14288c2ecf20Sopenharmony_ci * @data: Pointer to data copied from / to user-space. 14298c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 14308c2ecf20Sopenharmony_ci */ 14318c2ecf20Sopenharmony_ciint vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, 14328c2ecf20Sopenharmony_ci struct drm_file *file_priv) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci union drm_vmw_gb_surface_reference_ext_arg *arg = 14358c2ecf20Sopenharmony_ci (union drm_vmw_gb_surface_reference_ext_arg *)data; 14368c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *req = &arg->req; 14378c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci/** 14438c2ecf20Sopenharmony_ci * vmw_gb_surface_define_internal - Ioctl function implementing 14448c2ecf20Sopenharmony_ci * the user surface define functionality. 14458c2ecf20Sopenharmony_ci * 14468c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 14478c2ecf20Sopenharmony_ci * @req: Request argument from user-space. 14488c2ecf20Sopenharmony_ci * @rep: Response argument to user-space. 14498c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_cistatic int 14528c2ecf20Sopenharmony_civmw_gb_surface_define_internal(struct drm_device *dev, 14538c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_ext_req *req, 14548c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_create_rep *rep, 14558c2ecf20Sopenharmony_ci struct drm_file *file_priv) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 14588c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 14598c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 14608c2ecf20Sopenharmony_ci struct vmw_surface_metadata metadata = {0}; 14618c2ecf20Sopenharmony_ci struct vmw_surface *srf; 14628c2ecf20Sopenharmony_ci struct vmw_resource *res; 14638c2ecf20Sopenharmony_ci struct vmw_resource *tmp; 14648c2ecf20Sopenharmony_ci int ret = 0; 14658c2ecf20Sopenharmony_ci uint32_t size; 14668c2ecf20Sopenharmony_ci uint32_t backup_handle = 0; 14678c2ecf20Sopenharmony_ci SVGA3dSurfaceAllFlags svga3d_flags_64 = 14688c2ecf20Sopenharmony_ci SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, 14698c2ecf20Sopenharmony_ci req->base.svga3d_flags); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* array_size must be null for non-GL3 host. */ 14728c2ecf20Sopenharmony_ci if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) { 14738c2ecf20Sopenharmony_ci VMW_DEBUG_USER("SM4 surface not supported.\n"); 14748c2ecf20Sopenharmony_ci return -EINVAL; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (!has_sm4_1_context(dev_priv)) { 14788c2ecf20Sopenharmony_ci if (req->svga3d_flags_upper_32_bits != 0) 14798c2ecf20Sopenharmony_ci ret = -EINVAL; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (req->base.multisample_count != 0) 14828c2ecf20Sopenharmony_ci ret = -EINVAL; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) 14858c2ecf20Sopenharmony_ci ret = -EINVAL; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (req->quality_level != SVGA3D_MS_QUALITY_NONE) 14888c2ecf20Sopenharmony_ci ret = -EINVAL; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (ret) { 14918c2ecf20Sopenharmony_ci VMW_DEBUG_USER("SM4.1 surface not supported.\n"); 14928c2ecf20Sopenharmony_ci return ret; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (req->buffer_byte_stride > 0 && !has_sm5_context(dev_priv)) { 14978c2ecf20Sopenharmony_ci VMW_DEBUG_USER("SM5 surface not supported.\n"); 14988c2ecf20Sopenharmony_ci return -EINVAL; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if ((svga3d_flags_64 & SVGA3D_SURFACE_MULTISAMPLE) && 15028c2ecf20Sopenharmony_ci req->base.multisample_count == 0) { 15038c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid sample count.\n"); 15048c2ecf20Sopenharmony_ci return -EINVAL; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) { 15088c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid mip level.\n"); 15098c2ecf20Sopenharmony_ci return -EINVAL; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (unlikely(vmw_user_surface_size == 0)) 15138c2ecf20Sopenharmony_ci vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + 15148c2ecf20Sopenharmony_ci VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci size = vmw_user_surface_size; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci metadata.flags = svga3d_flags_64; 15198c2ecf20Sopenharmony_ci metadata.format = req->base.format; 15208c2ecf20Sopenharmony_ci metadata.mip_levels[0] = req->base.mip_levels; 15218c2ecf20Sopenharmony_ci metadata.multisample_count = req->base.multisample_count; 15228c2ecf20Sopenharmony_ci metadata.multisample_pattern = req->multisample_pattern; 15238c2ecf20Sopenharmony_ci metadata.quality_level = req->quality_level; 15248c2ecf20Sopenharmony_ci metadata.array_size = req->base.array_size; 15258c2ecf20Sopenharmony_ci metadata.buffer_byte_stride = req->buffer_byte_stride; 15268c2ecf20Sopenharmony_ci metadata.num_sizes = 1; 15278c2ecf20Sopenharmony_ci metadata.base_size = req->base.base_size; 15288c2ecf20Sopenharmony_ci metadata.scanout = req->base.drm_surface_flags & 15298c2ecf20Sopenharmony_ci drm_vmw_surface_flag_scanout; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* Define a surface based on the parameters. */ 15328c2ecf20Sopenharmony_ci ret = vmw_gb_surface_define(dev_priv, size, &metadata, &srf); 15338c2ecf20Sopenharmony_ci if (ret != 0) { 15348c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Failed to define surface.\n"); 15358c2ecf20Sopenharmony_ci return ret; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci user_srf = container_of(srf, struct vmw_user_surface, srf); 15398c2ecf20Sopenharmony_ci if (drm_is_primary_client(file_priv)) 15408c2ecf20Sopenharmony_ci user_srf->master = drm_file_get_master(file_priv); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 15438c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 15448c2ecf20Sopenharmony_ci return ret; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci res = &user_srf->srf.res; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (req->base.buffer_handle != SVGA3D_INVALID_ID) { 15498c2ecf20Sopenharmony_ci ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, 15508c2ecf20Sopenharmony_ci &res->backup, 15518c2ecf20Sopenharmony_ci &user_srf->backup_base); 15528c2ecf20Sopenharmony_ci if (ret == 0) { 15538c2ecf20Sopenharmony_ci if (res->backup->base.num_pages * PAGE_SIZE < 15548c2ecf20Sopenharmony_ci res->backup_size) { 15558c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Surface backup buffer too small.\n"); 15568c2ecf20Sopenharmony_ci vmw_bo_unreference(&res->backup); 15578c2ecf20Sopenharmony_ci ret = -EINVAL; 15588c2ecf20Sopenharmony_ci goto out_unlock; 15598c2ecf20Sopenharmony_ci } else { 15608c2ecf20Sopenharmony_ci backup_handle = req->base.buffer_handle; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci } else if (req->base.drm_surface_flags & 15648c2ecf20Sopenharmony_ci (drm_vmw_surface_flag_create_buffer | 15658c2ecf20Sopenharmony_ci drm_vmw_surface_flag_coherent)) 15668c2ecf20Sopenharmony_ci ret = vmw_user_bo_alloc(dev_priv, tfile, 15678c2ecf20Sopenharmony_ci res->backup_size, 15688c2ecf20Sopenharmony_ci req->base.drm_surface_flags & 15698c2ecf20Sopenharmony_ci drm_vmw_surface_flag_shareable, 15708c2ecf20Sopenharmony_ci &backup_handle, 15718c2ecf20Sopenharmony_ci &res->backup, 15728c2ecf20Sopenharmony_ci &user_srf->backup_base); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 15758c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 15768c2ecf20Sopenharmony_ci goto out_unlock; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (req->base.drm_surface_flags & drm_vmw_surface_flag_coherent) { 15808c2ecf20Sopenharmony_ci struct vmw_buffer_object *backup = res->backup; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci ttm_bo_reserve(&backup->base, false, false, NULL); 15838c2ecf20Sopenharmony_ci if (!res->func->dirty_alloc) 15848c2ecf20Sopenharmony_ci ret = -EINVAL; 15858c2ecf20Sopenharmony_ci if (!ret) 15868c2ecf20Sopenharmony_ci ret = vmw_bo_dirty_add(backup); 15878c2ecf20Sopenharmony_ci if (!ret) { 15888c2ecf20Sopenharmony_ci res->coherent = true; 15898c2ecf20Sopenharmony_ci ret = res->func->dirty_alloc(res); 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci ttm_bo_unreserve(&backup->base); 15928c2ecf20Sopenharmony_ci if (ret) { 15938c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 15948c2ecf20Sopenharmony_ci goto out_unlock; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci tmp = vmw_resource_reference(res); 16008c2ecf20Sopenharmony_ci ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, 16018c2ecf20Sopenharmony_ci req->base.drm_surface_flags & 16028c2ecf20Sopenharmony_ci drm_vmw_surface_flag_shareable, 16038c2ecf20Sopenharmony_ci VMW_RES_SURFACE, 16048c2ecf20Sopenharmony_ci &vmw_user_surface_base_release, NULL); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 16078c2ecf20Sopenharmony_ci vmw_resource_unreference(&tmp); 16088c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 16098c2ecf20Sopenharmony_ci goto out_unlock; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci rep->handle = user_srf->prime.base.handle; 16138c2ecf20Sopenharmony_ci rep->backup_size = res->backup_size; 16148c2ecf20Sopenharmony_ci if (res->backup) { 16158c2ecf20Sopenharmony_ci rep->buffer_map_handle = 16168c2ecf20Sopenharmony_ci drm_vma_node_offset_addr(&res->backup->base.base.vma_node); 16178c2ecf20Sopenharmony_ci rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; 16188c2ecf20Sopenharmony_ci rep->buffer_handle = backup_handle; 16198c2ecf20Sopenharmony_ci } else { 16208c2ecf20Sopenharmony_ci rep->buffer_map_handle = 0; 16218c2ecf20Sopenharmony_ci rep->buffer_size = 0; 16228c2ecf20Sopenharmony_ci rep->buffer_handle = SVGA3D_INVALID_ID; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ciout_unlock: 16288c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 16298c2ecf20Sopenharmony_ci return ret; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci/** 16338c2ecf20Sopenharmony_ci * vmw_gb_surface_reference_internal - Ioctl function implementing 16348c2ecf20Sopenharmony_ci * the user surface reference functionality. 16358c2ecf20Sopenharmony_ci * 16368c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm_device. 16378c2ecf20Sopenharmony_ci * @req: Pointer to user-space request surface arg. 16388c2ecf20Sopenharmony_ci * @rep: Pointer to response to user-space. 16398c2ecf20Sopenharmony_ci * @file_priv: Pointer to a drm file private structure. 16408c2ecf20Sopenharmony_ci */ 16418c2ecf20Sopenharmony_cistatic int 16428c2ecf20Sopenharmony_civmw_gb_surface_reference_internal(struct drm_device *dev, 16438c2ecf20Sopenharmony_ci struct drm_vmw_surface_arg *req, 16448c2ecf20Sopenharmony_ci struct drm_vmw_gb_surface_ref_ext_rep *rep, 16458c2ecf20Sopenharmony_ci struct drm_file *file_priv) 16468c2ecf20Sopenharmony_ci{ 16478c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 16488c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 16498c2ecf20Sopenharmony_ci struct vmw_surface *srf; 16508c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 16518c2ecf20Sopenharmony_ci struct vmw_surface_metadata *metadata; 16528c2ecf20Sopenharmony_ci struct ttm_base_object *base; 16538c2ecf20Sopenharmony_ci uint32_t backup_handle; 16548c2ecf20Sopenharmony_ci int ret; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, 16578c2ecf20Sopenharmony_ci req->handle_type, &base); 16588c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 16598c2ecf20Sopenharmony_ci return ret; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci user_srf = container_of(base, struct vmw_user_surface, prime.base); 16628c2ecf20Sopenharmony_ci srf = &user_srf->srf; 16638c2ecf20Sopenharmony_ci if (!srf->res.backup) { 16648c2ecf20Sopenharmony_ci DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); 16658c2ecf20Sopenharmony_ci goto out_bad_resource; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci metadata = &srf->metadata; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ 16708c2ecf20Sopenharmony_ci ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); 16718c2ecf20Sopenharmony_ci mutex_unlock(&dev_priv->cmdbuf_mutex); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 16748c2ecf20Sopenharmony_ci DRM_ERROR("Could not add a reference to a GB surface " 16758c2ecf20Sopenharmony_ci "backup buffer.\n"); 16768c2ecf20Sopenharmony_ci (void) ttm_ref_object_base_unref(tfile, base->handle, 16778c2ecf20Sopenharmony_ci TTM_REF_USAGE); 16788c2ecf20Sopenharmony_ci goto out_bad_resource; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(metadata->flags); 16828c2ecf20Sopenharmony_ci rep->creq.base.format = metadata->format; 16838c2ecf20Sopenharmony_ci rep->creq.base.mip_levels = metadata->mip_levels[0]; 16848c2ecf20Sopenharmony_ci rep->creq.base.drm_surface_flags = 0; 16858c2ecf20Sopenharmony_ci rep->creq.base.multisample_count = metadata->multisample_count; 16868c2ecf20Sopenharmony_ci rep->creq.base.autogen_filter = metadata->autogen_filter; 16878c2ecf20Sopenharmony_ci rep->creq.base.array_size = metadata->array_size; 16888c2ecf20Sopenharmony_ci rep->creq.base.buffer_handle = backup_handle; 16898c2ecf20Sopenharmony_ci rep->creq.base.base_size = metadata->base_size; 16908c2ecf20Sopenharmony_ci rep->crep.handle = user_srf->prime.base.handle; 16918c2ecf20Sopenharmony_ci rep->crep.backup_size = srf->res.backup_size; 16928c2ecf20Sopenharmony_ci rep->crep.buffer_handle = backup_handle; 16938c2ecf20Sopenharmony_ci rep->crep.buffer_map_handle = 16948c2ecf20Sopenharmony_ci drm_vma_node_offset_addr(&srf->res.backup->base.base.vma_node); 16958c2ecf20Sopenharmony_ci rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci rep->creq.version = drm_vmw_gb_surface_v1; 16988c2ecf20Sopenharmony_ci rep->creq.svga3d_flags_upper_32_bits = 16998c2ecf20Sopenharmony_ci SVGA3D_FLAGS_UPPER_32(metadata->flags); 17008c2ecf20Sopenharmony_ci rep->creq.multisample_pattern = metadata->multisample_pattern; 17018c2ecf20Sopenharmony_ci rep->creq.quality_level = metadata->quality_level; 17028c2ecf20Sopenharmony_ci rep->creq.must_be_zero = 0; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ciout_bad_resource: 17058c2ecf20Sopenharmony_ci ttm_base_object_unref(&base); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci return ret; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci/** 17118c2ecf20Sopenharmony_ci * vmw_subres_dirty_add - Add a dirty region to a subresource 17128c2ecf20Sopenharmony_ci * @dirty: The surfaces's dirty tracker. 17138c2ecf20Sopenharmony_ci * @loc_start: The location corresponding to the start of the region. 17148c2ecf20Sopenharmony_ci * @loc_end: The location corresponding to the end of the region. 17158c2ecf20Sopenharmony_ci * 17168c2ecf20Sopenharmony_ci * As we are assuming that @loc_start and @loc_end represent a sequential 17178c2ecf20Sopenharmony_ci * range of backing store memory, if the region spans multiple lines then 17188c2ecf20Sopenharmony_ci * regardless of the x coordinate, the full lines are dirtied. 17198c2ecf20Sopenharmony_ci * Correspondingly if the region spans multiple z slices, then full rather 17208c2ecf20Sopenharmony_ci * than partial z slices are dirtied. 17218c2ecf20Sopenharmony_ci */ 17228c2ecf20Sopenharmony_cistatic void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty, 17238c2ecf20Sopenharmony_ci const struct svga3dsurface_loc *loc_start, 17248c2ecf20Sopenharmony_ci const struct svga3dsurface_loc *loc_end) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci const struct svga3dsurface_cache *cache = &dirty->cache; 17278c2ecf20Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[loc_start->sub_resource]; 17288c2ecf20Sopenharmony_ci u32 mip = loc_start->sub_resource % cache->num_mip_levels; 17298c2ecf20Sopenharmony_ci const struct drm_vmw_size *size = &cache->mip[mip].size; 17308c2ecf20Sopenharmony_ci u32 box_c2 = box->z + box->d; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci if (WARN_ON(loc_start->sub_resource >= dirty->num_subres)) 17338c2ecf20Sopenharmony_ci return; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci if (box->d == 0 || box->z > loc_start->z) 17368c2ecf20Sopenharmony_ci box->z = loc_start->z; 17378c2ecf20Sopenharmony_ci if (box_c2 < loc_end->z) 17388c2ecf20Sopenharmony_ci box->d = loc_end->z - box->z; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (loc_start->z + 1 == loc_end->z) { 17418c2ecf20Sopenharmony_ci box_c2 = box->y + box->h; 17428c2ecf20Sopenharmony_ci if (box->h == 0 || box->y > loc_start->y) 17438c2ecf20Sopenharmony_ci box->y = loc_start->y; 17448c2ecf20Sopenharmony_ci if (box_c2 < loc_end->y) 17458c2ecf20Sopenharmony_ci box->h = loc_end->y - box->y; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (loc_start->y + 1 == loc_end->y) { 17488c2ecf20Sopenharmony_ci box_c2 = box->x + box->w; 17498c2ecf20Sopenharmony_ci if (box->w == 0 || box->x > loc_start->x) 17508c2ecf20Sopenharmony_ci box->x = loc_start->x; 17518c2ecf20Sopenharmony_ci if (box_c2 < loc_end->x) 17528c2ecf20Sopenharmony_ci box->w = loc_end->x - box->x; 17538c2ecf20Sopenharmony_ci } else { 17548c2ecf20Sopenharmony_ci box->x = 0; 17558c2ecf20Sopenharmony_ci box->w = size->width; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci } else { 17588c2ecf20Sopenharmony_ci box->y = 0; 17598c2ecf20Sopenharmony_ci box->h = size->height; 17608c2ecf20Sopenharmony_ci box->x = 0; 17618c2ecf20Sopenharmony_ci box->w = size->width; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci/** 17668c2ecf20Sopenharmony_ci * vmw_subres_dirty_full - Mark a full subresource as dirty 17678c2ecf20Sopenharmony_ci * @dirty: The surface's dirty tracker. 17688c2ecf20Sopenharmony_ci * @subres: The subresource 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_cistatic void vmw_subres_dirty_full(struct vmw_surface_dirty *dirty, u32 subres) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci const struct svga3dsurface_cache *cache = &dirty->cache; 17738c2ecf20Sopenharmony_ci u32 mip = subres % cache->num_mip_levels; 17748c2ecf20Sopenharmony_ci const struct drm_vmw_size *size = &cache->mip[mip].size; 17758c2ecf20Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[subres]; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci box->x = 0; 17788c2ecf20Sopenharmony_ci box->y = 0; 17798c2ecf20Sopenharmony_ci box->z = 0; 17808c2ecf20Sopenharmony_ci box->w = size->width; 17818c2ecf20Sopenharmony_ci box->h = size->height; 17828c2ecf20Sopenharmony_ci box->d = size->depth; 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci/* 17868c2ecf20Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for texture 17878c2ecf20Sopenharmony_ci * surfaces. 17888c2ecf20Sopenharmony_ci */ 17898c2ecf20Sopenharmony_cistatic void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, 17908c2ecf20Sopenharmony_ci size_t start, size_t end) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct vmw_surface_dirty *dirty = 17938c2ecf20Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 17948c2ecf20Sopenharmony_ci size_t backup_end = res->backup_offset + res->backup_size; 17958c2ecf20Sopenharmony_ci struct svga3dsurface_loc loc1, loc2; 17968c2ecf20Sopenharmony_ci const struct svga3dsurface_cache *cache; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci start = max_t(size_t, start, res->backup_offset) - res->backup_offset; 17998c2ecf20Sopenharmony_ci end = min(end, backup_end) - res->backup_offset; 18008c2ecf20Sopenharmony_ci cache = &dirty->cache; 18018c2ecf20Sopenharmony_ci svga3dsurface_get_loc(cache, &loc1, start); 18028c2ecf20Sopenharmony_ci svga3dsurface_get_loc(cache, &loc2, end - 1); 18038c2ecf20Sopenharmony_ci svga3dsurface_inc_loc(cache, &loc2); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (loc1.sheet != loc2.sheet) { 18068c2ecf20Sopenharmony_ci u32 sub_res; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* 18098c2ecf20Sopenharmony_ci * Multiple multisample sheets. To do this in an optimized 18108c2ecf20Sopenharmony_ci * fashion, compute the dirty region for each sheet and the 18118c2ecf20Sopenharmony_ci * resulting union. Since this is not a common case, just dirty 18128c2ecf20Sopenharmony_ci * the whole surface. 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_ci for (sub_res = 0; sub_res < dirty->num_subres; ++sub_res) 18158c2ecf20Sopenharmony_ci vmw_subres_dirty_full(dirty, sub_res); 18168c2ecf20Sopenharmony_ci return; 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci if (loc1.sub_resource + 1 == loc2.sub_resource) { 18198c2ecf20Sopenharmony_ci /* Dirty range covers a single sub-resource */ 18208c2ecf20Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc1, &loc2); 18218c2ecf20Sopenharmony_ci } else { 18228c2ecf20Sopenharmony_ci /* Dirty range covers multiple sub-resources */ 18238c2ecf20Sopenharmony_ci struct svga3dsurface_loc loc_min, loc_max; 18248c2ecf20Sopenharmony_ci u32 sub_res; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci svga3dsurface_max_loc(cache, loc1.sub_resource, &loc_max); 18278c2ecf20Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc1, &loc_max); 18288c2ecf20Sopenharmony_ci svga3dsurface_min_loc(cache, loc2.sub_resource - 1, &loc_min); 18298c2ecf20Sopenharmony_ci vmw_subres_dirty_add(dirty, &loc_min, &loc2); 18308c2ecf20Sopenharmony_ci for (sub_res = loc1.sub_resource + 1; 18318c2ecf20Sopenharmony_ci sub_res < loc2.sub_resource - 1; ++sub_res) 18328c2ecf20Sopenharmony_ci vmw_subres_dirty_full(dirty, sub_res); 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci} 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci/* 18378c2ecf20Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for buffer 18388c2ecf20Sopenharmony_ci * surfaces. 18398c2ecf20Sopenharmony_ci */ 18408c2ecf20Sopenharmony_cistatic void vmw_surface_buf_dirty_range_add(struct vmw_resource *res, 18418c2ecf20Sopenharmony_ci size_t start, size_t end) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci struct vmw_surface_dirty *dirty = 18448c2ecf20Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 18458c2ecf20Sopenharmony_ci const struct svga3dsurface_cache *cache = &dirty->cache; 18468c2ecf20Sopenharmony_ci size_t backup_end = res->backup_offset + cache->mip_chain_bytes; 18478c2ecf20Sopenharmony_ci SVGA3dBox *box = &dirty->boxes[0]; 18488c2ecf20Sopenharmony_ci u32 box_c2; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci box->h = box->d = 1; 18518c2ecf20Sopenharmony_ci start = max_t(size_t, start, res->backup_offset) - res->backup_offset; 18528c2ecf20Sopenharmony_ci end = min(end, backup_end) - res->backup_offset; 18538c2ecf20Sopenharmony_ci box_c2 = box->x + box->w; 18548c2ecf20Sopenharmony_ci if (box->w == 0 || box->x > start) 18558c2ecf20Sopenharmony_ci box->x = start; 18568c2ecf20Sopenharmony_ci if (box_c2 < end) 18578c2ecf20Sopenharmony_ci box->w = end - box->x; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci/* 18618c2ecf20Sopenharmony_ci * vmw_surface_tex_dirty_add_range - The dirty_add_range callback for surfaces 18628c2ecf20Sopenharmony_ci */ 18638c2ecf20Sopenharmony_cistatic void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, 18648c2ecf20Sopenharmony_ci size_t end) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (WARN_ON(end <= res->backup_offset || 18698c2ecf20Sopenharmony_ci start >= res->backup_offset + res->backup_size)) 18708c2ecf20Sopenharmony_ci return; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (srf->metadata.format == SVGA3D_BUFFER) 18738c2ecf20Sopenharmony_ci vmw_surface_buf_dirty_range_add(res, start, end); 18748c2ecf20Sopenharmony_ci else 18758c2ecf20Sopenharmony_ci vmw_surface_tex_dirty_range_add(res, start, end); 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci/* 18798c2ecf20Sopenharmony_ci * vmw_surface_dirty_sync - The surface's dirty_sync callback. 18808c2ecf20Sopenharmony_ci */ 18818c2ecf20Sopenharmony_cistatic int vmw_surface_dirty_sync(struct vmw_resource *res) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 18848c2ecf20Sopenharmony_ci bool has_dx = 0; 18858c2ecf20Sopenharmony_ci u32 i, num_dirty; 18868c2ecf20Sopenharmony_ci struct vmw_surface_dirty *dirty = 18878c2ecf20Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 18888c2ecf20Sopenharmony_ci size_t alloc_size; 18898c2ecf20Sopenharmony_ci const struct svga3dsurface_cache *cache = &dirty->cache; 18908c2ecf20Sopenharmony_ci struct { 18918c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 18928c2ecf20Sopenharmony_ci SVGA3dCmdDXUpdateSubResource body; 18938c2ecf20Sopenharmony_ci } *cmd1; 18948c2ecf20Sopenharmony_ci struct { 18958c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 18968c2ecf20Sopenharmony_ci SVGA3dCmdUpdateGBImage body; 18978c2ecf20Sopenharmony_ci } *cmd2; 18988c2ecf20Sopenharmony_ci void *cmd; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci num_dirty = 0; 19018c2ecf20Sopenharmony_ci for (i = 0; i < dirty->num_subres; ++i) { 19028c2ecf20Sopenharmony_ci const SVGA3dBox *box = &dirty->boxes[i]; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (box->d) 19058c2ecf20Sopenharmony_ci num_dirty++; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (!num_dirty) 19098c2ecf20Sopenharmony_ci goto out; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci alloc_size = num_dirty * ((has_dx) ? sizeof(*cmd1) : sizeof(*cmd2)); 19128c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size); 19138c2ecf20Sopenharmony_ci if (!cmd) 19148c2ecf20Sopenharmony_ci return -ENOMEM; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci cmd1 = cmd; 19178c2ecf20Sopenharmony_ci cmd2 = cmd; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci for (i = 0; i < dirty->num_subres; ++i) { 19208c2ecf20Sopenharmony_ci const SVGA3dBox *box = &dirty->boxes[i]; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci if (!box->d) 19238c2ecf20Sopenharmony_ci continue; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* 19268c2ecf20Sopenharmony_ci * DX_UPDATE_SUBRESOURCE is aware of array surfaces. 19278c2ecf20Sopenharmony_ci * UPDATE_GB_IMAGE is not. 19288c2ecf20Sopenharmony_ci */ 19298c2ecf20Sopenharmony_ci if (has_dx) { 19308c2ecf20Sopenharmony_ci cmd1->header.id = SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE; 19318c2ecf20Sopenharmony_ci cmd1->header.size = sizeof(cmd1->body); 19328c2ecf20Sopenharmony_ci cmd1->body.sid = res->id; 19338c2ecf20Sopenharmony_ci cmd1->body.subResource = i; 19348c2ecf20Sopenharmony_ci cmd1->body.box = *box; 19358c2ecf20Sopenharmony_ci cmd1++; 19368c2ecf20Sopenharmony_ci } else { 19378c2ecf20Sopenharmony_ci cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 19388c2ecf20Sopenharmony_ci cmd2->header.size = sizeof(cmd2->body); 19398c2ecf20Sopenharmony_ci cmd2->body.image.sid = res->id; 19408c2ecf20Sopenharmony_ci cmd2->body.image.face = i / cache->num_mip_levels; 19418c2ecf20Sopenharmony_ci cmd2->body.image.mipmap = i - 19428c2ecf20Sopenharmony_ci (cache->num_mip_levels * cmd2->body.image.face); 19438c2ecf20Sopenharmony_ci cmd2->body.box = *box; 19448c2ecf20Sopenharmony_ci cmd2++; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, alloc_size); 19498c2ecf20Sopenharmony_ci out: 19508c2ecf20Sopenharmony_ci memset(&dirty->boxes[0], 0, sizeof(dirty->boxes[0]) * 19518c2ecf20Sopenharmony_ci dirty->num_subres); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci return 0; 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci/* 19578c2ecf20Sopenharmony_ci * vmw_surface_dirty_alloc - The surface's dirty_alloc callback. 19588c2ecf20Sopenharmony_ci */ 19598c2ecf20Sopenharmony_cistatic int vmw_surface_dirty_alloc(struct vmw_resource *res) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci struct vmw_surface *srf = vmw_res_to_srf(res); 19628c2ecf20Sopenharmony_ci const struct vmw_surface_metadata *metadata = &srf->metadata; 19638c2ecf20Sopenharmony_ci struct vmw_surface_dirty *dirty; 19648c2ecf20Sopenharmony_ci u32 num_layers = 1; 19658c2ecf20Sopenharmony_ci u32 num_mip; 19668c2ecf20Sopenharmony_ci u32 num_subres; 19678c2ecf20Sopenharmony_ci u32 num_samples; 19688c2ecf20Sopenharmony_ci size_t dirty_size, acc_size; 19698c2ecf20Sopenharmony_ci static struct ttm_operation_ctx ctx = { 19708c2ecf20Sopenharmony_ci .interruptible = false, 19718c2ecf20Sopenharmony_ci .no_wait_gpu = false 19728c2ecf20Sopenharmony_ci }; 19738c2ecf20Sopenharmony_ci int ret; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (metadata->array_size) 19768c2ecf20Sopenharmony_ci num_layers = metadata->array_size; 19778c2ecf20Sopenharmony_ci else if (metadata->flags & SVGA3D_SURFACE_CUBEMAP) 19788c2ecf20Sopenharmony_ci num_layers *= SVGA3D_MAX_SURFACE_FACES; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci num_mip = metadata->mip_levels[0]; 19818c2ecf20Sopenharmony_ci if (!num_mip) 19828c2ecf20Sopenharmony_ci num_mip = 1; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci num_subres = num_layers * num_mip; 19858c2ecf20Sopenharmony_ci dirty_size = struct_size(dirty, boxes, num_subres); 19868c2ecf20Sopenharmony_ci acc_size = ttm_round_pot(dirty_size); 19878c2ecf20Sopenharmony_ci ret = ttm_mem_global_alloc(vmw_mem_glob(res->dev_priv), 19888c2ecf20Sopenharmony_ci acc_size, &ctx); 19898c2ecf20Sopenharmony_ci if (ret) { 19908c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Out of graphics memory for surface " 19918c2ecf20Sopenharmony_ci "dirty tracker.\n"); 19928c2ecf20Sopenharmony_ci return ret; 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci dirty = kvzalloc(dirty_size, GFP_KERNEL); 19968c2ecf20Sopenharmony_ci if (!dirty) { 19978c2ecf20Sopenharmony_ci ret = -ENOMEM; 19988c2ecf20Sopenharmony_ci goto out_no_dirty; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci num_samples = max_t(u32, 1, metadata->multisample_count); 20028c2ecf20Sopenharmony_ci ret = svga3dsurface_setup_cache(&metadata->base_size, metadata->format, 20038c2ecf20Sopenharmony_ci num_mip, num_layers, num_samples, 20048c2ecf20Sopenharmony_ci &dirty->cache); 20058c2ecf20Sopenharmony_ci if (ret) 20068c2ecf20Sopenharmony_ci goto out_no_cache; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci dirty->num_subres = num_subres; 20098c2ecf20Sopenharmony_ci dirty->size = acc_size; 20108c2ecf20Sopenharmony_ci res->dirty = (struct vmw_resource_dirty *) dirty; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci return 0; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ciout_no_cache: 20158c2ecf20Sopenharmony_ci kvfree(dirty); 20168c2ecf20Sopenharmony_ciout_no_dirty: 20178c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); 20188c2ecf20Sopenharmony_ci return ret; 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci/* 20228c2ecf20Sopenharmony_ci * vmw_surface_dirty_free - The surface's dirty_free callback 20238c2ecf20Sopenharmony_ci */ 20248c2ecf20Sopenharmony_cistatic void vmw_surface_dirty_free(struct vmw_resource *res) 20258c2ecf20Sopenharmony_ci{ 20268c2ecf20Sopenharmony_ci struct vmw_surface_dirty *dirty = 20278c2ecf20Sopenharmony_ci (struct vmw_surface_dirty *) res->dirty; 20288c2ecf20Sopenharmony_ci size_t acc_size = dirty->size; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci kvfree(dirty); 20318c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); 20328c2ecf20Sopenharmony_ci res->dirty = NULL; 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci/* 20368c2ecf20Sopenharmony_ci * vmw_surface_clean - The surface's clean callback 20378c2ecf20Sopenharmony_ci */ 20388c2ecf20Sopenharmony_cistatic int vmw_surface_clean(struct vmw_resource *res) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 20418c2ecf20Sopenharmony_ci size_t alloc_size; 20428c2ecf20Sopenharmony_ci struct { 20438c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 20448c2ecf20Sopenharmony_ci SVGA3dCmdReadbackGBSurface body; 20458c2ecf20Sopenharmony_ci } *cmd; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci alloc_size = sizeof(*cmd); 20488c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, alloc_size); 20498c2ecf20Sopenharmony_ci if (!cmd) 20508c2ecf20Sopenharmony_ci return -ENOMEM; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE; 20538c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 20548c2ecf20Sopenharmony_ci cmd->body.sid = res->id; 20558c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, alloc_size); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci return 0; 20588c2ecf20Sopenharmony_ci} 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci/* 20618c2ecf20Sopenharmony_ci * vmw_gb_surface_define - Define a private GB surface 20628c2ecf20Sopenharmony_ci * 20638c2ecf20Sopenharmony_ci * @dev_priv: Pointer to a device private. 20648c2ecf20Sopenharmony_ci * @user_accounting_size: Used to track user-space memory usage, set 20658c2ecf20Sopenharmony_ci * to 0 for kernel mode only memory 20668c2ecf20Sopenharmony_ci * @metadata: Metadata representing the surface to create. 20678c2ecf20Sopenharmony_ci * @user_srf_out: allocated user_srf. Set to NULL on failure. 20688c2ecf20Sopenharmony_ci * 20698c2ecf20Sopenharmony_ci * GB surfaces allocated by this function will not have a user mode handle, and 20708c2ecf20Sopenharmony_ci * thus will only be visible to vmwgfx. For optimization reasons the 20718c2ecf20Sopenharmony_ci * surface may later be given a user mode handle by another function to make 20728c2ecf20Sopenharmony_ci * it available to user mode drivers. 20738c2ecf20Sopenharmony_ci */ 20748c2ecf20Sopenharmony_ciint vmw_gb_surface_define(struct vmw_private *dev_priv, 20758c2ecf20Sopenharmony_ci uint32_t user_accounting_size, 20768c2ecf20Sopenharmony_ci const struct vmw_surface_metadata *req, 20778c2ecf20Sopenharmony_ci struct vmw_surface **srf_out) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct vmw_surface_metadata *metadata; 20808c2ecf20Sopenharmony_ci struct vmw_user_surface *user_srf; 20818c2ecf20Sopenharmony_ci struct vmw_surface *srf; 20828c2ecf20Sopenharmony_ci struct ttm_operation_ctx ctx = { 20838c2ecf20Sopenharmony_ci .interruptible = true, 20848c2ecf20Sopenharmony_ci .no_wait_gpu = false 20858c2ecf20Sopenharmony_ci }; 20868c2ecf20Sopenharmony_ci u32 sample_count = 1; 20878c2ecf20Sopenharmony_ci u32 num_layers = 1; 20888c2ecf20Sopenharmony_ci int ret; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci *srf_out = NULL; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci if (req->scanout) { 20938c2ecf20Sopenharmony_ci if (!svga3dsurface_is_screen_target_format(req->format)) { 20948c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid Screen Target surface format."); 20958c2ecf20Sopenharmony_ci return -EINVAL; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (req->base_size.width > dev_priv->texture_max_width || 20998c2ecf20Sopenharmony_ci req->base_size.height > dev_priv->texture_max_height) { 21008c2ecf20Sopenharmony_ci VMW_DEBUG_USER("%ux%u\n, exceed max surface size %ux%u", 21018c2ecf20Sopenharmony_ci req->base_size.width, 21028c2ecf20Sopenharmony_ci req->base_size.height, 21038c2ecf20Sopenharmony_ci dev_priv->texture_max_width, 21048c2ecf20Sopenharmony_ci dev_priv->texture_max_height); 21058c2ecf20Sopenharmony_ci return -EINVAL; 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci } else { 21088c2ecf20Sopenharmony_ci const struct svga3d_surface_desc *desc = 21098c2ecf20Sopenharmony_ci svga3dsurface_get_desc(req->format); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (desc->block_desc == SVGA3DBLOCKDESC_NONE) { 21128c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid surface format.\n"); 21138c2ecf20Sopenharmony_ci return -EINVAL; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (req->autogen_filter != SVGA3D_TEX_FILTER_NONE) 21188c2ecf20Sopenharmony_ci return -EINVAL; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (req->num_sizes != 1) 21218c2ecf20Sopenharmony_ci return -EINVAL; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (req->sizes != NULL) 21248c2ecf20Sopenharmony_ci return -EINVAL; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 21278c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 21288c2ecf20Sopenharmony_ci return ret; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 21318c2ecf20Sopenharmony_ci user_accounting_size, &ctx); 21328c2ecf20Sopenharmony_ci if (ret != 0) { 21338c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 21348c2ecf20Sopenharmony_ci DRM_ERROR("Out of graphics memory for surface.\n"); 21358c2ecf20Sopenharmony_ci goto out_unlock; 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); 21398c2ecf20Sopenharmony_ci if (unlikely(!user_srf)) { 21408c2ecf20Sopenharmony_ci ret = -ENOMEM; 21418c2ecf20Sopenharmony_ci goto out_no_user_srf; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci *srf_out = &user_srf->srf; 21458c2ecf20Sopenharmony_ci user_srf->size = user_accounting_size; 21468c2ecf20Sopenharmony_ci user_srf->prime.base.shareable = false; 21478c2ecf20Sopenharmony_ci user_srf->prime.base.tfile = NULL; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci srf = &user_srf->srf; 21508c2ecf20Sopenharmony_ci srf->metadata = *req; 21518c2ecf20Sopenharmony_ci srf->offsets = NULL; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci metadata = &srf->metadata; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (metadata->array_size) 21568c2ecf20Sopenharmony_ci num_layers = req->array_size; 21578c2ecf20Sopenharmony_ci else if (metadata->flags & SVGA3D_SURFACE_CUBEMAP) 21588c2ecf20Sopenharmony_ci num_layers = SVGA3D_MAX_SURFACE_FACES; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci if (metadata->flags & SVGA3D_SURFACE_MULTISAMPLE) 21618c2ecf20Sopenharmony_ci sample_count = metadata->multisample_count; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci srf->res.backup_size = 21648c2ecf20Sopenharmony_ci svga3dsurface_get_serialized_size_extended(metadata->format, 21658c2ecf20Sopenharmony_ci metadata->base_size, 21668c2ecf20Sopenharmony_ci metadata->mip_levels[0], 21678c2ecf20Sopenharmony_ci num_layers, 21688c2ecf20Sopenharmony_ci sample_count); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci if (metadata->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) 21718c2ecf20Sopenharmony_ci srf->res.backup_size += sizeof(SVGA3dDXSOState); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci /* 21748c2ecf20Sopenharmony_ci * Don't set SVGA3D_SURFACE_SCREENTARGET flag for a scanout surface with 21758c2ecf20Sopenharmony_ci * size greater than STDU max width/height. This is really a workaround 21768c2ecf20Sopenharmony_ci * to support creation of big framebuffer requested by some user-space 21778c2ecf20Sopenharmony_ci * for whole topology. That big framebuffer won't really be used for 21788c2ecf20Sopenharmony_ci * binding with screen target as during prepare_fb a separate surface is 21798c2ecf20Sopenharmony_ci * created so it's safe to ignore SVGA3D_SURFACE_SCREENTARGET flag. 21808c2ecf20Sopenharmony_ci */ 21818c2ecf20Sopenharmony_ci if (dev_priv->active_display_unit == vmw_du_screen_target && 21828c2ecf20Sopenharmony_ci metadata->scanout && 21838c2ecf20Sopenharmony_ci metadata->base_size.width <= dev_priv->stdu_max_width && 21848c2ecf20Sopenharmony_ci metadata->base_size.height <= dev_priv->stdu_max_height) 21858c2ecf20Sopenharmony_ci metadata->flags |= SVGA3D_SURFACE_SCREENTARGET; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci /* 21888c2ecf20Sopenharmony_ci * From this point, the generic resource management functions 21898c2ecf20Sopenharmony_ci * destroy the object on failure. 21908c2ecf20Sopenharmony_ci */ 21918c2ecf20Sopenharmony_ci ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 21948c2ecf20Sopenharmony_ci return ret; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ciout_no_user_srf: 21978c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ciout_unlock: 22008c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 22018c2ecf20Sopenharmony_ci return ret; 22028c2ecf20Sopenharmony_ci} 2203