diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_surface.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 678 |
1 files changed, 415 insertions, 263 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 0835468bb2ee..c4ac9b47e23a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1,59 +1,36 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * **************************************************************************/ -#include <drm/ttm/ttm_placement.h> - +#include "vmwgfx_bo.h" +#include "vmwgfx_cursor_plane.h" #include "vmwgfx_drv.h" #include "vmwgfx_resource_priv.h" #include "vmwgfx_so.h" #include "vmwgfx_binding.h" +#include "vmw_surface_cache.h" #include "device_include/svga3d_surfacedefs.h" +#include <drm/drm_dumb_buffers.h> +#include <drm/ttm/ttm_placement.h> + #define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) -#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) -#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ - (svga3d_flags & ((uint64_t)U32_MAX)) /** * struct vmw_user_surface - User-space visible surface resource * * @prime: The TTM prime object. - * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. - * @size: TTM accounting size for the surface. * @master: Master of the creating client. Used for security check. - * @backup_base: The TTM base object of the backup buffer. */ struct vmw_user_surface { struct ttm_prime_object prime; struct vmw_surface srf; - uint32_t size; struct drm_master *master; - struct ttm_base_object *backup_base; }; /** @@ -73,15 +50,13 @@ struct vmw_surface_offset { /** * struct vmw_surface_dirty - Surface dirty-tracker * @cache: Cached layout information of the surface. - * @size: Accounting size for the struct vmw_surface_dirty. * @num_subres: Number of subresources. * @boxes: Array of SVGA3dBoxes indicating dirty regions. One per subresource. */ struct vmw_surface_dirty { - struct svga3dsurface_cache cache; - size_t size; + struct vmw_surface_cache cache; u32 num_subres; - SVGA3dBox boxes[]; + SVGA3dBox boxes[] __counted_by(num_subres); }; static void vmw_user_surface_free(struct vmw_resource *res); @@ -128,17 +103,15 @@ static const struct vmw_user_resource_conv user_surface_conv = { const struct vmw_user_resource_conv *user_surface_converter = &user_surface_conv; - -static uint64_t vmw_user_surface_size; - static const struct vmw_res_func vmw_legacy_surface_func = { .res_type = vmw_res_surface, - .needs_backup = false, + .needs_guest_memory = false, .may_evict = true, .prio = 1, .dirty_prio = 1, .type_name = "legacy surfaces", - .backup_placement = &vmw_srf_placement, + .domain = VMW_BO_DOMAIN_GMR, + .busy_domain = VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM, .create = &vmw_legacy_srf_create, .destroy = &vmw_legacy_srf_destroy, .bind = &vmw_legacy_srf_bind, @@ -147,12 +120,13 @@ static const struct vmw_res_func vmw_legacy_surface_func = { static const struct vmw_res_func vmw_gb_surface_func = { .res_type = vmw_res_surface, - .needs_backup = true, + .needs_guest_memory = true, .may_evict = true, .prio = 1, .dirty_prio = 2, .type_name = "guest backed surfaces", - .backup_placement = &vmw_mob_placement, + .domain = VMW_BO_DOMAIN_MOB, + .busy_domain = VMW_BO_DOMAIN_MOB, .create = vmw_gb_surface_create, .destroy = vmw_gb_surface_destroy, .bind = vmw_gb_surface_bind, @@ -307,8 +281,8 @@ static void vmw_surface_dma_encode(struct vmw_surface *srf, { uint32_t i; struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space; - const struct svga3d_surface_desc *desc = - svga3dsurface_get_desc(srf->metadata.format); + const struct SVGA3dSurfaceDesc *desc = + vmw_surface_get_desc(srf->metadata.format); for (i = 0; i < srf->metadata.num_sizes; ++i) { SVGA3dCmdHeader *header = &cmd->header; @@ -323,8 +297,7 @@ static void vmw_surface_dma_encode(struct vmw_surface *srf, body->guest.ptr = *ptr; body->guest.ptr.offset += cur_offset->bo_offset; - body->guest.pitch = svga3dsurface_calculate_pitch(desc, - cur_size); + body->guest.pitch = vmw_surface_calculate_pitch(desc, cur_size); body->host.sid = srf->res.id; body->host.face = cur_offset->face; body->host.mipmap = cur_offset->mip; @@ -342,7 +315,7 @@ static void vmw_surface_dma_encode(struct vmw_surface *srf, suffix->suffixSize = sizeof(*suffix); suffix->maximumOffset = - svga3dsurface_get_image_buffer_size(desc, cur_size, + vmw_surface_get_image_buffer_size(desc, cur_size, body->guest.pitch); suffix->flags.discard = 0; suffix->flags.unsynchronized = 0; @@ -359,7 +332,7 @@ static void vmw_surface_dma_encode(struct vmw_surface *srf, * vmw_surface. * * Destroys a the device surface associated with a struct vmw_surface if - * any, and adjusts accounting and resource count accordingly. + * any, and adjusts resource count accordingly. */ static void vmw_hw_surface_destroy(struct vmw_resource *res) { @@ -388,7 +361,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) */ mutex_lock(&dev_priv->cmdbuf_mutex); - dev_priv->used_memory_size -= res->backup_size; + dev_priv->used_memory_size -= res->guest_memory_size; mutex_unlock(&dev_priv->cmdbuf_mutex); } } @@ -418,7 +391,7 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) return 0; srf = vmw_res_to_srf(res); - if (unlikely(dev_priv->used_memory_size + res->backup_size >= + if (unlikely(dev_priv->used_memory_size + res->guest_memory_size >= dev_priv->memory_size)) return -EBUSY; @@ -432,7 +405,7 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) goto out_no_id; } - if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) { + if (unlikely(res->id >= SVGA3D_HB_MAX_SURFACE_IDS)) { ret = -EBUSY; goto out_no_fifo; } @@ -456,7 +429,7 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) * Surface memory usage accounting. */ - dev_priv->used_memory_size += res->backup_size; + dev_priv->used_memory_size += res->guest_memory_size; return 0; out_no_fifo: @@ -533,7 +506,7 @@ static int vmw_legacy_srf_dma(struct vmw_resource *res, static int vmw_legacy_srf_bind(struct vmw_resource *res, struct ttm_validate_buffer *val_buf) { - if (!res->backup_dirty) + if (!res->guest_memory_dirty) return 0; return vmw_legacy_srf_dma(res, val_buf, true); @@ -592,7 +565,7 @@ static int vmw_legacy_srf_destroy(struct vmw_resource *res) * Surface memory usage accounting. */ - dev_priv->used_memory_size -= res->backup_size; + dev_priv->used_memory_size -= res->guest_memory_size; /* * Release the surface ID. @@ -666,17 +639,14 @@ static void vmw_user_surface_free(struct vmw_resource *res) struct vmw_surface *srf = vmw_res_to_srf(res); struct vmw_user_surface *user_srf = container_of(srf, struct vmw_user_surface, srf); - struct vmw_private *dev_priv = srf->res.dev_priv; - uint32_t size = user_srf->size; - WARN_ON_ONCE(res->dirty); + WARN_ON(res->dirty); if (user_srf->master) drm_master_put(&user_srf->master); kfree(srf->offsets); kfree(srf->metadata.sizes); kfree(srf->snooper.image); ttm_prime_object_kfree(user_srf, prime); - ttm_mem_global_free(vmw_mem_glob(dev_priv), size); } /** @@ -696,8 +666,13 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) struct vmw_resource *res = &user_srf->srf.res; *p_base = NULL; - if (user_srf->backup_base) - ttm_base_object_unref(&user_srf->backup_base); + + /* + * Dumb buffers own the resource and they'll unref the + * resource themselves + */ + WARN_ON(res && res->guest_memory_bo && res->guest_memory_bo->is_dumb); + vmw_resource_unreference(&res); } @@ -715,7 +690,7 @@ int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE); + return ttm_ref_object_base_unref(tfile, arg->sid); } /** @@ -740,22 +715,13 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, struct drm_vmw_surface_create_req *req = &arg->req; struct drm_vmw_surface_arg *rep = &arg->rep; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct ttm_operation_ctx ctx = { - .interruptible = true, - .no_wait_gpu = false - }; int ret; int i, j; uint32_t cur_bo_offset; struct drm_vmw_size *cur_size; struct vmw_surface_offset *cur_offset; uint32_t num_sizes; - uint32_t size; - const struct svga3d_surface_desc *desc; - - if (unlikely(vmw_user_surface_size == 0)) - vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + - VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; + const SVGA3dSurfaceDesc *desc; num_sizes = 0; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { @@ -768,29 +734,17 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, num_sizes == 0) return -EINVAL; - size = vmw_user_surface_size + - ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) + - ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset)); - - desc = svga3dsurface_get_desc(req->format); - if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { + desc = vmw_surface_get_desc(req->format); + if (unlikely(desc->blockDesc == SVGA3DBLOCKDESC_NONE)) { VMW_DEBUG_USER("Invalid format %d for surface creation.\n", req->format); return -EINVAL; } - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), - size, &ctx); - if (unlikely(ret != 0)) { - if (ret != -ERESTARTSYS) - DRM_ERROR("Out of graphics memory for surface.\n"); - goto out_unlock; - } - user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); if (unlikely(!user_srf)) { ret = -ENOMEM; - goto out_no_user_srf; + goto out_unlock; } srf = &user_srf->srf; @@ -805,11 +759,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, memcpy(metadata->mip_levels, req->mip_levels, sizeof(metadata->mip_levels)); metadata->num_sizes = num_sizes; - user_srf->size = size; metadata->sizes = - memdup_user((struct drm_vmw_size __user *)(unsigned long) + memdup_array_user((struct drm_vmw_size __user *)(unsigned long) req->size_addr, - sizeof(*metadata->sizes) * metadata->num_sizes); + metadata->num_sizes, sizeof(*metadata->sizes)); if (IS_ERR(metadata->sizes)) { ret = PTR_ERR(metadata->sizes); goto out_no_sizes; @@ -833,39 +786,28 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { for (j = 0; j < metadata->mip_levels[i]; ++j) { - uint32_t stride = svga3dsurface_calculate_pitch - (desc, cur_size); + uint32_t stride = vmw_surface_calculate_pitch( + desc, cur_size); cur_offset->face = i; cur_offset->mip = j; cur_offset->bo_offset = cur_bo_offset; - cur_bo_offset += svga3dsurface_get_image_buffer_size + cur_bo_offset += vmw_surface_get_image_buffer_size (desc, cur_size, stride); ++cur_offset; ++cur_size; } } - res->backup_size = cur_bo_offset; - if (metadata->scanout && - metadata->num_sizes == 1 && - metadata->sizes[0].width == 64 && - metadata->sizes[0].height == 64 && - metadata->format == SVGA3D_A8R8G8B8) { - - srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL); - if (!srf->snooper.image) { - DRM_ERROR("Failed to allocate cursor_image\n"); - ret = -ENOMEM; - goto out_no_copy; - } - } else { - srf->snooper.image = NULL; + res->guest_memory_size = cur_bo_offset; + + srf->snooper.image = vmw_cursor_snooper_create(file_priv, metadata); + if (IS_ERR(srf->snooper.image)) { + ret = PTR_ERR(srf->snooper.image); + goto out_no_copy; } - user_srf->prime.base.shareable = false; - user_srf->prime.base.tfile = NULL; if (drm_is_primary_client(file_priv)) - user_srf->master = drm_master_get(file_priv->master); + user_srf->master = drm_file_get_master(file_priv); /** * From this point, the generic resource management functions @@ -877,18 +819,25 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, goto out_unlock; /* - * A gb-aware client referencing a shared surface will - * expect a backup buffer to be present. + * A gb-aware client referencing a surface will expect a backup + * buffer to be present. */ - if (dev_priv->has_mob && req->shareable) { - uint32_t backup_handle; - - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - true, - &backup_handle, - &res->backup, - &user_srf->backup_base); + if (dev_priv->has_mob) { + struct vmw_bo_params params = { + .domain = VMW_BO_DOMAIN_SYS, + .busy_domain = VMW_BO_DOMAIN_SYS, + .bo_type = ttm_bo_type_device, + .size = res->guest_memory_size, + .pin = false + }; + + ret = vmw_bo_create(dev_priv, ¶ms, &res->guest_memory_bo); + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + + ret = vmw_bo_add_detached_resource(res->guest_memory_bo, res); if (unlikely(ret != 0)) { vmw_resource_unreference(&res); goto out_unlock; @@ -896,9 +845,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, } tmp = vmw_resource_reference(&srf->res); - ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, - req->shareable, VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); + ret = ttm_prime_object_init(tfile, res->guest_memory_size, + &user_srf->prime, + VMW_RES_SURFACE, + &vmw_user_surface_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); @@ -916,12 +866,117 @@ out_no_offsets: kfree(metadata->sizes); out_no_sizes: ttm_prime_object_kfree(user_srf, prime); -out_no_user_srf: - ttm_mem_global_free(vmw_mem_glob(dev_priv), size); out_unlock: return ret; } +static struct vmw_user_surface * +vmw_lookup_user_surface_for_buffer(struct vmw_private *vmw, struct vmw_bo *bo, + u32 handle) +{ + struct vmw_user_surface *user_srf = NULL; + struct vmw_surface *surf; + struct ttm_base_object *base; + + surf = vmw_bo_surface(bo); + if (surf) { + rcu_read_lock(); + user_srf = container_of(surf, struct vmw_user_surface, srf); + base = &user_srf->prime.base; + if (base && !kref_get_unless_zero(&base->refcount)) { + drm_dbg_driver(&vmw->drm, + "%s: referencing a stale surface handle %d\n", + __func__, handle); + base = NULL; + user_srf = NULL; + } + rcu_read_unlock(); + } + + return user_srf; +} + +struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw, + struct vmw_bo *bo, + u32 handle) +{ + struct vmw_user_surface *user_srf = + vmw_lookup_user_surface_for_buffer(vmw, bo, handle); + struct vmw_surface *surf = NULL; + struct ttm_base_object *base; + + if (user_srf) { + surf = vmw_surface_reference(&user_srf->srf); + base = &user_srf->prime.base; + ttm_base_object_unref(&base); + } + return surf; +} + +u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw, + struct vmw_bo *bo, + u32 handle) +{ + struct vmw_user_surface *user_srf = + vmw_lookup_user_surface_for_buffer(vmw, bo, handle); + int surf_handle = 0; + struct ttm_base_object *base; + + if (user_srf) { + base = &user_srf->prime.base; + surf_handle = (u32)base->handle; + ttm_base_object_unref(&base); + } + return surf_handle; +} + +static int vmw_buffer_prime_to_surface_base(struct vmw_private *dev_priv, + struct drm_file *file_priv, + u32 fd, u32 *handle, + struct ttm_base_object **base_p) +{ + struct ttm_base_object *base; + struct vmw_bo *bo; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_user_surface *user_srf; + int ret; + + ret = drm_gem_prime_fd_to_handle(&dev_priv->drm, file_priv, fd, handle); + if (ret) { + drm_warn(&dev_priv->drm, + "Wasn't able to find user buffer for fd = %u.\n", fd); + return ret; + } + + ret = vmw_user_bo_lookup(file_priv, *handle, &bo); + if (ret) { + drm_warn(&dev_priv->drm, + "Wasn't able to lookup user buffer for handle = %u.\n", *handle); + return ret; + } + + user_srf = vmw_lookup_user_surface_for_buffer(dev_priv, bo, *handle); + if (WARN_ON(!user_srf)) { + drm_warn(&dev_priv->drm, + "User surface fd %d (handle %d) is null.\n", fd, *handle); + ret = -EINVAL; + goto out; + } + + base = &user_srf->prime.base; + ret = ttm_ref_object_add(tfile, base, NULL, false); + if (ret) { + drm_warn(&dev_priv->drm, + "Couldn't add an object ref for the buffer (%d).\n", *handle); + goto out; + } + + *base_p = base; +out: + vmw_user_bo_unref(&bo); + + return ret; +} static int vmw_surface_handle_reference(struct vmw_private *dev_priv, @@ -931,15 +986,19 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, struct ttm_base_object **base_p) { struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_user_surface *user_srf; + struct vmw_user_surface *user_srf = NULL; uint32_t handle; struct ttm_base_object *base; int ret; if (handle_type == DRM_VMW_HANDLE_PRIME) { ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); - if (unlikely(ret != 0)) - return ret; + if (ret) + return vmw_buffer_prime_to_surface_base(dev_priv, + file_priv, + u_handle, + &handle, + base_p); } else { handle = u_handle; } @@ -955,7 +1014,6 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, VMW_DEBUG_USER("Referenced object is not a surface.\n"); goto out_bad_resource; } - if (handle_type != DRM_VMW_HANDLE_PRIME) { bool require_exist = false; @@ -980,8 +1038,7 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, if (unlikely(drm_is_render_client(file_priv))) require_exist = true; - ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, - require_exist); + ret = ttm_ref_object_add(tfile, base, NULL, require_exist); if (unlikely(ret != 0)) { DRM_ERROR("Could not add a reference to a surface.\n"); goto out_bad_resource; @@ -995,7 +1052,7 @@ out_bad_resource: ttm_base_object_unref(&base); out_no_lookup: if (handle_type == DRM_VMW_HANDLE_PRIME) - (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); + (void) ttm_ref_object_base_unref(tfile, handle); return ret; } @@ -1045,7 +1102,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) { VMW_DEBUG_USER("copy_to_user failed %p %u\n", user_sizes, srf->metadata.num_sizes); - ttm_ref_object_base_unref(tfile, base->handle, TTM_REF_USAGE); + ttm_ref_object_base_unref(tfile, base->handle); ret = -EFAULT; } @@ -1214,7 +1271,7 @@ static int vmw_gb_surface_bind(struct vmw_resource *res, BUG_ON(bo->resource->mem_type != VMW_PL_MOB); - submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0); + submit_size = sizeof(*cmd1) + (res->guest_memory_dirty ? sizeof(*cmd2) : 0); cmd1 = VMW_CMD_RESERVE(dev_priv, submit_size); if (unlikely(!cmd1)) @@ -1224,7 +1281,7 @@ static int vmw_gb_surface_bind(struct vmw_resource *res, cmd1->header.size = sizeof(cmd1->body); cmd1->body.sid = res->id; cmd1->body.mobid = bo->resource->start; - if (res->backup_dirty) { + if (res->guest_memory_dirty) { cmd2 = (void *) &cmd1[1]; cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE; cmd2->header.size = sizeof(cmd2->body); @@ -1232,12 +1289,12 @@ static int vmw_gb_surface_bind(struct vmw_resource *res, } vmw_cmd_commit(dev_priv, submit_size); - if (res->backup->dirty && res->backup_dirty) { + if (res->guest_memory_bo->dirty && res->guest_memory_dirty) { /* We've just made a full upload. Cear dirty regions. */ vmw_bo_dirty_clear_res(res); } - res->backup_dirty = false; + res->guest_memory_dirty = false; return 0; } @@ -1459,7 +1516,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, struct vmw_resource *res; struct vmw_resource *tmp; int ret = 0; - uint32_t size; uint32_t backup_handle = 0; SVGA3dSurfaceAllFlags svga3d_flags_64 = SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, @@ -1506,12 +1562,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, return -EINVAL; } - if (unlikely(vmw_user_surface_size == 0)) - vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + - VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; - - size = vmw_user_surface_size; - metadata.flags = svga3d_flags_64; metadata.format = req->base.format; metadata.mip_levels[0] = req->base.mip_levels; @@ -1526,7 +1576,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev, drm_vmw_surface_flag_scanout; /* Define a surface based on the parameters. */ - ret = vmw_gb_surface_define(dev_priv, size, &metadata, &srf); + ret = vmw_gb_surface_define(dev_priv, &metadata, &srf); if (ret != 0) { VMW_DEBUG_USER("Failed to define surface.\n"); return ret; @@ -1534,18 +1584,22 @@ vmw_gb_surface_define_internal(struct drm_device *dev, user_srf = container_of(srf, struct vmw_user_surface, srf); if (drm_is_primary_client(file_priv)) - user_srf->master = drm_master_get(file_priv->master); + user_srf->master = drm_file_get_master(file_priv); res = &user_srf->srf.res; if (req->base.buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_lookup(file_priv, req->base.buffer_handle, + &res->guest_memory_bo); if (ret == 0) { - if (res->backup->base.base.size < res->backup_size) { + if (res->guest_memory_bo->is_dumb) { + VMW_DEBUG_USER("Can't backup surface with a dumb buffer.\n"); + vmw_user_bo_unref(&res->guest_memory_bo); + ret = -EINVAL; + goto out_unlock; + } else if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) { VMW_DEBUG_USER("Surface backup buffer too small.\n"); - vmw_bo_unreference(&res->backup); + vmw_user_bo_unref(&res->guest_memory_bo); ret = -EINVAL; goto out_unlock; } else { @@ -1554,14 +1608,12 @@ vmw_gb_surface_define_internal(struct drm_device *dev, } } else if (req->base.drm_surface_flags & (drm_vmw_surface_flag_create_buffer | - drm_vmw_surface_flag_coherent)) - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - req->base.drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); + drm_vmw_surface_flag_coherent)) { + ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, + res->guest_memory_size, + &backup_handle, + &res->guest_memory_bo); + } if (unlikely(ret != 0)) { vmw_resource_unreference(&res); @@ -1569,9 +1621,9 @@ vmw_gb_surface_define_internal(struct drm_device *dev, } if (req->base.drm_surface_flags & drm_vmw_surface_flag_coherent) { - struct vmw_buffer_object *backup = res->backup; + struct vmw_bo *backup = res->guest_memory_bo; - ttm_bo_reserve(&backup->base, false, false, NULL); + ttm_bo_reserve(&backup->tbo, false, false, NULL); if (!res->func->dirty_alloc) ret = -EINVAL; if (!ret) @@ -1580,7 +1632,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev, res->coherent = true; ret = res->func->dirty_alloc(res); } - ttm_bo_unreserve(&backup->base); + ttm_bo_unreserve(&backup->tbo); if (ret) { vmw_resource_unreference(&res); goto out_unlock; @@ -1588,12 +1640,18 @@ vmw_gb_surface_define_internal(struct drm_device *dev, } + if (res->guest_memory_bo) { + ret = vmw_bo_add_detached_resource(res->guest_memory_bo, res); + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + } + tmp = vmw_resource_reference(res); - ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, - req->base.drm_surface_flags & - drm_vmw_surface_flag_shareable, + ret = ttm_prime_object_init(tfile, res->guest_memory_size, &user_srf->prime, VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); + &vmw_user_surface_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); @@ -1602,18 +1660,17 @@ vmw_gb_surface_define_internal(struct drm_device *dev, } rep->handle = user_srf->prime.base.handle; - rep->backup_size = res->backup_size; - if (res->backup) { + rep->backup_size = res->guest_memory_size; + if (res->guest_memory_bo) { rep->buffer_map_handle = - drm_vma_node_offset_addr(&res->backup->base.base.vma_node); - rep->buffer_size = res->backup->base.base.size; + drm_vma_node_offset_addr(&res->guest_memory_bo->tbo.base.vma_node); + rep->buffer_size = res->guest_memory_bo->tbo.base.size; rep->buffer_handle = backup_handle; } else { rep->buffer_map_handle = 0; rep->buffer_size = 0; rep->buffer_handle = SVGA3D_INVALID_ID; } - vmw_resource_unreference(&res); out_unlock: @@ -1636,12 +1693,11 @@ vmw_gb_surface_reference_internal(struct drm_device *dev, struct drm_file *file_priv) { struct vmw_private *dev_priv = vmw_priv(dev); - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_surface *srf; struct vmw_user_surface *user_srf; struct vmw_surface_metadata *metadata; struct ttm_base_object *base; - uint32_t backup_handle; + u32 backup_handle; int ret; ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, @@ -1651,21 +1707,19 @@ vmw_gb_surface_reference_internal(struct drm_device *dev, user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; - if (!srf->res.backup) { + if (!srf->res.guest_memory_bo) { DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); goto out_bad_resource; } metadata = &srf->metadata; mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); + ret = drm_gem_handle_create(file_priv, &srf->res.guest_memory_bo->tbo.base, + &backup_handle); mutex_unlock(&dev_priv->cmdbuf_mutex); - - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a GB surface " - "backup buffer.\n"); - (void) ttm_ref_object_base_unref(tfile, base->handle, - TTM_REF_USAGE); + if (ret != 0) { + drm_err(dev, "Wasn't able to create a backing handle for surface sid = %u.\n", + req->sid); goto out_bad_resource; } @@ -1679,11 +1733,11 @@ vmw_gb_surface_reference_internal(struct drm_device *dev, rep->creq.base.buffer_handle = backup_handle; rep->creq.base.base_size = metadata->base_size; rep->crep.handle = user_srf->prime.base.handle; - rep->crep.backup_size = srf->res.backup_size; + rep->crep.backup_size = srf->res.guest_memory_size; rep->crep.buffer_handle = backup_handle; rep->crep.buffer_map_handle = - drm_vma_node_offset_addr(&srf->res.backup->base.base.vma_node); - rep->crep.buffer_size = srf->res.backup->base.base.size; + drm_vma_node_offset_addr(&srf->res.guest_memory_bo->tbo.base.vma_node); + rep->crep.buffer_size = srf->res.guest_memory_bo->tbo.base.size; rep->creq.version = drm_vmw_gb_surface_v1; rep->creq.svga3d_flags_upper_32_bits = @@ -1711,10 +1765,10 @@ out_bad_resource: * than partial z slices are dirtied. */ static void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty, - const struct svga3dsurface_loc *loc_start, - const struct svga3dsurface_loc *loc_end) + const struct vmw_surface_loc *loc_start, + const struct vmw_surface_loc *loc_end) { - const struct svga3dsurface_cache *cache = &dirty->cache; + const struct vmw_surface_cache *cache = &dirty->cache; SVGA3dBox *box = &dirty->boxes[loc_start->sub_resource]; u32 mip = loc_start->sub_resource % cache->num_mip_levels; const struct drm_vmw_size *size = &cache->mip[mip].size; @@ -1760,7 +1814,7 @@ static void vmw_subres_dirty_add(struct vmw_surface_dirty *dirty, */ static void vmw_subres_dirty_full(struct vmw_surface_dirty *dirty, u32 subres) { - const struct svga3dsurface_cache *cache = &dirty->cache; + const struct vmw_surface_cache *cache = &dirty->cache; u32 mip = subres % cache->num_mip_levels; const struct drm_vmw_size *size = &cache->mip[mip].size; SVGA3dBox *box = &dirty->boxes[subres]; @@ -1782,16 +1836,16 @@ static void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, { struct vmw_surface_dirty *dirty = (struct vmw_surface_dirty *) res->dirty; - size_t backup_end = res->backup_offset + res->backup_size; - struct svga3dsurface_loc loc1, loc2; - const struct svga3dsurface_cache *cache; + size_t backup_end = res->guest_memory_offset + res->guest_memory_size; + struct vmw_surface_loc loc1, loc2; + const struct vmw_surface_cache *cache; - start = max_t(size_t, start, res->backup_offset) - res->backup_offset; - end = min(end, backup_end) - res->backup_offset; + start = max_t(size_t, start, res->guest_memory_offset) - res->guest_memory_offset; + end = min(end, backup_end) - res->guest_memory_offset; cache = &dirty->cache; - svga3dsurface_get_loc(cache, &loc1, start); - svga3dsurface_get_loc(cache, &loc2, end - 1); - svga3dsurface_inc_loc(cache, &loc2); + vmw_surface_get_loc(cache, &loc1, start); + vmw_surface_get_loc(cache, &loc2, end - 1); + vmw_surface_inc_loc(cache, &loc2); if (loc1.sheet != loc2.sheet) { u32 sub_res; @@ -1811,12 +1865,12 @@ static void vmw_surface_tex_dirty_range_add(struct vmw_resource *res, vmw_subres_dirty_add(dirty, &loc1, &loc2); } else { /* Dirty range covers multiple sub-resources */ - struct svga3dsurface_loc loc_min, loc_max; + struct vmw_surface_loc loc_min, loc_max; u32 sub_res; - svga3dsurface_max_loc(cache, loc1.sub_resource, &loc_max); + vmw_surface_max_loc(cache, loc1.sub_resource, &loc_max); vmw_subres_dirty_add(dirty, &loc1, &loc_max); - svga3dsurface_min_loc(cache, loc2.sub_resource - 1, &loc_min); + vmw_surface_min_loc(cache, loc2.sub_resource - 1, &loc_min); vmw_subres_dirty_add(dirty, &loc_min, &loc2); for (sub_res = loc1.sub_resource + 1; sub_res < loc2.sub_resource - 1; ++sub_res) @@ -1833,14 +1887,14 @@ static void vmw_surface_buf_dirty_range_add(struct vmw_resource *res, { struct vmw_surface_dirty *dirty = (struct vmw_surface_dirty *) res->dirty; - const struct svga3dsurface_cache *cache = &dirty->cache; - size_t backup_end = res->backup_offset + cache->mip_chain_bytes; + const struct vmw_surface_cache *cache = &dirty->cache; + size_t backup_end = res->guest_memory_offset + cache->mip_chain_bytes; SVGA3dBox *box = &dirty->boxes[0]; u32 box_c2; box->h = box->d = 1; - start = max_t(size_t, start, res->backup_offset) - res->backup_offset; - end = min(end, backup_end) - res->backup_offset; + start = max_t(size_t, start, res->guest_memory_offset) - res->guest_memory_offset; + end = min(end, backup_end) - res->guest_memory_offset; box_c2 = box->x + box->w; if (box->w == 0 || box->x > start) box->x = start; @@ -1856,8 +1910,8 @@ static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, { struct vmw_surface *srf = vmw_res_to_srf(res); - if (WARN_ON(end <= res->backup_offset || - start >= res->backup_offset + res->backup_size)) + if (WARN_ON(end <= res->guest_memory_offset || + start >= res->guest_memory_offset + res->guest_memory_size)) return; if (srf->metadata.format == SVGA3D_BUFFER) @@ -1872,12 +1926,11 @@ static void vmw_surface_dirty_range_add(struct vmw_resource *res, size_t start, static int vmw_surface_dirty_sync(struct vmw_resource *res) { struct vmw_private *dev_priv = res->dev_priv; - bool has_dx = 0; u32 i, num_dirty; struct vmw_surface_dirty *dirty = (struct vmw_surface_dirty *) res->dirty; size_t alloc_size; - const struct svga3dsurface_cache *cache = &dirty->cache; + const struct vmw_surface_cache *cache = &dirty->cache; struct { SVGA3dCmdHeader header; SVGA3dCmdDXUpdateSubResource body; @@ -1899,7 +1952,7 @@ static int vmw_surface_dirty_sync(struct vmw_resource *res) if (!num_dirty) goto out; - alloc_size = num_dirty * ((has_dx) ? sizeof(*cmd1) : sizeof(*cmd2)); + alloc_size = num_dirty * ((has_sm4_context(dev_priv)) ? sizeof(*cmd1) : sizeof(*cmd2)); cmd = VMW_CMD_RESERVE(dev_priv, alloc_size); if (!cmd) return -ENOMEM; @@ -1917,7 +1970,7 @@ static int vmw_surface_dirty_sync(struct vmw_resource *res) * DX_UPDATE_SUBRESOURCE is aware of array surfaces. * UPDATE_GB_IMAGE is not. */ - if (has_dx) { + if (has_sm4_context(dev_priv)) { cmd1->header.id = SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE; cmd1->header.size = sizeof(cmd1->body); cmd1->body.sid = res->id; @@ -1956,11 +2009,7 @@ static int vmw_surface_dirty_alloc(struct vmw_resource *res) u32 num_mip; u32 num_subres; u32 num_samples; - size_t dirty_size, acc_size; - static struct ttm_operation_ctx ctx = { - .interruptible = false, - .no_wait_gpu = false - }; + size_t dirty_size; int ret; if (metadata->array_size) @@ -1974,14 +2023,6 @@ static int vmw_surface_dirty_alloc(struct vmw_resource *res) num_subres = num_layers * num_mip; dirty_size = struct_size(dirty, boxes, num_subres); - acc_size = ttm_round_pot(dirty_size); - ret = ttm_mem_global_alloc(vmw_mem_glob(res->dev_priv), - acc_size, &ctx); - if (ret) { - VMW_DEBUG_USER("Out of graphics memory for surface " - "dirty tracker.\n"); - return ret; - } dirty = kvzalloc(dirty_size, GFP_KERNEL); if (!dirty) { @@ -1990,14 +2031,13 @@ static int vmw_surface_dirty_alloc(struct vmw_resource *res) } num_samples = max_t(u32, 1, metadata->multisample_count); - ret = svga3dsurface_setup_cache(&metadata->base_size, metadata->format, - num_mip, num_layers, num_samples, - &dirty->cache); + ret = vmw_surface_setup_cache(&metadata->base_size, metadata->format, + num_mip, num_layers, num_samples, + &dirty->cache); if (ret) goto out_no_cache; dirty->num_subres = num_subres; - dirty->size = acc_size; res->dirty = (struct vmw_resource_dirty *) dirty; return 0; @@ -2005,7 +2045,6 @@ static int vmw_surface_dirty_alloc(struct vmw_resource *res) out_no_cache: kvfree(dirty); out_no_dirty: - ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); return ret; } @@ -2016,10 +2055,8 @@ static void vmw_surface_dirty_free(struct vmw_resource *res) { struct vmw_surface_dirty *dirty = (struct vmw_surface_dirty *) res->dirty; - size_t acc_size = dirty->size; kvfree(dirty); - ttm_mem_global_free(vmw_mem_glob(res->dev_priv), acc_size); res->dirty = NULL; } @@ -2052,8 +2089,6 @@ static int vmw_surface_clean(struct vmw_resource *res) * vmw_gb_surface_define - Define a private GB surface * * @dev_priv: Pointer to a device private. - * @user_accounting_size: Used to track user-space memory usage, set - * to 0 for kernel mode only memory * @metadata: Metadata representing the surface to create. * @user_srf_out: allocated user_srf. Set to NULL on failure. * @@ -2063,17 +2098,12 @@ static int vmw_surface_clean(struct vmw_resource *res) * it available to user mode drivers. */ int vmw_gb_surface_define(struct vmw_private *dev_priv, - uint32_t user_accounting_size, const struct vmw_surface_metadata *req, struct vmw_surface **srf_out) { struct vmw_surface_metadata *metadata; struct vmw_user_surface *user_srf; struct vmw_surface *srf; - struct ttm_operation_ctx ctx = { - .interruptible = true, - .no_wait_gpu = false - }; u32 sample_count = 1; u32 num_layers = 1; int ret; @@ -2081,7 +2111,7 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, *srf_out = NULL; if (req->scanout) { - if (!svga3dsurface_is_screen_target_format(req->format)) { + if (!vmw_surface_is_screen_target_format(req->format)) { VMW_DEBUG_USER("Invalid Screen Target surface format."); return -EINVAL; } @@ -2096,10 +2126,10 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, return -EINVAL; } } else { - const struct svga3d_surface_desc *desc = - svga3dsurface_get_desc(req->format); + const SVGA3dSurfaceDesc *desc = + vmw_surface_get_desc(req->format); - if (desc->block_desc == SVGA3DBLOCKDESC_NONE) { + if (desc->blockDesc == SVGA3DBLOCKDESC_NONE) { VMW_DEBUG_USER("Invalid surface format.\n"); return -EINVAL; } @@ -2114,24 +2144,13 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, if (req->sizes != NULL) return -EINVAL; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), - user_accounting_size, &ctx); - if (ret != 0) { - if (ret != -ERESTARTSYS) - DRM_ERROR("Out of graphics memory for surface.\n"); - goto out_unlock; - } - user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); if (unlikely(!user_srf)) { ret = -ENOMEM; - goto out_no_user_srf; + goto out_unlock; } *srf_out = &user_srf->srf; - user_srf->size = user_accounting_size; - user_srf->prime.base.shareable = false; - user_srf->prime.base.tfile = NULL; srf = &user_srf->srf; srf->metadata = *req; @@ -2147,15 +2166,16 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, if (metadata->flags & SVGA3D_SURFACE_MULTISAMPLE) sample_count = metadata->multisample_count; - srf->res.backup_size = - svga3dsurface_get_serialized_size_extended(metadata->format, - metadata->base_size, - metadata->mip_levels[0], - num_layers, - sample_count); + srf->res.guest_memory_size = + vmw_surface_get_serialized_size_extended( + metadata->format, + metadata->base_size, + metadata->mip_levels[0], + num_layers, + sample_count); if (metadata->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) - srf->res.backup_size += sizeof(SVGA3dDXSOState); + srf->res.guest_memory_size += sizeof(SVGA3dDXSOState); /* * Don't set SVGA3D_SURFACE_SCREENTARGET flag for a scanout surface with @@ -2179,9 +2199,141 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv, return ret; -out_no_user_srf: - ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size); - out_unlock: return ret; } + +static SVGA3dSurfaceFormat vmw_format_bpp_to_svga(struct vmw_private *vmw, + int bpp) +{ + switch (bpp) { + case 8: /* DRM_FORMAT_C8 */ + return SVGA3D_P8; + case 16: /* DRM_FORMAT_RGB565 */ + return SVGA3D_R5G6B5; + case 32: /* DRM_FORMAT_XRGB8888 */ + if (has_sm4_context(vmw)) + return SVGA3D_B8G8R8X8_UNORM; + return SVGA3D_X8R8G8B8; + default: + drm_warn(&vmw->drm, "Unsupported format bpp: %d\n", bpp); + return SVGA3D_X8R8G8B8; + } +} + +/** + * vmw_dumb_create - Create a dumb kms buffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @args: Pointer to a struct drm_mode_create_dumb structure + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm create_dumb functionality. + * Note that this is very similar to the vmw_bo_alloc ioctl, except + * that the arguments have a different format. + */ +int vmw_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_bo *vbo = NULL; + struct vmw_resource *res = NULL; + union drm_vmw_gb_surface_create_ext_arg arg = { 0 }; + struct drm_vmw_gb_surface_create_ext_req *req = &arg.req; + int ret; + struct drm_vmw_size drm_size = { + .width = args->width, + .height = args->height, + .depth = 1, + }; + SVGA3dSurfaceFormat format = vmw_format_bpp_to_svga(dev_priv, args->bpp); + const struct SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format); + SVGA3dSurfaceAllFlags flags = SVGA3D_SURFACE_HINT_TEXTURE | + SVGA3D_SURFACE_HINT_RENDERTARGET | + SVGA3D_SURFACE_SCREENTARGET; + + if (vmw_surface_is_dx_screen_target_format(format)) { + flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE | + SVGA3D_SURFACE_BIND_RENDER_TARGET; + } + + /* + * Without mob support we're just going to use raw memory buffer + * because we wouldn't be able to support full surface coherency + * without mobs. There also no reason to support surface coherency + * without 3d (i.e. gpu usage on the host) because then all the + * contents is going to be rendered guest side. + */ + if (!dev_priv->has_mob || !vmw_supports_3d(dev_priv)) { + ret = drm_mode_size_dumb(dev, args, 0, 0); + if (ret) + return ret; + + ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, + args->size, &args->handle, + &vbo); + /* drop reference from allocate - handle holds it now */ + drm_gem_object_put(&vbo->tbo.base); + return ret; + } + + req->version = drm_vmw_gb_surface_v1; + req->multisample_pattern = SVGA3D_MS_PATTERN_NONE; + req->quality_level = SVGA3D_MS_QUALITY_NONE; + req->buffer_byte_stride = 0; + req->must_be_zero = 0; + req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags); + req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags); + req->base.format = (uint32_t)format; + req->base.drm_surface_flags = drm_vmw_surface_flag_scanout; + req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable; + req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer; + req->base.drm_surface_flags |= drm_vmw_surface_flag_coherent; + req->base.base_size.width = args->width; + req->base.base_size.height = args->height; + req->base.base_size.depth = 1; + req->base.array_size = 0; + req->base.mip_levels = 1; + req->base.multisample_count = 0; + req->base.buffer_handle = SVGA3D_INVALID_ID; + req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE; + ret = vmw_gb_surface_define_ext_ioctl(dev, &arg, file_priv); + if (ret) { + drm_warn(dev, "Unable to create a dumb buffer\n"); + return ret; + } + + args->handle = arg.rep.buffer_handle; + args->size = arg.rep.buffer_size; + args->pitch = vmw_surface_calculate_pitch(desc, &drm_size); + + ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg.rep.handle, + user_surface_converter, + &res); + if (ret) { + drm_err(dev, "Created resource handle doesn't exist!\n"); + goto err; + } + + vbo = res->guest_memory_bo; + vbo->is_dumb = true; + vbo->dumb_surface = vmw_res_to_srf(res); + drm_gem_object_put(&vbo->tbo.base); + /* + * Unset the user surface dtor since this in not actually exposed + * to userspace. The suface is owned via the dumb_buffer's GEM handle + */ + struct vmw_user_surface *usurf = container_of(vbo->dumb_surface, + struct vmw_user_surface, srf); + usurf->prime.base.refcount_release = NULL; +err: + if (res) + vmw_resource_unreference(&res); + + ttm_ref_object_base_unref(tfile, arg.rep.handle); + + return ret; +} |
