From: Martin Krastev krastevm@vmware.com
* Add support for CursorMob * Add support for CursorBypass 4
Reviewed-by: Zack Rusin zackr@vmware.com Signed-off-by: Martin Krastev krastevm@vmware.com Signed-off-by: Zack Rusin zackr@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 45 +++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 79 +++++++++++++++++++++++++++-- 3 files changed, 125 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 086dc75e7b42..7d8cc2f6b04e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009-2016 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2021 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 @@ -301,8 +301,12 @@ static void vmw_print_capabilities2(uint32_t capabilities2) DRM_INFO(" Grow oTable.\n"); if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) DRM_INFO(" IntraSurface copy.\n"); + if (capabilities2 & SVGA_CAP2_CURSOR_MOB) + DRM_INFO(" Cursor Mob.\n"); if (capabilities2 & SVGA_CAP2_DX3) DRM_INFO(" DX3.\n"); + if (capabilities2 & SVGA_CAP2_EXTRA_REGS) + DRM_INFO(" Extra Regs.\n"); }
static void vmw_print_capabilities(uint32_t capabilities) @@ -505,6 +509,7 @@ static int vmw_request_device_late(struct vmw_private *dev_priv) static int vmw_request_device(struct vmw_private *dev_priv) { int ret; + size_t i;
ret = vmw_device_init(dev_priv); if (unlikely(ret != 0)) { @@ -526,6 +531,37 @@ static int vmw_request_device(struct vmw_private *dev_priv) if (unlikely(ret != 0)) goto out_no_query_bo;
+ /* Set up mobs for cursor updates */ + if (dev_priv->has_mob && dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) { + const uint32_t cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); + + for (i = 0; i < ARRAY_SIZE(dev_priv->cursor_mob); i++) { + struct ttm_buffer_object **const bo = &dev_priv->cursor_mob[i]; + + ret = vmw_bo_create_kernel(dev_priv, + cursor_max_dim * cursor_max_dim * sizeof(u32) + sizeof(SVGAGBCursorHeader), + &vmw_mob_placement, bo); + + if (ret != 0) { + DRM_ERROR("Unable to create CursorMob array.\n"); + break; + } + + BUG_ON((*bo)->resource->mem_type != VMW_PL_MOB); + + /* Fence the mob creation so we are guarateed to have the mob */ + ret = ttm_bo_reserve(*bo, false, true, NULL); + BUG_ON(ret); + + vmw_bo_fence_single(*bo, NULL); + + ttm_bo_unreserve(*bo); + + DRM_INFO("Using CursorMob mobid %lu, max dimension %u\n", + (*bo)->resource->start, cursor_max_dim); + } + } + return 0;
out_no_query_bo: @@ -556,6 +592,8 @@ static int vmw_request_device(struct vmw_private *dev_priv) */ static void vmw_release_device_early(struct vmw_private *dev_priv) { + size_t i; + /* * Previous destructions should've released * the pinned bo. @@ -570,6 +608,11 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) if (dev_priv->has_mob) { struct ttm_resource_manager *man;
+ for (i = 0; i < ARRAY_SIZE(dev_priv->cursor_mob); i++) { + if (dev_priv->cursor_mob[i] != NULL) + ttm_bo_put(dev_priv->cursor_mob[i]); + } + man = ttm_manager_type(&dev_priv->bdev, VMW_PL_MOB); ttm_resource_manager_evict_all(&dev_priv->bdev, man); vmw_otables_takedown(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356f82c26f59..46bf54f6169a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -642,6 +642,12 @@ struct vmw_private { u8 mksstat_kern_top_timer[MKSSTAT_CAPACITY]; atomic_t mksstat_kern_pids[MKSSTAT_CAPACITY]; #endif + + /* + * CursorMob buffer objects + */ + struct ttm_buffer_object *cursor_mob[2]; + atomic_t cursor_mob_idx; };
static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 2ddf4932d62c..8d7844354774 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2021 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 @@ -53,6 +53,10 @@ void vmw_du_cleanup(struct vmw_display_unit *du) * Display Unit Cursor functions */
+static int vmw_cursor_update_mob(struct vmw_private *dev_priv, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY); + static int vmw_cursor_update_image(struct vmw_private *dev_priv, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY) @@ -67,6 +71,10 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv, if (!image) return -EINVAL;
+ if (dev_priv->cursor_mob[ARRAY_SIZE(dev_priv->cursor_mob) - 1] != NULL) + return vmw_cursor_update_mob(dev_priv, image, width, height, + hotspotX, hotspotY); + cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); if (unlikely(cmd == NULL)) return -ENOMEM; @@ -87,6 +95,62 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv, return 0; }
+static int vmw_cursor_update_mob(struct vmw_private *dev_priv, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + SVGAGBCursorHeader *header; + SVGAGBAlphaCursorHeader *alpha_header; + const u32 image_size = width * height * sizeof(*image); + const u32 mob_size = sizeof(*header) + image_size; + + struct ttm_buffer_object *bo; + struct ttm_bo_kmap_obj map; + bool dummy; + int ret; + + bo = dev_priv->cursor_mob[atomic_inc_return(&dev_priv->cursor_mob_idx) % + ARRAY_SIZE(dev_priv->cursor_mob)]; + BUG_ON(bo == NULL); + + ret = ttm_bo_reserve(bo, true, false, NULL); + + if (unlikely(ret != 0)) { + DRM_ERROR("reserve failed\n"); + return -EINVAL; + } + + ret = ttm_bo_kmap(bo, 0, vmw_num_pages(mob_size), &map); + + if (unlikely(ret != 0)) + goto err_map; + + header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(&map, &dummy); + alpha_header = &header->header.alphaHeader; + + header->type = SVGA_ALPHA_CURSOR; + header->sizeInBytes = image_size; + + alpha_header->hotspotX = hotspotX; + alpha_header->hotspotY = hotspotY; + alpha_header->width = width; + alpha_header->height = height; + + memcpy(header + 1, image, image_size); + + ttm_bo_kunmap(&map); + ttm_bo_unreserve(bo); + + vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start); + + return 0; + +err_map: + ttm_bo_unreserve(bo); + + return ret; +} + static int vmw_cursor_update_bo(struct vmw_private *dev_priv, struct vmw_buffer_object *bo, u32 width, u32 height, @@ -127,11 +191,18 @@ static int vmw_cursor_update_bo(struct vmw_private *dev_priv, static void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y) { + const uint32_t svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW + : SVGA_CURSOR_ON_HIDE; uint32_t count;
spin_lock(&dev_priv->cursor_lock); - if (vmw_is_cursor_bypass3_enabled(dev_priv)) { - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, show ? 1 : 0); + if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) { + vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x); + vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y); + vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on); + vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, TRUE); + } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) { + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on); vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); @@ -139,7 +210,7 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv, } else { vmw_write(dev_priv, SVGA_REG_CURSOR_X, x); vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y); - vmw_write(dev_priv, SVGA_REG_CURSOR_ON, show ? 1 : 0); + vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on); } spin_unlock(&dev_priv->cursor_lock); }
The macro has been accounting for DRM_COMMAND_BASE for a long time now so there's no reason to still be duplicating it. Plus we were leaving the name undefined which meant that all the DRM ioctl warnings/errors were always listing "null" ioctl at the culprit.
This fixes the undefined ioctl name and removes duplicated code.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 176 +++++++++++++--------------- 1 file changed, 84 insertions(+), 92 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7d8cc2f6b04e..359f2e6f3693 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -159,110 +159,102 @@ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_REMOVE, \ struct drm_vmw_mksstat_remove_arg)
-/* - * The core DRM version of this macro doesn't account for - * DRM_COMMAND_BASE. - */ - -#define VMW_IOCTL_DEF(ioctl, func, flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func} - /* * Ioctl definitions. */
static const struct drm_ioctl_desc vmw_ioctls[] = { - VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, - vmw_kms_cursor_bypass_ioctl, - DRM_MASTER), - - VMW_IOCTL_DEF(VMW_CONTROL_STREAM, vmw_overlay_ioctl, - DRM_MASTER), - VMW_IOCTL_DEF(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, - DRM_MASTER), - VMW_IOCTL_DEF(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, - DRM_MASTER), - - VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_SIGNALED, - vmw_fence_obj_signaled_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, - DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GET_PARAM, vmw_getparam_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CURSOR_BYPASS, + vmw_kms_cursor_bypass_ioctl, + DRM_MASTER), + + DRM_IOCTL_DEF_DRV(VMW_CONTROL_STREAM, vmw_overlay_ioctl, + DRM_MASTER), + DRM_IOCTL_DEF_DRV(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, + DRM_MASTER), + DRM_IOCTL_DEF_DRV(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, + DRM_MASTER), + + DRM_IOCTL_DEF_DRV(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_REF_SURFACE, vmw_surface_reference_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_EXECBUF, vmw_execbuf_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_SIGNALED, + vmw_fence_obj_signaled_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_EVENT, vmw_fence_event_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, + DRM_RENDER_ALLOW),
/* these allow direct access to the framebuffers mark as master only */ - VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, - DRM_MASTER | DRM_AUTH), - VMW_IOCTL_DEF(VMW_PRESENT_READBACK, - vmw_present_readback_ioctl, - DRM_MASTER | DRM_AUTH), + DRM_IOCTL_DEF_DRV(VMW_PRESENT, vmw_present_ioctl, + DRM_MASTER | DRM_AUTH), + DRM_IOCTL_DEF_DRV(VMW_PRESENT_READBACK, + vmw_present_readback_ioctl, + DRM_MASTER | DRM_AUTH), /* * The permissions of the below ioctl are overridden in * vmw_generic_ioctl(). We require either * DRM_MASTER or capable(CAP_SYS_ADMIN). */ - VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, - vmw_kms_update_layout_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_SHADER, - vmw_shader_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_SHADER, - vmw_shader_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, - vmw_gb_surface_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, - vmw_gb_surface_reference_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_SYNCCPU, - vmw_user_bo_synccpu_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, - vmw_extended_context_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, - vmw_gb_surface_define_ext_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, - vmw_gb_surface_reference_ext_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MSG, - vmw_msg_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_RESET, - vmw_mksstat_reset_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_ADD, - vmw_mksstat_add_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_REMOVE, - vmw_mksstat_remove_ioctl, - DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UPDATE_LAYOUT, + vmw_kms_update_layout_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_SHADER, + vmw_shader_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_SHADER, + vmw_shader_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE, + vmw_gb_surface_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF, + vmw_gb_surface_reference_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_SYNCCPU, + vmw_user_bo_synccpu_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_EXTENDED_CONTEXT, + vmw_extended_context_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE_EXT, + vmw_gb_surface_define_ext_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF_EXT, + vmw_gb_surface_reference_ext_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MSG, + vmw_msg_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_RESET, + vmw_mksstat_reset_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_ADD, + vmw_mksstat_add_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_REMOVE, + vmw_mksstat_remove_ioctl, + DRM_RENDER_ALLOW), };
static const struct pci_device_id vmw_pci_id_list[] = {
The code was trying to keep a strict limit on the amount of mob memory that was used in the guest by making it match the host settings. There's technically no reason to do that (guests can certainly use more than the host can have resident in renderers at the same time).
In particular this is problematic because our userspace is not great at handling OOM conditions and running out of MOB space results in GL apps crashing, e.g. gnome-shell likes to allocate huge surfaces (~61MB for the desktop on 2560x1600 with two workspaces) and running out of memory there means that the gnome-shell crashes on startup taking us back to the login and resulting in a system where one can not login in graphically anymore.
Instead of letting the userspace crash we can extend available MOB space, we just don't want to use all of the RAM for graphics, so we're going to limit it to half of RAM.
With the addition of some extra logging this should make the "guest has been configured with not enough graphics memory" errors a lot easier to diagnose in cases where the automatic expansion of MOB space fails.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 8 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 36 +++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 359f2e6f3693..a9195c472b75 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -948,6 +948,13 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->texture_max_height = 8192; dev_priv->max_primary_mem = dev_priv->vram_size; } + DRM_INFO("Legacy memory limits: VRAM = %llu kB, FIFO = %llu kB, surface = %u kB\n", + (u64)dev_priv->vram_size / 1024, + (u64)dev_priv->fifo_mem_size / 1024, + dev_priv->memory_size / 1024); + + DRM_INFO("MOB limits: max mob size = %u kB, max mob pages = %u\n", + dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages);
vmw_print_capabilities(dev_priv->capabilities); if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) @@ -1094,7 +1101,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) DRM_INFO("SM4_1 support available.\n"); if (dev_priv->sm_type == VMW_SM_4) DRM_INFO("SM4 support available.\n"); - DRM_INFO("Running without reservation semaphore\n");
vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 28ceb749a733..b2c4af331c9d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -71,8 +71,40 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
if (gman->max_gmr_pages > 0) { gman->used_gmr_pages += (*res)->num_pages; - if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) - goto nospace; + /* + * Because the graphics memory is a soft limit we can try to + * expand it instead of letting the userspace apps crash. + * We're just going to have a sane limit (half of RAM) + * on the number of MOB's that we create and will try to keep + * the system running until we reach that. + */ + if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) { + const unsigned long max_graphics_pages = totalram_pages() / 2; + uint32_t new_max_pages = 0; + + DRM_WARN("vmwgfx: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n"); + vmw_host_printf("vmwgfx, warning: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n"); + + if (gman->max_gmr_pages > (max_graphics_pages / 2)) { + DRM_WARN("vmwgfx: guest requires more than half of RAM for graphics.\n"); + new_max_pages = max_graphics_pages; + } else + new_max_pages = gman->max_gmr_pages * 2; + if (new_max_pages > gman->max_gmr_pages && new_max_pages >= gman->used_gmr_pages) { + DRM_WARN("vmwgfx: increasing guest mob limits to %u kB.\n", + ((new_max_pages) << (PAGE_SHIFT - 10))); + + gman->max_gmr_pages = new_max_pages; + } else { + char buf[256]; + snprintf(buf, sizeof(buf), + "vmwgfx, error: guest graphics is out of memory (mob limit at: %ukB).\n", + ((gman->max_gmr_pages) << (PAGE_SHIFT - 10))); + vmw_host_printf(buf); + DRM_WARN("%s", buf); + goto nospace; + } + } }
(*res)->start = id;
To let the userspace recognize that it's running on top of a vmwgfx that supports mks-stat ioctls we need to bump the version number.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Reviewed-by: Neha Bhende bhenden@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 46bf54f6169a..aaadda5f1b4a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -54,10 +54,10 @@
#define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20210218" +#define VMWGFX_DRIVER_DATE "20210713" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 18 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 19 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 #define VMWGFX_MAX_VALIDATIONS 2048
Hi
Am 14.07.21 um 06:14 schrieb Zack Rusin:
From: Martin Krastev krastevm@vmware.com
- Add support for CursorMob
- Add support for CursorBypass 4
Reviewed-by: Zack Rusin zackr@vmware.com Signed-off-by: Martin Krastev krastevm@vmware.com Signed-off-by: Zack Rusin zackr@vmware.com
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 45 +++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 79 +++++++++++++++++++++++++++-- 3 files changed, 125 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 086dc75e7b42..7d8cc2f6b04e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /**************************************************************************
- Copyright 2009-2016 VMware, Inc., Palo Alto, CA., USA
- Copyright 2009-2021 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
@@ -301,8 +301,12 @@ static void vmw_print_capabilities2(uint32_t capabilities2) DRM_INFO(" Grow oTable.\n");
These macros have been out of fashion for a while. There's drm_info(), drm_warn(), drm_err(), etc as replacements. They also print device information. Applis here and for the rest of the patchset.
if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) DRM_INFO(" IntraSurface copy.\n");
if (capabilities2 & SVGA_CAP2_CURSOR_MOB)
DRM_INFO(" Cursor Mob.\n");
if (capabilities2 & SVGA_CAP2_DX3) DRM_INFO(" DX3.\n");
if (capabilities2 & SVGA_CAP2_EXTRA_REGS)
DRM_INFO(" Extra Regs.\n");
}
static void vmw_print_capabilities(uint32_t capabilities)
@@ -505,6 +509,7 @@ static int vmw_request_device_late(struct vmw_private *dev_priv) static int vmw_request_device(struct vmw_private *dev_priv) { int ret;
size_t i;
ret = vmw_device_init(dev_priv); if (unlikely(ret != 0)) {
@@ -526,6 +531,37 @@ static int vmw_request_device(struct vmw_private *dev_priv) if (unlikely(ret != 0)) goto out_no_query_bo;
- /* Set up mobs for cursor updates */
- if (dev_priv->has_mob && dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) {
const uint32_t cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
for (i = 0; i < ARRAY_SIZE(dev_priv->cursor_mob); i++) {
struct ttm_buffer_object **const bo = &dev_priv->cursor_mob[i];
ret = vmw_bo_create_kernel(dev_priv,
cursor_max_dim * cursor_max_dim * sizeof(u32) + sizeof(SVGAGBCursorHeader),
&vmw_mob_placement, bo);
if (ret != 0) {
DRM_ERROR("Unable to create CursorMob array.\n");
break;
}
BUG_ON((*bo)->resource->mem_type != VMW_PL_MOB);
BUG_ON() crashes the kernel. The prefered way is to use drm_WARN_*() and return.
/* Fence the mob creation so we are guarateed to have the mob */
ret = ttm_bo_reserve(*bo, false, true, NULL);
BUG_ON(ret);
I'm not quite sure, but this line is probably a no-go wrt to best practices. See the comment above.
vmw_bo_fence_single(*bo, NULL);
ttm_bo_unreserve(*bo);
DRM_INFO("Using CursorMob mobid %lu, max dimension %u\n",
(*bo)->resource->start, cursor_max_dim);
IIRC anything *_info() is just radom info into the log. Most of the time, no one cares. Better use one of the drm_dbg_() calls.
}
}
return 0;
out_no_query_bo:
@@ -556,6 +592,8 @@ static int vmw_request_device(struct vmw_private *dev_priv) */ static void vmw_release_device_early(struct vmw_private *dev_priv) {
- size_t i;
- /*
- Previous destructions should've released
- the pinned bo.
@@ -570,6 +608,11 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) if (dev_priv->has_mob) { struct ttm_resource_manager *man;
for (i = 0; i < ARRAY_SIZE(dev_priv->cursor_mob); i++) {
if (dev_priv->cursor_mob[i] != NULL)
ttm_bo_put(dev_priv->cursor_mob[i]);
}
- man = ttm_manager_type(&dev_priv->bdev, VMW_PL_MOB); ttm_resource_manager_evict_all(&dev_priv->bdev, man); vmw_otables_takedown(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356f82c26f59..46bf54f6169a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -642,6 +642,12 @@ struct vmw_private { u8 mksstat_kern_top_timer[MKSSTAT_CAPACITY]; atomic_t mksstat_kern_pids[MKSSTAT_CAPACITY]; #endif
- /*
* CursorMob buffer objects
*/
- struct ttm_buffer_object *cursor_mob[2];
- atomic_t cursor_mob_idx;
That's something like page-flipping with alternating BO's and shadow buffering?
You really want a cursor plane to hold this information.
I briefly looked through vmwgfx and it has all these fail-able code in its atomic-update path. The patches here only make things worse. With cursor planes, you can do all the preparation in atomic_check and prepare_fb, and store the intermediate state/mappings/etc in the plane state.
The ast driver started with a design like this one here and then we moved it to cursor planes. Ast has now none of the mentioned problems. Relevant code is at [1][2].
Best regards Thomas
[1] https://elixir.bootlin.com/linux/v5.13.1/source/drivers/gpu/drm/ast/ast_drv....
[2] https://elixir.bootlin.com/linux/v5.13.1/source/drivers/gpu/drm/ast/ast_mode...
On 7/14/21 3:30 AM, Thomas Zimmermann wrote:
@@ -301,8 +301,12 @@ static void vmw_print_capabilities2(uint32_t capabilities2) DRM_INFO(" Grow oTable.\n");
These macros have been out of fashion for a while. There's drm_info(), drm_warn(), drm_err(), etc as replacements. They also print device information. Applis here and for the rest of the patchset.
Yea, that's messy, I'll go ahead and cleanup some of our logging in v2.
+ BUG_ON((*bo)->resource->mem_type != VMW_PL_MOB);
BUG_ON() crashes the kernel. The prefered way is to use drm_WARN_*() and return.
This one is really an assert. This should never happen, I'm not sure if it's worth even testing for this because the driver is broken if that happens.
That's something like page-flipping with alternating BO's and shadow buffering?
You really want a cursor plane to hold this information.
I briefly looked through vmwgfx and it has all these fail-able code in its atomic-update path. The patches here only make things worse. With cursor planes, you can do all the preparation in atomic_check and prepare_fb, and store the intermediate state/mappings/etc in the plane state.
The ast driver started with a design like this one here and then we moved it to cursor planes. Ast has now none of the mentioned problems. Relevant code is at [1][2].
Yea, I was hoping to the the cursor mob's first and then go back and refactor the error paths for all cursor modes. I do agree that it's not the cleanest approach because it leaves us in a bit broken state until the refactor lands. I'll take out the cursor mob change from v2 of this patchset to give Martin some time to clean up the patch a bit. I'll probably send that out as a separate "cursor mob and atomic errors refactor/fixes" patchset later. Thanks for the review!
z
dri-devel@lists.freedesktop.org