From: Zack Rusin zackr@vmware.com
Series finishes 3D support on arm64 with vmwgfx. With this and changes that add svga3 pci id's to Mesa3D - OpenGL 4.3 and GLES 3.1 work smoothly on arm64.
Most changes are not svga3 specific but rather could be classified as generic improvements. That's in particular true for support for curso mobs which enable large cursor support on both svga2 and svga3 and fixing initialization of drm_mode_fb_cmd2 struct.
Martin Krastev (1): drm/vmwgfx: Add support for CursorMob and CursorBypass 4
Zack Rusin (7): drm/vmwgfx: Cleanup multimon initialization code drm/vmwgfx: Print capabilities early during the initialization drm/vmwgfx: Fix fencing on SVGAv3 drm/vmwgfx: Allow querying of the SVGA PCI id from the userspace drm/vmwgfx: Initialize drm_mode_fb_cmd2 drm/vmwgfx: Implement MSI/MSI-X support for IRQs drm/vmwgfx: Stop using surface dma commands on most configurations
drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 20 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 23 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 28 +- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 27 +- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 80 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 407 +++++++++++++++++++++----- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 28 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 36 ++- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 17 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 27 +- include/uapi/drm/vmwgfx_drm.h | 9 +- 13 files changed, 538 insertions(+), 168 deletions(-)
From: Martin Krastev krastevm@vmware.com
* Add support for CursorMob * Add support for CursorBypass 4 * Refactor vmw_du_cursor_plane_atomic_update to be kms-helper-atomic -- move BO mappings to vmw_du_cursor_plane_prepare_fb -- move BO unmappings to vmw_du_cursor_plane_cleanup_fb
Cursor mobs are a new svga feature which enables support for large cursors, e.g. large accessibility cursor on platforms with vmwgfx. It also cleans up the cursor code and makes it more uniform with the rest of modern guest backed objects support.
Signed-off-by: Martin Krastev krastevm@vmware.com Reviewed-by: Zack Rusin zackr@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com Signed-off-by: Zack Rusin zackr@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 399 ++++++++++++++++++++++----- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 28 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 18 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 17 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 16 +- 7 files changed, 382 insertions(+), 104 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 26eb5478394a..621231c66fd4 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-2022 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 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index ea3ecdda561d..780da6147cf9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright 2009-2021 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2022 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 @@ -101,6 +101,7 @@ struct vmw_fpriv { * struct vmw_buffer_object - TTM buffer object with vmwgfx additions * @base: The TTM buffer object * @res_tree: RB tree of resources using this buffer object as a backing MOB + * @base_mapped_count: ttm BO mapping count; used by KMS atomic helpers. * @cpu_writers: Number of synccpu write grabs. Protected by reservation when * increased. May be decreased without reservation. * @dx_query_ctx: DX context if this buffer object is used as a DX query MOB @@ -111,6 +112,9 @@ struct vmw_fpriv { struct vmw_buffer_object { struct ttm_buffer_object base; struct rb_root res_tree; + /* For KMS atomic helpers: ttm bo mapping count */ + atomic_t base_mapped_count; + atomic_t cpu_writers; /* Not ref-counted. Protected by binding_mutex */ struct vmw_resource *dx_query_ctx; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bbd2f4ec08ec..9d82a7b49aed 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-2022 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 @@ -41,7 +41,7 @@ void vmw_du_cleanup(struct vmw_display_unit *du) struct vmw_private *dev_priv = vmw_priv(du->primary.dev); drm_plane_cleanup(&du->primary); if (vmw_cmd_supported(dev_priv)) - drm_plane_cleanup(&du->cursor); + drm_plane_cleanup(&du->cursor.base);
drm_connector_unregister(&du->connector); drm_crtc_cleanup(&du->crtc); @@ -53,23 +53,43 @@ void vmw_du_cleanup(struct vmw_display_unit *du) * Display Unit Cursor functions */
-static int vmw_cursor_update_image(struct vmw_private *dev_priv, - u32 *image, u32 width, u32 height, - u32 hotspotX, u32 hotspotY) +static void vmw_cursor_update_mob(struct vmw_private *dev_priv, + struct ttm_buffer_object *bo, + struct ttm_bo_kmap_obj *map, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY); + +struct vmw_svga_fifo_cmd_define_cursor { + u32 cmd; + SVGAFifoCmdDefineAlphaCursor cursor; +}; + +static void vmw_cursor_update_image(struct vmw_private *dev_priv, + struct ttm_buffer_object *cm_bo, + struct ttm_bo_kmap_obj *cm_map, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY) { - struct { - u32 cmd; - SVGAFifoCmdDefineAlphaCursor cursor; - } *cmd; - u32 image_size = width * height * 4; - u32 cmd_size = sizeof(*cmd) + image_size; + struct vmw_svga_fifo_cmd_define_cursor *cmd; + const u32 image_size = width * height * sizeof(*image); + const u32 cmd_size = sizeof(*cmd) + image_size;
- if (!image) - return -EINVAL; + if (cm_bo != NULL) { + vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image, + width, height, + hotspotX, hotspotY); + return; + }
+ /* Try to reserve fifocmd space and swallow any failures; + such reservations cannot be left unconsumed for long + under the risk of clogging other fifocmd users, so + we treat reservations separtely from the way we treat + other fallible KMS-atomic resources at prepare_fb */ cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); + if (unlikely(cmd == NULL)) - return -ENOMEM; + return;
memset(cmd, 0, sizeof(*cmd));
@@ -83,55 +103,158 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv, cmd->cursor.hotspotY = hotspotY;
vmw_cmd_commit_flush(dev_priv, cmd_size); - - return 0; }
-static int vmw_cursor_update_bo(struct vmw_private *dev_priv, - struct vmw_buffer_object *bo, - u32 width, u32 height, - u32 hotspotX, u32 hotspotY) -{ - struct ttm_bo_kmap_obj map; - unsigned long kmap_offset; - unsigned long kmap_num; - void *virtual; +/** + * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism + * + * @dev_priv: device to work with + * @bo: BO for the MOB + * @map: kmap obj for the BO + * @image: cursor source data to fill the MOB with + * @width: source data width + * @height: source data height + * @hotspotX: cursor hotspot x + * @hotspotY: cursor hotspot Y + */ +static void vmw_cursor_update_mob(struct vmw_private *dev_priv, + struct ttm_buffer_object *bo, + struct ttm_bo_kmap_obj *map, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + SVGAGBCursorHeader *header; + SVGAGBAlphaCursorHeader *alpha_header; + const u32 image_size = width * height * sizeof(*image); bool dummy; - int ret;
- kmap_offset = 0; - kmap_num = PFN_UP(width*height*4); + BUG_ON(!image);
- ret = ttm_bo_reserve(&bo->base, true, false, NULL); - if (unlikely(ret != 0)) { - DRM_ERROR("reserve failed\n"); - return -EINVAL; + 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); + + vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start); +} + +void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) { + if (vcp->cursor_mob[i] != NULL) { + ttm_bo_unpin(vcp->cursor_mob[i]); + ttm_bo_put(vcp->cursor_mob[i]); + kfree(vcp->cursor_mob[i]); + vcp->cursor_mob[i] = NULL; + } } +}
- ret = ttm_bo_kmap(&bo->base, kmap_offset, kmap_num, &map); - if (unlikely(ret != 0)) - goto err_unreserve; +#define CURSOR_MOB_SIZE(dimension) \ + ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader))
- virtual = ttm_kmap_obj_virtual(&map, &dummy); - ret = vmw_cursor_update_image(dev_priv, virtual, width, height, - hotspotX, hotspotY); +int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor) +{ + struct vmw_private *dev_priv = cursor->base.dev->dev_private; + uint32_t cursor_max_dim, mob_max_size; + int ret = 0; + size_t i;
- ttm_bo_kunmap(&map); -err_unreserve: - ttm_bo_unreserve(&bo->base); + if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) + return -ENOSYS; + + mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); + cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); + + if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size) + cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */ + + for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) { + struct ttm_buffer_object **const bo = &cursor->cursor_mob[i]; + + ret = vmw_bo_create_kernel(dev_priv, + CURSOR_MOB_SIZE(cursor_max_dim), + &vmw_mob_placement, bo); + + if (ret != 0) + goto teardown; + + if ((*bo)->resource->mem_type != VMW_PL_MOB) { + DRM_ERROR("Obtained buffer object is not a MOB.\n"); + ret = -ENOSYS; + goto teardown; + } + + /* Fence the mob creation so we are guarateed to have the mob */ + ret = ttm_bo_reserve(*bo, false, false, NULL); + + if (ret != 0) + goto teardown; + + vmw_bo_fence_single(*bo, NULL); + + ttm_bo_unreserve(*bo); + + drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n", + (*bo)->resource->start, cursor_max_dim); + } + + return 0; + +teardown: + vmw_du_destroy_cursor_mob_array(cursor);
return ret; }
+#undef CURSOR_MOB_SIZE + +static void vmw_cursor_update_bo(struct vmw_private *dev_priv, + struct ttm_buffer_object *cm_bo, + struct ttm_bo_kmap_obj *cm_map, + struct vmw_buffer_object *bo, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + void *virtual; + bool dummy; + + virtual = ttm_kmap_obj_virtual(&bo->map, &dummy); + if (virtual) { + vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual, + width, height, + hotspotX, hotspotY); + atomic_dec(&bo->base_mapped_count); + } +} +
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_SCREEN_ID, SVGA3D_INVALID_ID); + 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 +262,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); } @@ -269,7 +392,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) continue;
du->cursor_age = du->cursor_surface->snooper.age; - vmw_cursor_update_image(dev_priv, + vmw_cursor_update_image(dev_priv, NULL, NULL, du->cursor_surface->snooper.image, 64, 64, du->hotspot_x + du->core_hotspot_x, @@ -283,7 +406,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) void vmw_du_cursor_plane_destroy(struct drm_plane *plane) { vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0); - + vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane)); drm_plane_cleanup(plane); }
@@ -321,7 +444,7 @@ void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
/** - * vmw_du_plane_cleanup_fb - Unpins the cursor + * vmw_du_plane_cleanup_fb - Unpins the plane surface * * @plane: display plane * @old_state: Contains the FB to clean up @@ -340,6 +463,55 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane, }
+/** + * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface + * + * @plane: cursor plane + * @old_state: contains the state to clean up + * + * Unmaps all cursor bo mappings and unpins the cursor surface + * + * Returns 0 on success + */ +void +vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); + bool dummy; + + if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { + const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); + + if (likely(ret == 0)) { + if (atomic_read(&vps->bo->base_mapped_count) == 0) + ttm_bo_kunmap(&vps->bo->map); + ttm_bo_unreserve(&vps->bo->base); + } + } + + if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) { + const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL); + + if (likely(ret == 0)) { + ttm_bo_kunmap(&vps->cm_map); + ttm_bo_unreserve(vps->cm_bo); + } + } + + vmw_du_plane_unpin_surf(vps, false); + + if (vps->surf) { + vmw_surface_unreference(&vps->surf); + vps->surf = NULL; + } + + if (vps->bo) { + vmw_bo_unreference(&vps->bo); + vps->bo = NULL; + } +} + /** * vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it * @@ -353,14 +525,21 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { struct drm_framebuffer *fb = new_state->fb; + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); + struct ttm_buffer_object *cm_bo = NULL; + bool dummy; + int ret = 0;
- - if (vps->surf) + if (vps->surf) { vmw_surface_unreference(&vps->surf); + vps->surf = NULL; + }
- if (vps->bo) + if (vps->bo) { vmw_bo_unreference(&vps->bo); + vps->bo = NULL; + }
if (fb) { if (vmw_framebuffer_to_vfb(fb)->bo) { @@ -372,7 +551,82 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, } }
+ vps->cm_bo = NULL; + + if (vps->surf == NULL && vps->bo != NULL) { + const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); + + /* Not using vmw_bo_map_and_cache() helper here as we need to reserve + the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */ + ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); + + if (unlikely(ret != 0)) + return -ENOMEM; + + ret = ttm_bo_kmap(&vps->bo->base, 0, PFN_UP(size), &vps->bo->map); + + if (likely(ret == 0)) + atomic_inc(&vps->bo->base_mapped_count); + + ttm_bo_unreserve(&vps->bo->base); + + if (unlikely(ret != 0)) + return -ENOMEM; + } + + if (vps->surf || vps->bo) { + unsigned cursor_mob_idx = vps->cursor_mob_idx; + + /* Lazily set up cursor MOBs just once -- no reattempts. */ + if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL) + if (vmw_du_create_cursor_mob_array(vcp) != 0) + vps->cursor_mob_idx = cursor_mob_idx = -1U; + + if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) { + const u32 size = sizeof(SVGAGBCursorHeader) + + new_state->crtc_w * new_state->crtc_h * sizeof(u32); + + cm_bo = vcp->cursor_mob[cursor_mob_idx]; + + if (cm_bo->resource->num_pages * PAGE_SIZE < size) { + ret = -EINVAL; + goto error_bo_unmap; + } + + ret = ttm_bo_reserve(cm_bo, false, false, NULL); + + if (unlikely(ret != 0)) { + ret = -ENOMEM; + goto error_bo_unmap; + } + + ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map); + + ttm_bo_unreserve(cm_bo); + + if (unlikely(ret != 0)) { + ret = -ENOMEM; + goto error_bo_unmap; + } + + vps->cursor_mob_idx = cursor_mob_idx ^ 1; + vps->cm_bo = cm_bo; + } + } + return 0; + +error_bo_unmap: + if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { + const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); + if (likely(ret == 0)) { + atomic_dec(&vps->bo->base_mapped_count); + ttm_bo_kunmap(&vps->bo->map); + ttm_bo_unreserve(&vps->bo->base); + } + } + + return ret; }
@@ -389,8 +643,6 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); s32 hotspot_x, hotspot_y; - int ret = 0; -
hotspot_x = du->hotspot_x; hotspot_y = du->hotspot_y; @@ -406,33 +658,31 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age;
- ret = vmw_cursor_update_image(dev_priv, - vps->surf->snooper.image, - 64, 64, hotspot_x, - hotspot_y); + vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map, + vps->surf->snooper.image, + new_state->crtc_w, + new_state->crtc_h, + hotspot_x, hotspot_y); } else if (vps->bo) { - ret = vmw_cursor_update_bo(dev_priv, vps->bo, - new_state->crtc_w, - new_state->crtc_h, - hotspot_x, hotspot_y); + vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map, + vps->bo, + new_state->crtc_w, + new_state->crtc_h, + hotspot_x, hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); return; }
- if (!ret) { - du->cursor_x = new_state->crtc_x + du->set_gui_x; - du->cursor_y = new_state->crtc_y + du->set_gui_y; + du->cursor_x = new_state->crtc_x + du->set_gui_x; + du->cursor_y = new_state->crtc_y + du->set_gui_y;
- vmw_cursor_update_position(dev_priv, true, - du->cursor_x + hotspot_x, - du->cursor_y + hotspot_y); + vmw_cursor_update_position(dev_priv, true, + du->cursor_x + hotspot_x, + du->cursor_y + hotspot_y);
- du->core_hotspot_x = hotspot_x - du->hotspot_x; - du->core_hotspot_y = hotspot_y - du->hotspot_y; - } else { - DRM_ERROR("Failed to update cursor image\n"); - } + du->core_hotspot_x = hotspot_x - du->hotspot_x; + du->core_hotspot_y = hotspot_y - du->hotspot_y; }
@@ -518,7 +768,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", new_state->crtc_w, new_state->crtc_h); - ret = -EINVAL; + return -EINVAL; }
if (!vmw_framebuffer_to_vfb(fb)->bo) @@ -526,10 +776,10 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
if (surface && !surface->snooper.image) { DRM_ERROR("surface not suitable for cursor\n"); - ret = -EINVAL; + return -EINVAL; }
- return ret; + return 0; }
@@ -712,7 +962,6 @@ void vmw_du_plane_reset(struct drm_plane *plane) { struct vmw_plane_state *vps;
- if (plane->state) vmw_du_plane_destroy_state(plane, plane->state);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 4d36e8507380..c95be95deb8d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2022 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 @@ -261,6 +261,7 @@ static const uint32_t __maybe_unused vmw_cursor_plane_formats[] = { #define vmw_plane_state_to_vps(x) container_of(x, struct vmw_plane_state, base) #define vmw_connector_state_to_vcs(x) \ container_of(x, struct vmw_connector_state, base) +#define vmw_plane_to_vcp(x) container_of(x, struct vmw_cursor_plane, base)
/** * Derived class for crtc state object @@ -293,6 +294,14 @@ struct vmw_plane_state {
/* For CPU Blit */ unsigned int cpp; + + /* CursorMob flipping index; -1 if cursor mobs not used */ + unsigned int cursor_mob_idx; + /* Currently-active CursorMob */ + struct ttm_buffer_object *cm_bo; + /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update + IFF currently-active CursorMob above is valid */ + struct ttm_bo_kmap_obj cm_map; };
@@ -325,6 +334,17 @@ struct vmw_connector_state { int gui_y; };
+/** + * Derived class for cursor plane object + * + * @base DRM plane object + * @cursor_mob array of two MOBs for CursorMob flipping + */ +struct vmw_cursor_plane { + struct drm_plane base; + struct ttm_buffer_object *cursor_mob[2]; +}; + /** * Base class display unit. * @@ -337,7 +357,7 @@ struct vmw_display_unit { struct drm_encoder encoder; struct drm_connector connector; struct drm_plane primary; - struct drm_plane cursor; + struct vmw_cursor_plane cursor;
struct vmw_surface *cursor_surface; struct vmw_buffer_object *cursor_bo; @@ -452,6 +472,8 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); /* Universal Plane Helpers */ void vmw_du_primary_plane_destroy(struct drm_plane *plane); void vmw_du_cursor_plane_destroy(struct drm_plane *plane); +int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp); +void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
/* Atomic Helpers */ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, @@ -462,6 +484,8 @@ void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state); int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state); +void vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); void vmw_du_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state); void vmw_du_plane_reset(struct drm_plane *plane); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index fb58a71c458f..643c1608ddfd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2022 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 @@ -338,7 +338,7 @@ drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = { .atomic_check = vmw_du_cursor_plane_atomic_check, .atomic_update = vmw_du_cursor_plane_atomic_update, .prepare_fb = vmw_du_cursor_plane_prepare_fb, - .cleanup_fb = vmw_du_plane_cleanup_fb, + .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, };
static const struct @@ -363,7 +363,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_plane *primary, *cursor; + struct drm_plane *primary; + struct vmw_cursor_plane *cursor; struct drm_crtc *crtc; int ret;
@@ -392,7 +393,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) ldu->base.is_implicit = true;
/* Initialize primary plane */ - ret = drm_universal_plane_init(dev, &ldu->base.primary, + ret = drm_universal_plane_init(dev, primary, 0, &vmw_ldu_plane_funcs, vmw_primary_plane_formats, ARRAY_SIZE(vmw_primary_plane_formats), @@ -409,7 +410,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) */ if (vmw_cmd_supported(dev_priv)) { /* Initialize cursor plane */ - ret = drm_universal_plane_init(dev, &ldu->base.cursor, + ret = drm_universal_plane_init(dev, &cursor->base, 0, &vmw_ldu_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), @@ -420,7 +421,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free; }
- drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs); + drm_plane_helper_add(&cursor->base, &vmw_ldu_cursor_plane_helper_funcs); }
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, @@ -450,9 +451,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_encoder; }
- ret = drm_crtc_init_with_planes( - dev, crtc, &ldu->base.primary, - vmw_cmd_supported(dev_priv) ? &ldu->base.cursor : NULL, + ret = drm_crtc_init_with_planes(dev, crtc, primary, + vmw_cmd_supported(dev_priv) ? &cursor->base : NULL, &vmw_legacy_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 3004c7a719e9..c89ad3a2d141 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2011-2022 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 @@ -804,7 +804,7 @@ drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = { .atomic_check = vmw_du_cursor_plane_atomic_check, .atomic_update = vmw_du_cursor_plane_atomic_update, .prepare_fb = vmw_du_cursor_plane_prepare_fb, - .cleanup_fb = vmw_du_plane_cleanup_fb, + .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, };
static const struct @@ -832,7 +832,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_plane *primary, *cursor; + struct drm_plane *primary; + struct vmw_cursor_plane *cursor; struct drm_crtc *crtc; int ret;
@@ -859,7 +860,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) sou->base.is_implicit = false;
/* Initialize primary plane */ - ret = drm_universal_plane_init(dev, &sou->base.primary, + ret = drm_universal_plane_init(dev, primary, 0, &vmw_sou_plane_funcs, vmw_primary_plane_formats, ARRAY_SIZE(vmw_primary_plane_formats), @@ -873,7 +874,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */ - ret = drm_universal_plane_init(dev, &sou->base.cursor, + ret = drm_universal_plane_init(dev, &cursor->base, 0, &vmw_sou_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), @@ -884,7 +885,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) goto err_free; }
- drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs); + drm_plane_helper_add(&cursor->base, &vmw_sou_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -913,8 +914,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_encoder; }
- ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary, - &sou->base.cursor, + ret = drm_crtc_init_with_planes(dev, crtc, primary, + &cursor->base, &vmw_screen_object_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ae9a6044d448..42b5ecb0c5e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /****************************************************************************** * - * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA + * COPYRIGHT (C) 2014-2022 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 @@ -1685,7 +1685,7 @@ drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = { .atomic_check = vmw_du_cursor_plane_atomic_check, .atomic_update = vmw_du_cursor_plane_atomic_update, .prepare_fb = vmw_du_cursor_plane_prepare_fb, - .cleanup_fb = vmw_du_plane_cleanup_fb, + .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, };
static const struct @@ -1723,11 +1723,11 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_plane *primary, *cursor; + struct drm_plane *primary; + struct vmw_cursor_plane *cursor; struct drm_crtc *crtc; int ret;
- stdu = kzalloc(sizeof(*stdu), GFP_KERNEL); if (!stdu) return -ENOMEM; @@ -1759,7 +1759,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) drm_plane_enable_fb_damage_clips(primary);
/* Initialize cursor plane */ - ret = drm_universal_plane_init(dev, cursor, + ret = drm_universal_plane_init(dev, &cursor->base, 0, &vmw_stdu_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), @@ -1770,7 +1770,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free; }
- drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs); + drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs);
ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -1799,8 +1799,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_encoder; }
- ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary, - &stdu->base.cursor, + ret = drm_crtc_init_with_planes(dev, crtc, primary, + &cursor->base, &vmw_stdu_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n");
From: Zack Rusin zackr@vmware.com
The results of the legacy display unit initialization were being silently ignored. Unifying the selection of number of display units based on whether the underlying device supports multimon makes it easier to add error checking to all paths.
This makes the driver report the errors in ldu initialization paths and try to recover from them.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 643c1608ddfd..e4347faccee0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -492,6 +492,8 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; int i, ret; + int num_display_units = (dev_priv->capabilities & SVGA_CAP_MULTIMON) ? + VMWGFX_NUM_DISPLAY_UNITS : 1;
if (unlikely(dev_priv->ldu_priv)) { return -EINVAL; @@ -506,21 +508,17 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) dev_priv->ldu_priv->last_num_active = 0; dev_priv->ldu_priv->fb = NULL;
- /* for old hardware without multimon only enable one display */ - if (dev_priv->capabilities & SVGA_CAP_MULTIMON) - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); - else - ret = drm_vblank_init(dev, 1); + ret = drm_vblank_init(dev, num_display_units); if (ret != 0) goto err_free;
vmw_kms_create_implicit_placement_property(dev_priv);
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON) - for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) - vmw_ldu_init(dev_priv, i); - else - vmw_ldu_init(dev_priv, 0); + for (i = 0; i < num_display_units; ++i) { + ret = vmw_ldu_init(dev_priv, i); + if (ret != 0) + goto err_free; + }
dev_priv->active_display_unit = vmw_du_legacy;
From: Zack Rusin zackr@vmware.com
Capabilities were logged at the end of initialization so any early errors would make them not appear in the logs. Which is also when they're needed the most. Print the the capabilities right after fetching them, before the init code starts using them to make sure they always show up in the logs.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 621231c66fd4..f43afd56915e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -848,12 +848,16 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); - + vmw_print_bitmap(&dev_priv->drm, "Capabilities", + dev_priv->capabilities, + cap1_names, ARRAY_SIZE(cap1_names)); if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) { dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2); + vmw_print_bitmap(&dev_priv->drm, "Capabilities2", + dev_priv->capabilities2, + cap2_names, ARRAY_SIZE(cap2_names)); }
- ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { drm_info(&dev_priv->drm, @@ -939,14 +943,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) "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_bitmap(&dev_priv->drm, "Capabilities", - dev_priv->capabilities, - cap1_names, ARRAY_SIZE(cap1_names)); - if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) - vmw_print_bitmap(&dev_priv->drm, "Capabilities2", - dev_priv->capabilities2, - cap2_names, ARRAY_SIZE(cap2_names)); - ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) goto out_err0;
From: Zack Rusin zackr@vmware.com
Port of the vmwgfx to SVGAv3 lacked support for fencing. SVGAv3 removed FIFO's and replaced them with command buffers and extra registers. The initial version of SVGAv3 lacked support for most advanced features (e.g. 3D) which made fences unnecessary. That is no longer the case, especially as 3D support is being turned on.
Switch from FIFO commands and capabilities to command buffers and extra registers to enable fences on SVGAv3.
Fixes: 2cd80dbd3551 ("drm/vmwgfx: Add basic support for SVGA3") Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 8 ++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 28 ++++++++++++++++++++------- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 26 +++++++++++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 8 +++++--- 5 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c index a3bfbb6c3e14..bf1b394753da 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c @@ -528,7 +528,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) *seqno = atomic_add_return(1, &dev_priv->marker_seq); } while (*seqno == 0);
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) { + if (!vmw_has_fences(dev_priv)) {
/* * Don't request hardware to send a fence. The diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 780da6147cf9..12eb4de41036 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1683,4 +1683,12 @@ static inline void vmw_irq_status_write(struct vmw_private *vmw, outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT); }
+static inline bool vmw_has_fences(struct vmw_private *vmw) +{ + if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS | + SVGA_CAP_CMD_BUFFERS_2)) != 0) + return true; + return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0; +} + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 59d6a2dd4c2e..66cc35dc223e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -82,6 +82,22 @@ fman_from_fence(struct vmw_fence_obj *fence) return container_of(fence->base.lock, struct vmw_fence_manager, lock); }
+static u32 vmw_fence_goal_read(struct vmw_private *vmw) +{ + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) + return vmw_read(vmw, SVGA_REG_FENCE_GOAL); + else + return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL); +} + +static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value) +{ + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) + vmw_write(vmw, SVGA_REG_FENCE_GOAL, value); + else + vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value); +} + /* * Note on fencing subsystem usage of irqs: * Typically the vmw_fences_update function is called @@ -392,7 +408,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, if (likely(!fman->seqno_valid)) return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL); + goal_seqno = vmw_fence_goal_read(fman->dev_priv); if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP)) return false;
@@ -400,9 +416,8 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, list_for_each_entry(fence, &fman->fence_list, head) { if (!list_empty(&fence->seq_passed_actions)) { fman->seqno_valid = true; - vmw_fifo_mem_write(fman->dev_priv, - SVGA_FIFO_FENCE_GOAL, - fence->base.seqno); + vmw_fence_goal_write(fman->dev_priv, + fence->base.seqno); break; } } @@ -434,13 +449,12 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence) if (dma_fence_is_signaled_locked(&fence->base)) return false;
- goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL); + goal_seqno = vmw_fence_goal_read(fman->dev_priv); if (likely(fman->seqno_valid && goal_seqno - fence->base.seqno < VMW_FENCE_WRAP)) return false;
- vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL, - fence->base.seqno); + vmw_fence_goal_write(fman->dev_priv, fence->base.seqno); fman->seqno_valid = true;
return true; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index c5191de365ca..fe4732bf2c9d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -32,6 +32,14 @@
#define VMW_FENCE_WRAP (1 << 24)
+static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw) +{ + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) + return SVGA_IRQFLAG_REG_FENCE_GOAL; + else + return SVGA_IRQFLAG_FENCE_GOAL; +} + /** * vmw_thread_fn - Deferred (process context) irq handler * @@ -96,7 +104,7 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg) wake_up_all(&dev_priv->fifo_queue);
if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE | - SVGA_IRQFLAG_FENCE_GOAL)) && + vmw_irqflag_fence_goal(dev_priv))) && !test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending)) ret = IRQ_WAKE_THREAD;
@@ -137,8 +145,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv, if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return true;
- if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) && - vmw_fifo_idle(dev_priv, seqno)) + if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno)) return true;
/** @@ -160,6 +167,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, unsigned long timeout) { struct vmw_fifo_state *fifo_state = dev_priv->fifo; + bool fifo_down = false;
uint32_t count = 0; uint32_t signal_seq; @@ -176,12 +184,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, */
if (fifo_idle) { - down_read(&fifo_state->rwsem); if (dev_priv->cman) { ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible, 10*HZ); if (ret) goto out_err; + } else if (fifo_state) { + down_read(&fifo_state->rwsem); + fifo_down = true; } }
@@ -218,12 +228,12 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, } } finish_wait(&dev_priv->fence_queue, &__wait); - if (ret == 0 && fifo_idle) + if (ret == 0 && fifo_idle && fifo_state) vmw_fence_write(dev_priv, signal_seq);
wake_up_all(&dev_priv->fence_queue); out_err: - if (fifo_idle) + if (fifo_down) up_read(&fifo_state->rwsem);
return ret; @@ -266,13 +276,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
void vmw_goal_waiter_add(struct vmw_private *dev_priv) { - vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, + vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv), &dev_priv->goal_queue_waiters); }
void vmw_goal_waiter_remove(struct vmw_private *dev_priv) { - vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, + vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv), &dev_priv->goal_queue_waiters); }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9d82a7b49aed..af252210ef84 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1593,7 +1593,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv, ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, mode_cmd, is_bo_proxy); - /* * vmw_create_bo_proxy() adds a reference that is no longer * needed @@ -1634,13 +1633,16 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, ret = vmw_user_lookup_handle(dev_priv, file_priv, mode_cmd->handles[0], &surface, &bo); - if (ret) + if (ret) { + DRM_ERROR("Invalid buffer object handle %u (0x%x).\n", + mode_cmd->handles[0], mode_cmd->handles[0]); goto err_out; + }
if (!bo && !vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) { - DRM_ERROR("Surface size cannot exceed %dx%d", + DRM_ERROR("Surface size cannot exceed %dx%d\n", dev_priv->texture_max_width, dev_priv->texture_max_height); goto err_out;
From: Zack Rusin zackr@vmware.com
Mesa3D loaders require knowledge of the devices PCI id. SVGAv2 and v3 have different PCI id's, but the same driver is used to handle them both. To allow Mesa3D svga driver to be loaded automatically for both SVGAv2 and SVGAv3 make the kernel return the PCI id of the currently running device.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 27 +++++++++++++++------------ include/uapi/drm/vmwgfx_drm.h | 9 ++++++++- 2 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 471da2b4c177..a1da5678c731 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2022 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 @@ -27,9 +27,11 @@
#include "vmwgfx_drv.h" #include "vmwgfx_devcaps.h" -#include <drm/vmwgfx_drm.h> #include "vmwgfx_kms.h"
+#include <drm/vmwgfx_drm.h> +#include <linux/pci.h> + int vmw_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -62,17 +64,15 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, break; case DRM_VMW_PARAM_FIFO_HW_VERSION: { - if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { + if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) param->value = SVGA3D_HWVERSION_WS8_B1; - break; - } - - param->value = - vmw_fifo_mem_read(dev_priv, - ((vmw_fifo_caps(dev_priv) & - SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? - SVGA_FIFO_3D_HWVERSION_REVISED : - SVGA_FIFO_3D_HWVERSION)); + else + param->value = vmw_fifo_mem_read( + dev_priv, + ((vmw_fifo_caps(dev_priv) & + SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? + SVGA_FIFO_3D_HWVERSION_REVISED : + SVGA_FIFO_3D_HWVERSION)); break; } case DRM_VMW_PARAM_MAX_SURF_MEMORY: @@ -108,6 +108,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_GL43: param->value = has_gl43_context(dev_priv); break; + case DRM_VMW_PARAM_DEVICE_ID: + param->value = to_pci_dev(dev_priv->drm.dev)->device; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 8277644c1144..26549c86a91f 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2022 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -92,6 +92,12 @@ extern "C" { * * DRM_VMW_PARAM_SM5 * SM5 support is enabled. + * + * DRM_VMW_PARAM_GL43 + * SM5.1+GL4.3 support is enabled. + * + * DRM_VMW_PARAM_DEVICE_ID + * PCI ID of the underlying SVGA device. */
#define DRM_VMW_PARAM_NUM_STREAMS 0 @@ -111,6 +117,7 @@ extern "C" { #define DRM_VMW_PARAM_SM4_1 14 #define DRM_VMW_PARAM_SM5 15 #define DRM_VMW_PARAM_GL43 16 +#define DRM_VMW_PARAM_DEVICE_ID 17
/** * enum drm_vmw_handle_type - handle type for ref ioctls
From: Zack Rusin zackr@vmware.com
Transition to drm_mode_fb_cmd2 from drm_mode_fb_cmd left the structure unitialized. drm_mode_fb_cmd2 adds a few additional members, e.g. flags and modifiers which were never initialized. Garbage in those members can cause random failures during the bringup of the fbcon.
Initializing the structure fixes random blank screens after bootup due to flags/modifiers mismatches during the fbcon bring up.
Fixes: dabdcdc9822a ("drm/vmwgfx: Switch to mode_cmd2") Signed-off-by: Zack Rusin zackr@vmware.com Cc: Daniel Vetter daniel.vetter@intel.com Cc: stable@vger.kernel.org # v4.10+ Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 8ee34576c7d0..adf17c740656 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -483,7 +483,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
static int vmw_fb_kms_framebuffer(struct fb_info *info) { - struct drm_mode_fb_cmd2 mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd = {0}; struct vmw_fb_par *par = info->par; struct fb_var_screeninfo *var = &info->var; struct drm_framebuffer *cur_fb;
From: Zack Rusin zackr@vmware.com
SVGAv3 deprecates legacy interrupts and adds support for MSI/MSI-X. With MSI the driver visible side remains largely unchanged but with MSI-X each interrupt gets delivered on its own vector.
Add support for MSI/MSI-X while preserving the old functionality for SVGAv2. Code between the SVGAv2 and SVGAv3 is exactly the same, only the number of available vectors changes, in particular between legacy and MSI-X interrupts.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 54 +++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f43afd56915e..791f9a5f3868 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -980,7 +980,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) }
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { - ret = vmw_irq_install(&dev_priv->drm, pdev->irq); + ret = vmw_irq_install(dev_priv); if (ret != 0) { drm_err(&dev_priv->drm, "Failed installing irq: %d\n", ret); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 12eb4de41036..be19aa6e1f13 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -65,6 +65,11 @@ #define VMWGFX_PCI_ID_SVGA2 0x0405 #define VMWGFX_PCI_ID_SVGA3 0x0406
+/* + * This has to match get_count_order(SVGA_IRQFLAG_MAX) + */ +#define VMWGFX_MAX_NUM_IRQS 6 + /* * Perhaps we should have sysfs entries for these. */ @@ -532,6 +537,8 @@ struct vmw_private { bool has_mob; spinlock_t hw_lock; bool assume_16bpp; + u32 irqs[VMWGFX_MAX_NUM_IRQS]; + u32 num_irq_vectors;
enum vmw_sm_type sm_type;
@@ -1158,7 +1165,7 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd); * IRQs and wating - vmwgfx_irq.c */
-extern int vmw_irq_install(struct drm_device *dev, int irq); +extern int vmw_irq_install(struct vmw_private *dev_priv); extern void vmw_irq_uninstall(struct drm_device *dev); extern bool vmw_seqno_passed(struct vmw_private *dev_priv, uint32_t seqno); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index fe4732bf2c9d..482989b1f211 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -300,6 +300,7 @@ void vmw_irq_uninstall(struct drm_device *dev) struct vmw_private *dev_priv = vmw_priv(dev); struct pci_dev *pdev = to_pci_dev(dev->dev); uint32_t status; + u32 i;
if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return; @@ -309,20 +310,61 @@ void vmw_irq_uninstall(struct drm_device *dev) status = vmw_irq_status_read(dev_priv); vmw_irq_status_write(dev_priv, status);
- free_irq(pdev->irq, dev); + for (i = 0; i < dev_priv->num_irq_vectors; ++i) + free_irq(dev_priv->irqs[i], dev); + + pci_free_irq_vectors(pdev); + dev_priv->num_irq_vectors = 0; }
/** * vmw_irq_install - Install the irq handlers * - * @dev: Pointer to the drm device. - * @irq: The irq number. + * @dev_priv: Pointer to the vmw_private device. * Return: Zero if successful. Negative number otherwise. */ -int vmw_irq_install(struct drm_device *dev, int irq) +int vmw_irq_install(struct vmw_private *dev_priv) { + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct drm_device *dev = &dev_priv->drm; + int ret; + int nvec; + int i = 0; + + BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1); + BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX)); + + nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS, + PCI_IRQ_ALL_TYPES); + + if (nvec <= 0) { + drm_err(&dev_priv->drm, + "IRQ's are unavailable, nvec: %d\n", nvec); + goto done; + } + vmw_irq_preinstall(dev);
- return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn, - IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); + for (i = 0; i < nvec; ++i) { + ret = pci_irq_vector(pdev, i); + if (ret < 0) { + drm_err(&dev_priv->drm, + "failed getting irq vector: %d\n", ret); + goto done; + } + dev_priv->irqs[i] = ret; + + ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn, + IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); + if (ret != 0) { + drm_err(&dev_priv->drm, + "Failed installing irq(%d): %d\n", + dev_priv->irqs[i], ret); + goto done; + } + } + +done: + dev_priv->num_irq_vectors = i; + return ret; }
Hi Zack,
I love your patch! Perhaps something to improve:
[auto build test WARNING on drm/drm-next] [also build test WARNING on drm-intel/for-linux-next drm-tip/drm-tip drm-exynos/exynos-drm-next tegra-drm/drm/tegra/for-next v5.17-rc6 next-20220302] [cannot apply to airlied/drm-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Zack-Rusin/drm-vmwgfx-3D-on-arm64-a... base: git://anongit.freedesktop.org/drm/drm drm-next config: i386-randconfig-a004 (https://download.01.org/0day-ci/archive/20220303/202203030802.itIYtJH1-lkp@i...) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project d271fc04d5b97b12e6b797c6067d3c96a8d7470e) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/63d27e1cb11562966a6f07bf0e667b0a54dc... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Zack-Rusin/drm-vmwgfx-3D-on-arm64-and-large-cursor-support/20220302-232641 git checkout 63d27e1cb11562966a6f07bf0e667b0a54dc2412 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/gpu/drm/vmwgfx/
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All warnings (new ones prefixed by >>):
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c:340:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
if (nvec <= 0) { ^~~~~~~~~ drivers/gpu/drm/vmwgfx/vmwgfx_irq.c:369:9: note: uninitialized use occurs here return ret; ^~~ drivers/gpu/drm/vmwgfx/vmwgfx_irq.c:340:2: note: remove the 'if' if its condition is always false if (nvec <= 0) { ^~~~~~~~~~~~~~~~ drivers/gpu/drm/vmwgfx/vmwgfx_irq.c:330:9: note: initialize the variable 'ret' to silence this warning int ret; ^ = 0 1 warning generated.
vim +340 drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
319 320 /** 321 * vmw_irq_install - Install the irq handlers 322 * 323 * @dev_priv: Pointer to the vmw_private device. 324 * Return: Zero if successful. Negative number otherwise. 325 */ 326 int vmw_irq_install(struct vmw_private *dev_priv) 327 { 328 struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 329 struct drm_device *dev = &dev_priv->drm; 330 int ret; 331 int nvec; 332 int i = 0; 333 334 BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1); 335 BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX)); 336 337 nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS, 338 PCI_IRQ_ALL_TYPES); 339
340 if (nvec <= 0) {
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
From: Zack Rusin zackr@vmware.com
SVGAv3 deprecates legacy interrupts and adds support for MSI/MSI-X. With MSI the driver visible side remains largely unchanged but with MSI-X each interrupt gets delivered on its own vector.
Add support for MSI/MSI-X while preserving the old functionality for SVGAv2. Code between the SVGAv2 and SVGAv3 is exactly the same, only the number of available vectors changes, in particular between legacy and MSI-X interrupts.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 55 +++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f43afd56915e..791f9a5f3868 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -980,7 +980,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) }
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { - ret = vmw_irq_install(&dev_priv->drm, pdev->irq); + ret = vmw_irq_install(dev_priv); if (ret != 0) { drm_err(&dev_priv->drm, "Failed installing irq: %d\n", ret); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 12eb4de41036..be19aa6e1f13 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -65,6 +65,11 @@ #define VMWGFX_PCI_ID_SVGA2 0x0405 #define VMWGFX_PCI_ID_SVGA3 0x0406
+/* + * This has to match get_count_order(SVGA_IRQFLAG_MAX) + */ +#define VMWGFX_MAX_NUM_IRQS 6 + /* * Perhaps we should have sysfs entries for these. */ @@ -532,6 +537,8 @@ struct vmw_private { bool has_mob; spinlock_t hw_lock; bool assume_16bpp; + u32 irqs[VMWGFX_MAX_NUM_IRQS]; + u32 num_irq_vectors;
enum vmw_sm_type sm_type;
@@ -1158,7 +1165,7 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd); * IRQs and wating - vmwgfx_irq.c */
-extern int vmw_irq_install(struct drm_device *dev, int irq); +extern int vmw_irq_install(struct vmw_private *dev_priv); extern void vmw_irq_uninstall(struct drm_device *dev); extern bool vmw_seqno_passed(struct vmw_private *dev_priv, uint32_t seqno); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index fe4732bf2c9d..086e69a130d4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -300,6 +300,7 @@ void vmw_irq_uninstall(struct drm_device *dev) struct vmw_private *dev_priv = vmw_priv(dev); struct pci_dev *pdev = to_pci_dev(dev->dev); uint32_t status; + u32 i;
if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return; @@ -309,20 +310,62 @@ void vmw_irq_uninstall(struct drm_device *dev) status = vmw_irq_status_read(dev_priv); vmw_irq_status_write(dev_priv, status);
- free_irq(pdev->irq, dev); + for (i = 0; i < dev_priv->num_irq_vectors; ++i) + free_irq(dev_priv->irqs[i], dev); + + pci_free_irq_vectors(pdev); + dev_priv->num_irq_vectors = 0; }
/** * vmw_irq_install - Install the irq handlers * - * @dev: Pointer to the drm device. - * @irq: The irq number. + * @dev_priv: Pointer to the vmw_private device. * Return: Zero if successful. Negative number otherwise. */ -int vmw_irq_install(struct drm_device *dev, int irq) +int vmw_irq_install(struct vmw_private *dev_priv) { + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct drm_device *dev = &dev_priv->drm; + int ret; + int nvec; + int i = 0; + + BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1); + BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX)); + + nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS, + PCI_IRQ_ALL_TYPES); + + if (nvec <= 0) { + drm_err(&dev_priv->drm, + "IRQ's are unavailable, nvec: %d\n", nvec); + ret = nvec; + goto done; + } + vmw_irq_preinstall(dev);
- return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn, - IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); + for (i = 0; i < nvec; ++i) { + ret = pci_irq_vector(pdev, i); + if (ret < 0) { + drm_err(&dev_priv->drm, + "failed getting irq vector: %d\n", ret); + goto done; + } + dev_priv->irqs[i] = ret; + + ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn, + IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); + if (ret != 0) { + drm_err(&dev_priv->drm, + "Failed installing irq(%d): %d\n", + dev_priv->irqs[i], ret); + goto done; + } + } + +done: + dev_priv->num_irq_vectors = i; + return ret; }
From: Zack Rusin zackr@vmware.com
Initial version of guest backed objects in the host had some performance issues that made using surface-dma's instead of direct copies faster. Surface dma's force a migration to vram which at best is slow and at worst is impossible (e.g. on svga3 where there's not enough vram to migrate fb's to it).
Slowly migrate away from surface dma's to direct copies by limiting their usage to systems with more than 32MB of vram.
Signed-off-by: Zack Rusin zackr@vmware.com Reviewed-by: Maaz Mombasawala mombasawalam@vmware.com Reviewed-by: Martin Krastev krastevm@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 42b5ecb0c5e9..eb014b97d156 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -138,6 +138,11 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); * Screen Target Display Unit CRTC Functions *****************************************************************************/
+static bool vmw_stdu_use_cpu_blit(const struct vmw_private *vmw) +{ + return !(vmw->capabilities & SVGA_CAP_3D) || vmw->vram_size < (32 * 1024 * 1024); +} +
/** * vmw_stdu_crtc_destroy - cleans up the STDU @@ -689,7 +694,7 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_stdu_dirty ddirty; int ret; - bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); + bool cpu_blit = vmw_stdu_use_cpu_blit(dev_priv); DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
/* @@ -1164,7 +1169,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, * so cache these mappings */ if (vps->content_fb_type == SEPARATE_BO && - !(dev_priv->capabilities & SVGA_CAP_3D)) + vmw_stdu_use_cpu_blit(dev_priv)) vps->cpp = new_fb->pitches[0] / new_fb->width;
return 0; @@ -1368,7 +1373,7 @@ static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, bo_update.base.vfb = vfb; bo_update.base.out_fence = out_fence; bo_update.base.mutex = NULL; - bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); + bo_update.base.cpu_blit = vmw_stdu_use_cpu_blit(dev_priv); bo_update.base.intr = false;
/*
dri-devel@lists.freedesktop.org