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