diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_surface.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 468 |
1 files changed, 302 insertions, 166 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index a5f93f62c7fa..1d4c010a0e48 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -33,6 +33,10 @@ #include "vmwgfx_binding.h" #include "device_include/svga3d_surfacedefs.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 @@ -81,7 +85,16 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, bool readback, struct ttm_validate_buffer *val_buf); static int vmw_gb_surface_destroy(struct vmw_resource *res); - +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv); +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + struct drm_file *file_priv); static const struct vmw_user_resource_conv user_surface_conv = { .object_type = VMW_RES_SURFACE, @@ -1289,193 +1302,55 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) /** * vmw_gb_surface_define_ioctl - Ioctl function implementing - * the user surface define functionality. + * the user surface define functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_user_surface *user_srf; - struct vmw_surface *srf; - struct vmw_resource *res; - struct vmw_resource *tmp; union drm_vmw_gb_surface_create_arg *arg = (union drm_vmw_gb_surface_create_arg *)data; - struct drm_vmw_gb_surface_create_req *req = &arg->req; struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - int ret; - uint32_t size; - uint32_t backup_handle = 0; - - if (req->multisample_count != 0) - return -EINVAL; - - if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS) - return -EINVAL; - - if (unlikely(vmw_user_surface_size == 0)) - vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + - 128; - - size = vmw_user_surface_size + 128; - - /* Define a surface based on the parameters. */ - ret = vmw_surface_gb_priv_define(dev, - size, - (SVGA3dSurfaceAllFlags)req->svga3d_flags, - req->format, - req->drm_surface_flags & drm_vmw_surface_flag_scanout, - req->mip_levels, - req->multisample_count, - req->array_size, - req->base_size, - &srf); - if (unlikely(ret != 0)) - return ret; - - 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); - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - res = &user_srf->srf.res; - - - if (req->buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_bo_lookup(tfile, req->buffer_handle, - &res->backup, - &user_srf->backup_base); - if (ret == 0) { - if (res->backup->base.num_pages * PAGE_SIZE < - res->backup_size) { - DRM_ERROR("Surface backup buffer is too small.\n"); - vmw_bo_unreference(&res->backup); - ret = -EINVAL; - goto out_unlock; - } else { - backup_handle = req->buffer_handle; - } - } - } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); - - 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->drm_surface_flags & - drm_vmw_surface_flag_shareable, - VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); - - if (unlikely(ret != 0)) { - vmw_resource_unreference(&tmp); - vmw_resource_unreference(&res); - goto out_unlock; - } - - rep->handle = user_srf->prime.base.hash.key; - rep->backup_size = res->backup_size; - if (res->backup) { - rep->buffer_map_handle = - drm_vma_node_offset_addr(&res->backup->base.vma_node); - rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; - rep->buffer_handle = backup_handle; - } else { - rep->buffer_map_handle = 0; - rep->buffer_size = 0; - rep->buffer_handle = SVGA3D_INVALID_ID; - } + struct drm_vmw_gb_surface_create_ext_req req_ext; - vmw_resource_unreference(&res); + req_ext.base = arg->req; + req_ext.version = drm_vmw_gb_surface_v1; + req_ext.svga3d_flags_upper_32_bits = 0; + req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; + req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; + req_ext.must_be_zero = 0; -out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; + return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); } /** * vmw_gb_surface_reference_ioctl - Ioctl function implementing - * the user surface reference functionality. + * the user surface reference functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_gb_surface_reference_arg *arg = (union drm_vmw_gb_surface_reference_arg *)data; struct drm_vmw_surface_arg *req = &arg->req; struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_surface *srf; - struct vmw_user_surface *user_srf; - struct ttm_base_object *base; - uint32_t backup_handle; - int ret = -EINVAL; + struct drm_vmw_gb_surface_ref_ext_rep rep_ext; + int ret; + + ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); - ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, - req->handle_type, &base); if (unlikely(ret != 0)) return ret; - user_srf = container_of(base, struct vmw_user_surface, prime.base); - srf = &user_srf->srf; - if (!srf->res.backup) { - DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); - goto out_bad_resource; - } - - mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_bo_reference(tfile, srf->res.backup, &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->hash.key, - TTM_REF_USAGE); - goto out_bad_resource; - } - - rep->creq.svga3d_flags = (uint32_t)srf->flags; - rep->creq.format = srf->format; - rep->creq.mip_levels = srf->mip_levels[0]; - rep->creq.drm_surface_flags = 0; - rep->creq.multisample_count = srf->multisample_count; - rep->creq.autogen_filter = srf->autogen_filter; - rep->creq.array_size = srf->array_size; - rep->creq.buffer_handle = backup_handle; - rep->creq.base_size = srf->base_size; - rep->crep.handle = user_srf->prime.base.hash.key; - rep->crep.backup_size = srf->res.backup_size; - rep->crep.buffer_handle = backup_handle; - rep->crep.buffer_map_handle = - drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); - rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; - -out_bad_resource: - ttm_base_object_unref(&base); + rep->creq = rep_ext.creq.base; + rep->crep = rep_ext.crep; return ret; } @@ -1493,6 +1368,8 @@ out_bad_resource: * @multisample_count: * @array_size: Surface array size. * @size: width, heigh, depth of the surface requested + * @multisample_pattern: Multisampling pattern when msaa is supported + * @quality_level: Precision settings * @user_srf_out: allocated user_srf. Set to NULL on failure. * * GB surfaces allocated by this function will not have a user mode handle, and @@ -1509,6 +1386,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t multisample_count, uint32_t array_size, struct drm_vmw_size size, + SVGA3dMSPattern multisample_pattern, + SVGA3dMSQualityLevel quality_level, struct vmw_surface **srf_out) { struct vmw_private *dev_priv = vmw_priv(dev); @@ -1519,7 +1398,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, }; struct vmw_surface *srf; int ret; - u32 num_layers; + u32 num_layers = 1; *srf_out = NULL; @@ -1594,15 +1473,13 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->array_size = array_size; srf->multisample_count = multisample_count; - srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; - srf->quality_level = SVGA3D_MS_QUALITY_NONE; + srf->multisample_pattern = multisample_pattern; + srf->quality_level = quality_level; if (array_size) num_layers = array_size; else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) num_layers = SVGA3D_MAX_SURFACE_FACES; - else - num_layers = 1; srf->res.backup_size = svga3dsurface_get_serialized_size(srf->format, @@ -1633,3 +1510,262 @@ out_unlock: ttm_read_unlock(&dev_priv->reservation_sem); return ret; } + +/** + * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_create_ext_arg *arg = + (union drm_vmw_gb_surface_create_ext_arg *)data; + struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; + struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; + + return vmw_gb_surface_define_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_reference_ext_arg *arg = + (union drm_vmw_gb_surface_reference_ext_arg *)data; + struct drm_vmw_surface_arg *req = &arg->req; + struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; + + return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_define_internal - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Request argument from user-space. + * @rep: Response argument to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_user_surface *user_srf; + struct vmw_surface *srf; + struct vmw_resource *res; + struct vmw_resource *tmp; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + int ret; + uint32_t size; + uint32_t backup_handle = 0; + SVGA3dSurfaceAllFlags svga3d_flags_64 = + SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, + req->base.svga3d_flags); + + if (!dev_priv->has_sm4_1) { + /* + * If SM4_1 is not support then cannot send 64-bit flag to + * device. + */ + if (req->svga3d_flags_upper_32_bits != 0) + return -EINVAL; + + if (req->base.multisample_count != 0) + return -EINVAL; + + if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) + return -EINVAL; + + if (req->quality_level != SVGA3D_MS_QUALITY_NONE) + return -EINVAL; + } + + if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) + return -EINVAL; + + if (unlikely(vmw_user_surface_size == 0)) + vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + + 128; + + size = vmw_user_surface_size + 128; + + /* Define a surface based on the parameters. */ + ret = vmw_surface_gb_priv_define(dev, + size, + svga3d_flags_64, + req->base.format, + req->base.drm_surface_flags & + drm_vmw_surface_flag_scanout, + req->base.mip_levels, + req->base.multisample_count, + req->base.array_size, + req->base.base_size, + req->multisample_pattern, + req->quality_level, + &srf); + if (unlikely(ret != 0)) + return ret; + + 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); + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + 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); + if (ret == 0) { + if (res->backup->base.num_pages * PAGE_SIZE < + res->backup_size) { + DRM_ERROR("Surface backup buffer too small.\n"); + vmw_bo_unreference(&res->backup); + ret = -EINVAL; + goto out_unlock; + } else { + backup_handle = req->base.buffer_handle; + } + } + } else if (req->base.drm_surface_flags & + drm_vmw_surface_flag_create_buffer) + 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); + + 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, + VMW_RES_SURFACE, + &vmw_user_surface_base_release, NULL); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&tmp); + vmw_resource_unreference(&res); + goto out_unlock; + } + + rep->handle = user_srf->prime.base.hash.key; + rep->backup_size = res->backup_size; + if (res->backup) { + rep->buffer_map_handle = + drm_vma_node_offset_addr(&res->backup->base.vma_node); + rep->buffer_size = res->backup->base.num_pages * PAGE_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: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + +/** + * vmw_gb_surface_reference_internal - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Pointer to user-space request surface arg. + * @rep: Pointer to response to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + 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 ttm_base_object *base; + uint32_t backup_handle; + int ret = -EINVAL; + + ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, + req->handle_type, &base); + if (unlikely(ret != 0)) + return ret; + + user_srf = container_of(base, struct vmw_user_surface, prime.base); + srf = &user_srf->srf; + if (!srf->res.backup) { + DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); + goto out_bad_resource; + } + + mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ + ret = vmw_user_bo_reference(tfile, srf->res.backup, &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->hash.key, + TTM_REF_USAGE); + goto out_bad_resource; + } + + rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(srf->flags); + rep->creq.base.format = srf->format; + rep->creq.base.mip_levels = srf->mip_levels[0]; + rep->creq.base.drm_surface_flags = 0; + rep->creq.base.multisample_count = srf->multisample_count; + rep->creq.base.autogen_filter = srf->autogen_filter; + rep->creq.base.array_size = srf->array_size; + rep->creq.base.buffer_handle = backup_handle; + rep->creq.base.base_size = srf->base_size; + rep->crep.handle = user_srf->prime.base.hash.key; + rep->crep.backup_size = srf->res.backup_size; + rep->crep.buffer_handle = backup_handle; + rep->crep.buffer_map_handle = + drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); + rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; + + rep->creq.version = drm_vmw_gb_surface_v1; + rep->creq.svga3d_flags_upper_32_bits = + SVGA3D_FLAGS_UPPER_32(srf->flags); + rep->creq.multisample_pattern = srf->multisample_pattern; + rep->creq.quality_level = srf->quality_level; + rep->creq.must_be_zero = 0; + +out_bad_resource: + ttm_base_object_unref(&base); + + return ret; +} |