From f1d34bfd70b1b4543a139ea28bad4c001c5f413d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 19 Jun 2018 15:02:16 +0200 Subject: drm/vmwgfx: Replace vmw_dma_buffer with vmw_buffer_object Initially vmware buffer objects were only used as DMA buffers, so the name DMA buffer was a natural one. However, currently they are used also as dumb buffers and MOBs backing guest backed objects so renaming them to buffer objects is logical. Particularly since there is a dmabuf subsystem in the kernel where a dma buffer means something completely different. This also renames user-space api structures and IOCTL names correspondingly, but the old names remain defined for now and the ABI hasn't changed. There are a couple of minor style changes to make checkpatch happy. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Reviewed-by: Deepak Rawat --- include/uapi/drm/vmwgfx_drm.h | 61 ++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 39 deletions(-) (limited to 'include/uapi/drm') diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 0bc784f5e0db..57115a5fe61a 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -40,6 +40,7 @@ extern "C" { #define DRM_VMW_GET_PARAM 0 #define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_ALLOC_BO 1 #define DRM_VMW_UNREF_DMABUF 2 #define DRM_VMW_HANDLE_CLOSE 2 #define DRM_VMW_CURSOR_BYPASS 3 @@ -356,9 +357,9 @@ struct drm_vmw_fence_rep { /*************************************************************************/ /** - * DRM_VMW_ALLOC_DMABUF + * DRM_VMW_ALLOC_BO * - * Allocate a DMA buffer that is visible also to the host. + * Allocate a buffer object that is visible also to the host. * NOTE: The buffer is * identified by a handle and an offset, which are private to the guest, but * useable in the command stream. The guest kernel may translate these @@ -366,27 +367,28 @@ struct drm_vmw_fence_rep { * be zero at all times, or it may disappear from the interface before it is * fixed. * - * The DMA buffer may stay user-space mapped in the guest at all times, + * The buffer object may stay user-space mapped in the guest at all times, * and is thus suitable for sub-allocation. * - * DMA buffers are mapped using the mmap() syscall on the drm device. + * Buffer objects are mapped using the mmap() syscall on the drm device. */ /** - * struct drm_vmw_alloc_dmabuf_req + * struct drm_vmw_alloc_bo_req * * @size: Required minimum size of the buffer. * - * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Input data to the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_alloc_dmabuf_req { +struct drm_vmw_alloc_bo_req { __u32 size; __u32 pad64; }; +#define drm_vmw_alloc_dmabuf_req drm_vmw_alloc_bo_req /** - * struct drm_vmw_dmabuf_rep + * struct drm_vmw_bo_rep * * @map_handle: Offset to use in the mmap() call used to map the buffer. * @handle: Handle unique to this buffer. Used for unreferencing. @@ -395,50 +397,32 @@ struct drm_vmw_alloc_dmabuf_req { * @cur_gmr_offset: Offset to use in the command stream when this buffer is * referenced. See note above. * - * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + * Output data from the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_dmabuf_rep { +struct drm_vmw_bo_rep { __u64 map_handle; __u32 handle; __u32 cur_gmr_id; __u32 cur_gmr_offset; __u32 pad64; }; +#define drm_vmw_dmabuf_rep drm_vmw_bo_rep /** - * union drm_vmw_dmabuf_arg + * union drm_vmw_alloc_bo_arg * * @req: Input data as described above. * @rep: Output data as described above. * - * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Argument to the DRM_VMW_ALLOC_BO Ioctl. */ -union drm_vmw_alloc_dmabuf_arg { - struct drm_vmw_alloc_dmabuf_req req; - struct drm_vmw_dmabuf_rep rep; -}; - -/*************************************************************************/ -/** - * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. - * - */ - -/** - * struct drm_vmw_unref_dmabuf_arg - * - * @handle: Handle indicating what buffer to free. Obtained from the - * DRM_VMW_ALLOC_DMABUF Ioctl. - * - * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. - */ - -struct drm_vmw_unref_dmabuf_arg { - __u32 handle; - __u32 pad64; +union drm_vmw_alloc_bo_arg { + struct drm_vmw_alloc_bo_req req; + struct drm_vmw_bo_rep rep; }; +#define drm_vmw_alloc_dmabuf_arg drm_vmw_alloc_bo_arg /*************************************************************************/ /** @@ -1103,9 +1087,8 @@ union drm_vmw_extended_context_arg { * DRM_VMW_HANDLE_CLOSE - Close a user-space handle and release its * underlying resource. * - * Note that this ioctl is overlaid on the DRM_VMW_UNREF_DMABUF Ioctl. - * The ioctl arguments therefore need to be identical in layout. - * + * Note that this ioctl is overlaid on the deprecated DRM_VMW_UNREF_DMABUF + * Ioctl. */ /** @@ -1119,7 +1102,7 @@ struct drm_vmw_handle_close_arg { __u32 handle; __u32 pad64; }; - +#define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg #if defined(__cplusplus) } -- cgit v1.2.3-73-gaa49b From 3b4c2511c004521efa89875512b5039a04d5e2e0 Mon Sep 17 00:00:00 2001 From: Neha Bhende Date: Mon, 18 Jun 2018 16:44:48 -0700 Subject: drm/vmwgfx: Add CAP2 support in vmwgfx The device exposes a new capability register. Add support for it. Signed-off-by: Neha Bhende Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 17 +++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 +++ include/uapi/drm/vmwgfx_drm.h | 1 + 4 files changed, 22 insertions(+) (limited to 'include/uapi/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1128420de2c0..f2fad88e4c54 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -258,6 +258,15 @@ MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); +static void vmw_print_capabilities2(uint32_t capabilities2) +{ + DRM_INFO("Capabilities2:\n"); + if (capabilities2 & SVGA_CAP2_GROW_OTABLE) + DRM_INFO(" Grow oTable.\n"); + if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) + DRM_INFO(" IntraSurface copy.\n"); +} + static void vmw_print_capabilities(uint32_t capabilities) { DRM_INFO("Capabilities:\n"); @@ -684,6 +693,12 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); + + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) { + dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2); + } + + ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { DRM_INFO("Restricting capabilities due to IOMMU setup.\n"); @@ -752,6 +767,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } vmw_print_capabilities(dev_priv->capabilities); + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) + vmw_print_capabilities2(dev_priv->capabilities2); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a3a0826958a1..920365c0e9ab 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -386,6 +386,7 @@ struct vmw_private { uint32_t initial_height; u32 *mmio_virt; uint32_t capabilities; + uint32_t capabilities2; uint32_t max_gmr_ids; uint32_t max_gmr_pages; uint32_t max_mob_pages; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 6872c7ee8a08..ac6da0da2824 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -56,6 +56,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_HW_CAPS: param->value = dev_priv->capabilities; break; + case DRM_VMW_PARAM_HW_CAPS2: + param->value = dev_priv->capabilities2; + break; case DRM_VMW_PARAM_FIFO_CAPS: param->value = dev_priv->fifo.capabilities; break; diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 57115a5fe61a..84e81b38ca18 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -95,6 +95,7 @@ extern "C" { #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 #define DRM_VMW_PARAM_SCREEN_TARGET 11 #define DRM_VMW_PARAM_DX 12 +#define DRM_VMW_PARAM_HW_CAPS2 13 /** * enum drm_vmw_handle_type - handle type for ref ioctls -- cgit v1.2.3-73-gaa49b From 14b1c33e84295693c3b1a1d7c6ac82b3f384cd17 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 20 Jun 2018 14:48:35 -0700 Subject: drm/vmwgfx: Add new ioctl for GB surface create and reference New ioctls DRM_VMW_GB_SURFACE_CREATE_EXT and DRM_VMW_GB_SURFACE_REF_EXT are added which support 64-bit wide svga device surface flags, quality level and multisample pattern. Signed-off-by: Deepak Rawat Reviewed-by: Sinclair Yeh Reviewed-by: Brian Paul Reviewed-by: Thomas Hellstrom Reviewed-by: Charmaine Lee Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 12 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 8 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 20 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 + drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 468 +++++++++++++++++++++----------- include/uapi/drm/vmwgfx_drm.h | 102 +++++++ 6 files changed, 437 insertions(+), 175 deletions(-) (limited to 'include/uapi/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6cf81e19182f..59229111f303 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -137,6 +137,12 @@ #define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ struct drm_vmw_context_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \ + union drm_vmw_gb_surface_create_ext_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ + union drm_vmw_gb_surface_reference_ext_arg) /** * The core DRM version of this macro doesn't account for @@ -224,6 +230,12 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, + vmw_gb_surface_define_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, + vmw_gb_surface_reference_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7e5c93083036..59af14714797 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1087,7 +1087,15 @@ 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); +extern int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); +extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); /* * Shader management - vmwgfx_shader.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0fb363458ab5..3201b0a51d10 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1238,15 +1238,17 @@ static int vmw_create_bo_proxy(struct drm_device *dev, content_base_size.depth = 1; ret = vmw_surface_gb_priv_define(dev, - 0, /* kernel visible only */ - 0, /* flags */ - format, - true, /* can be a scanout buffer */ - 1, /* num of mip levels */ - 0, - 0, - content_base_size, - srf_out); + 0, /* kernel visible only */ + 0, /* flags */ + format, + true, /* can be a scanout buffer */ + 1, /* num of mip levels */ + 0, + 0, + content_base_size, + SVGA3D_MS_PATTERN_NONE, + SVGA3D_MS_QUALITY_NONE, + srf_out); if (ret) { DRM_ERROR("Failed to allocate proxy content buffer\n"); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 6630abf3a95c..f9872c9e60c4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1188,6 +1188,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, content_srf.multisample_count, 0, display_base_size, + content_srf.multisample_pattern, + content_srf.quality_level, &vps->surf); if (ret != 0) { DRM_ERROR("Couldn't allocate STDU surface.\n"); 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; +} diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 84e81b38ca18..68ff37d4c035 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -69,6 +69,8 @@ extern "C" { #define DRM_VMW_GB_SURFACE_REF 24 #define DRM_VMW_SYNCCPU 25 #define DRM_VMW_CREATE_EXTENDED_CONTEXT 26 +#define DRM_VMW_GB_SURFACE_CREATE_EXT 27 +#define DRM_VMW_GB_SURFACE_REF_EXT 28 /*************************************************************************/ /** @@ -1105,6 +1107,106 @@ struct drm_vmw_handle_close_arg { }; #define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_CREATE_EXT - Create a host guest-backed surface. + * + * Allocates a surface handle and queues a create surface command + * for the host on the first use of the surface. The surface ID can + * be used as the surface ID in commands referencing the surface. + * + * This new command extends DRM_VMW_GB_SURFACE_CREATE by adding version + * parameter and 64 bit svga flag. + */ + +/** + * enum drm_vmw_surface_version + * + * @drm_vmw_surface_gb_v1: Corresponds to current gb surface format with + * svga3d surface flags split into 2, upper half and lower half. + */ +enum drm_vmw_surface_version { + drm_vmw_gb_surface_v1 +}; + +/** + * struct drm_vmw_gb_surface_create_ext_req + * + * @base: Surface create parameters. + * @version: Version of surface create ioctl. + * @svga3d_flags_upper_32_bits: Upper 32 bits of svga3d flags. + * @multisample_pattern: Multisampling pattern when msaa is supported. + * @quality_level: Precision settings for each sample. + * @must_be_zero: Reserved for future usage. + * + * Input argument to the DRM_VMW_GB_SURFACE_CREATE_EXT Ioctl. + * Part of output argument for the DRM_VMW_GB_SURFACE_REF_EXT Ioctl. + */ +struct drm_vmw_gb_surface_create_ext_req { + struct drm_vmw_gb_surface_create_req base; + enum drm_vmw_surface_version version; + uint32_t svga3d_flags_upper_32_bits; + SVGA3dMSPattern multisample_pattern; + SVGA3dMSQualityLevel quality_level; + uint64_t must_be_zero; +}; + +/** + * union drm_vmw_gb_surface_create_ext_arg + * + * @req: Input argument as described above. + * @rep: Output argument as described above. + * + * Argument to the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ +union drm_vmw_gb_surface_create_ext_arg { + struct drm_vmw_gb_surface_create_rep rep; + struct drm_vmw_gb_surface_create_ext_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_REF_EXT - Reference a host surface. + * + * Puts a reference on a host surface with a given handle, as previously + * returned by the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface handle in + * the command stream. + * + * On successful return, the Ioctl returns the surface information given + * to and returned from the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ + +/** + * struct drm_vmw_gb_surface_ref_ext_rep + * + * @creq: The data used as input when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_ext_req" + * @crep: Additional data output when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_rep" + * + * Output Argument to the DRM_VMW_GB_SURFACE_REF_EXT ioctl. + */ +struct drm_vmw_gb_surface_ref_ext_rep { + struct drm_vmw_gb_surface_create_ext_req creq; + struct drm_vmw_gb_surface_create_rep crep; +}; + +/** + * union drm_vmw_gb_surface_reference_ext_arg + * + * @req: Input data as described above at "struct drm_vmw_surface_arg" + * @rep: Output data as described above at + * "struct drm_vmw_gb_surface_ref_ext_rep" + * + * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +union drm_vmw_gb_surface_reference_ext_arg { + struct drm_vmw_gb_surface_ref_ext_rep rep; + struct drm_vmw_surface_arg req; +}; + #if defined(__cplusplus) } #endif -- cgit v1.2.3-73-gaa49b From 9b07b287aa3ef49695bfad59c1870cd942f579a8 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 20 Jun 2018 15:09:43 -0700 Subject: drm/vmwgfx: Expose SM4_1 param to user space A new param DRM_VMW_PARAM_SM4_1, is added for user space to determine availability of SM4.1. Minor version bump for SM4.1. Signed-off-by: Deepak Rawat Reviewed-by: Sinclair Yeh Reviewed-by: Brian Paul Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 +++ include/uapi/drm/vmwgfx_drm.h | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include/uapi/drm') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a67b54e4fd50..f1b803d34c59 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,10 +43,10 @@ #include #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20180322" +#define VMWGFX_DRIVER_DATE "20180704" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 14 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 15 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index ac6da0da2824..e825192ca30e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -116,6 +116,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_DX: param->value = dev_priv->has_dx; break; + case DRM_VMW_PARAM_SM4_1: + param->value = dev_priv->has_sm4_1; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 68ff37d4c035..399f58317cff 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -82,6 +82,9 @@ extern "C" { * * DRM_VMW_PARAM_OVERLAY_IOCTL: * Does the driver support the overlay ioctl. + * + * DRM_VMW_PARAM_SM4_1 + * SM4_1 support is enabled. */ #define DRM_VMW_PARAM_NUM_STREAMS 0 @@ -98,6 +101,7 @@ extern "C" { #define DRM_VMW_PARAM_SCREEN_TARGET 11 #define DRM_VMW_PARAM_DX 12 #define DRM_VMW_PARAM_HW_CAPS2 13 +#define DRM_VMW_PARAM_SM4_1 14 /** * enum drm_vmw_handle_type - handle type for ref ioctls -- cgit v1.2.3-73-gaa49b From 964d0fbf6301d3dc8dfad19ffab5a06d002d27f1 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Fri, 6 Jul 2018 14:16:54 -0400 Subject: drm/amdgpu: Allow to create BO lists in CS ioctl v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is to support MESA performace optimization. Modify CS IOCTL to allow its input as command buffer and an array of buffer handles to create a temporay bo list and then destroy it when IOCTL completes. This saves on calling for BO_LIST create and destry IOCTLs in MESA and by this improves performance. v2: Avoid inserting the temp list into idr struct. v3: Remove idr alloation from amdgpu_bo_list_create. Remove useless argument from amdgpu_cs_parser_fini Minor cosmetic stuff. v4: Revert amdgpu_bo_list_destroy back to static Signed-off-by: Andrey Grodzovsky Reviewed-by: Christian König Reviewed-by: Chunming Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 8 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 88 +++++++++++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 48 +++++++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +- include/uapi/drm/amdgpu_drm.h | 1 + 5 files changed, 108 insertions(+), 40 deletions(-) (limited to 'include/uapi/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 53435da158c2..c6c1e8dc919f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -732,6 +732,14 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, struct list_head *validated); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); void amdgpu_bo_list_free(struct amdgpu_bo_list *list); +int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, + struct drm_amdgpu_bo_list_entry **info_param); + +int amdgpu_bo_list_create(struct amdgpu_device *adev, + struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + unsigned num_entries, + struct amdgpu_bo_list **list); /* * GFX stuff diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 92be7f6de197..7679c068c89a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -55,15 +55,15 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref) kfree_rcu(list, rhead); } -static int amdgpu_bo_list_create(struct amdgpu_device *adev, +int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, struct drm_amdgpu_bo_list_entry *info, unsigned num_entries, - int *id) + struct amdgpu_bo_list **list_out) { - int r; - struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_bo_list *list; + int r; + list = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL); if (!list) @@ -78,16 +78,7 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev, return r; } - /* idr alloc should be called only after initialization of bo list. */ - mutex_lock(&fpriv->bo_list_lock); - r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); - mutex_unlock(&fpriv->bo_list_lock); - if (r < 0) { - amdgpu_bo_list_free(list); - return r; - } - *id = r; - + *list_out = list; return 0; } @@ -263,55 +254,79 @@ void amdgpu_bo_list_free(struct amdgpu_bo_list *list) kfree(list); } -int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) +int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, + struct drm_amdgpu_bo_list_entry **info_param) { + const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr); const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry); - - struct amdgpu_device *adev = dev->dev_private; - struct amdgpu_fpriv *fpriv = filp->driver_priv; - union drm_amdgpu_bo_list *args = data; - uint32_t handle = args->in.list_handle; - const void __user *uptr = u64_to_user_ptr(args->in.bo_info_ptr); - struct drm_amdgpu_bo_list_entry *info; - struct amdgpu_bo_list *list; - int r; - info = kvmalloc_array(args->in.bo_number, - sizeof(struct drm_amdgpu_bo_list_entry), GFP_KERNEL); + info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL); if (!info) return -ENOMEM; /* copy the handle array from userspace to a kernel buffer */ r = -EFAULT; - if (likely(info_size == args->in.bo_info_size)) { - unsigned long bytes = args->in.bo_number * - args->in.bo_info_size; + if (likely(info_size == in->bo_info_size)) { + unsigned long bytes = in->bo_number * + in->bo_info_size; if (copy_from_user(info, uptr, bytes)) goto error_free; } else { - unsigned long bytes = min(args->in.bo_info_size, info_size); + unsigned long bytes = min(in->bo_info_size, info_size); unsigned i; - memset(info, 0, args->in.bo_number * info_size); - for (i = 0; i < args->in.bo_number; ++i) { + memset(info, 0, in->bo_number * info_size); + for (i = 0; i < in->bo_number; ++i) { if (copy_from_user(&info[i], uptr, bytes)) goto error_free; - uptr += args->in.bo_info_size; + uptr += in->bo_info_size; } } + *info_param = info; + return 0; + +error_free: + kvfree(info); + return r; +} + +int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_fpriv *fpriv = filp->driver_priv; + union drm_amdgpu_bo_list *args = data; + uint32_t handle = args->in.list_handle; + struct drm_amdgpu_bo_list_entry *info = NULL; + struct amdgpu_bo_list *list; + int r; + + r = amdgpu_bo_create_list_entry_array(&args->in, &info); + if (r) + goto error_free; + switch (args->in.operation) { case AMDGPU_BO_LIST_OP_CREATE: r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number, - &handle); + &list); if (r) goto error_free; + + mutex_lock(&fpriv->bo_list_lock); + r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); + mutex_unlock(&fpriv->bo_list_lock); + if (r < 0) { + amdgpu_bo_list_free(list); + return r; + } + + handle = r; break; case AMDGPU_BO_LIST_OP_DESTROY: @@ -345,6 +360,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, return 0; error_free: - kvfree(info); + if (info) + kvfree(info); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 5a2a5ba29f9a..6d8df76b5a5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -66,11 +66,35 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, return 0; } -static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) +static int amdgpu_cs_bo_handles_chunk(struct amdgpu_cs_parser *p, + struct drm_amdgpu_bo_list_in *data) +{ + int r; + struct drm_amdgpu_bo_list_entry *info = NULL; + + r = amdgpu_bo_create_list_entry_array(data, &info); + if (r) + return r; + + r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number, + &p->bo_list); + if (r) + goto error_free; + + kvfree(info); + return 0; + +error_free: + if (info) + kvfree(info); + + return r; +} + +static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - union drm_amdgpu_cs *cs = data; uint64_t *chunk_array_user; uint64_t *chunk_array; unsigned size, num_ibs = 0; @@ -164,6 +188,19 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) break; + case AMDGPU_CHUNK_ID_BO_HANDLES: + size = sizeof(struct drm_amdgpu_bo_list_in); + if (p->chunks[i].length_dw * sizeof(uint32_t) < size) { + ret = -EINVAL; + goto free_partial_kdata; + } + + ret = amdgpu_cs_bo_handles_chunk(p, p->chunks[i].kdata); + if (ret) + goto free_partial_kdata; + + break; + case AMDGPU_CHUNK_ID_DEPENDENCIES: case AMDGPU_CHUNK_ID_SYNCOBJ_IN: case AMDGPU_CHUNK_ID_SYNCOBJ_OUT: @@ -534,7 +571,12 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&p->validated); - p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); + /* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */ + if (!p->bo_list) + p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); + else + mutex_lock(&p->bo_list->lock); + if (p->bo_list) { amdgpu_bo_list_get_list(p->bo_list, &p->validated); if (p->bo_list->first_userptr != p->bo_list->num_entries) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 06aede194bf8..529500c94675 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -69,9 +69,10 @@ * - 3.24.0 - Add high priority compute support for gfx9 * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk). * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE. + * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation. */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 26 +#define KMS_DRIVER_MINOR 27 #define KMS_DRIVER_PATCHLEVEL 0 int amdgpu_vram_limit = 0; diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 784b0fe470ee..1ceec56de015 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -516,6 +516,7 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 #define AMDGPU_CHUNK_ID_SYNCOBJ_IN 0x04 #define AMDGPU_CHUNK_ID_SYNCOBJ_OUT 0x05 +#define AMDGPU_CHUNK_ID_BO_HANDLES 0x06 struct drm_amdgpu_cs_chunk { __u32 chunk_id; -- cgit v1.2.3-73-gaa49b From 2a8536f6e8464b8988baa7db881f30721616b0da Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran Date: Tue, 5 Jun 2018 19:00:54 -0700 Subject: drm: add msm compressed format modifiers Qualcomm Snapdragon chipsets uses compressed format to optimize BW across multiple IP's. This change adds needed modifier support in drm for a simple 4x4 tile based compressed variants of base formats. Changes in v3: - Removed duplicate entry for DRM_FORMAT_MOD_QCOM_COMPRESSED (Rob Clark) Changes in v4: - Remove all modifiers aside from COMPRESSED, this includes tiled and 10-bit Signed-off-by: Jeykumar Sankaran Signed-off-by: Sean Paul Signed-off-by: Rob Clark --- include/uapi/drm/drm_fourcc.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include/uapi/drm') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index d43949b5bb3e..721ab7e54d96 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -299,6 +299,19 @@ extern "C" { */ #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) +/* + * Qualcomm Compressed Format + * + * Refers to a compressed variant of the base format that is compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) + /* Vivante framebuffer modifiers */ /* -- cgit v1.2.3-73-gaa49b