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