diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_drv.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 178 |
1 files changed, 93 insertions, 85 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9ad28346aff7..599052d07ae8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1,41 +1,23 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * 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 - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * **************************************************************************/ - #include "vmwgfx_drv.h" +#include "vmwgfx_bo.h" +#include "vmwgfx_binding.h" #include "vmwgfx_devcaps.h" #include "vmwgfx_mksstat.h" -#include "vmwgfx_binding.h" +#include "vmwgfx_vkms.h" #include "ttm_object.h" -#include <drm/drm_aperture.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_drv.h> -#include <drm/drm_fbdev_generic.h> +#include <drm/drm_fbdev_ttm.h> #include <drm/drm_gem_ttm_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_module.h> @@ -44,11 +26,17 @@ #include <drm/ttm/ttm_placement.h> #include <generated/utsrelease.h> +#ifdef CONFIG_X86 +#include <asm/hypervisor.h> +#endif + +#include <linux/aperture.h> #include <linux/cc_platform.h> #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/version.h> +#include <linux/vmalloc.h> #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" @@ -386,27 +374,29 @@ static void vmw_print_sm_type(struct vmw_private *dev_priv) static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { int ret; - struct vmw_buffer_object *vbo; + struct vmw_bo *vbo; struct ttm_bo_kmap_obj map; volatile SVGA3dQueryResult *result; bool dummy; + struct vmw_bo_params bo_params = { + .domain = VMW_BO_DOMAIN_SYS, + .busy_domain = VMW_BO_DOMAIN_SYS, + .bo_type = ttm_bo_type_kernel, + .size = PAGE_SIZE, + .pin = true, + .keep_resv = true, + }; /* * Create the vbo as pinned, so that a tryreserve will * immediately succeed. This is because we're the only * user of the bo currently. */ - ret = vmw_bo_create(dev_priv, PAGE_SIZE, - &vmw_sys_placement, false, true, - &vmw_bo_bo_free, &vbo); + ret = vmw_bo_create(dev_priv, &bo_params, &vbo); if (unlikely(ret != 0)) return ret; - ret = ttm_bo_reserve(&vbo->base, false, true, NULL); - BUG_ON(ret != 0); - vmw_bo_pin_reserved(vbo, true); - - ret = ttm_bo_kmap(&vbo->base, 0, 1, &map); + ret = ttm_bo_kmap(&vbo->tbo, 0, 1, &map); if (likely(ret == 0)) { result = ttm_kmap_obj_virtual(&map, &dummy); result->totalSize = sizeof(*result); @@ -415,7 +405,7 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) ttm_bo_kunmap(&map); } vmw_bo_pin_reserved(vbo, false); - ttm_bo_unreserve(&vbo->base); + ttm_bo_unreserve(&vbo->tbo); if (unlikely(ret != 0)) { DRM_ERROR("Dummy query buffer map failed.\n"); @@ -450,8 +440,10 @@ static int vmw_device_init(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1); } - dev_priv->last_read_seqno = vmw_fence_read(dev_priv); - atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); + u32 seqno = vmw_fence_read(dev_priv); + + atomic_set(&dev_priv->last_read_seqno, seqno); + atomic_set(&dev_priv->marker_seq, seqno); return 0; } @@ -464,7 +456,7 @@ static void vmw_device_fini(struct vmw_private *vmw) while (vmw_read(vmw, SVGA_REG_BUSY) != 0) ; - vmw->last_read_seqno = vmw_fence_read(vmw); + atomic_set(&vmw->last_read_seqno, vmw_fence_read(vmw)); vmw_write(vmw, SVGA_REG_CONFIG_DONE, vmw->config_done_state); @@ -657,11 +649,12 @@ static int vmw_dma_select_mode(struct vmw_private *dev_priv) [vmw_dma_map_populate] = "Caching DMA mappings.", [vmw_dma_map_bind] = "Giving up DMA mappings early."}; - /* TTM currently doesn't fully support SEV encryption. */ - if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) - return -EINVAL; - - if (vmw_force_coherent) + /* + * When running with SEV we always want dma mappings, because + * otherwise ttm tt pool pages will bounce through swiotlb running + * out of available space. + */ + if (vmw_force_coherent || cc_platform_has(CC_ATTR_MEM_ENCRYPT)) dev_priv->map_mode = vmw_dma_alloc_coherent; else if (vmw_restrict_iommu) dev_priv->map_mode = vmw_dma_map_bind; @@ -722,7 +715,7 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, pci_set_master(pdev); - ret = pci_request_regions(pdev, "vmwgfx probe"); + ret = pcim_request_all_regions(pdev, "vmwgfx probe"); if (ret) return ret; @@ -734,7 +727,7 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, dev->vram_size = pci_resource_len(pdev, 2); drm_info(&dev->drm, - "Register MMIO at 0x%pa size is %llu kiB\n", + "Register MMIO at 0x%pa size is %llu KiB\n", &rmmio_start, (uint64_t)rmmio_size / 1024); dev->rmmio = devm_ioremap(dev->drm.dev, rmmio_start, @@ -742,7 +735,6 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, if (!dev->rmmio) { drm_err(&dev->drm, "Failed mapping registers mmio memory.\n"); - pci_release_regions(pdev); return -ENOMEM; } } else if (pci_id == VMWGFX_PCI_ID_SVGA2) { @@ -753,21 +745,19 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, fifo_size = pci_resource_len(pdev, 2); drm_info(&dev->drm, - "FIFO at %pa size is %llu kiB\n", + "FIFO at %pa size is %llu KiB\n", &fifo_start, (uint64_t)fifo_size / 1024); dev->fifo_mem = devm_memremap(dev->drm.dev, fifo_start, fifo_size, - MEMREMAP_WB); + MEMREMAP_WB | MEMREMAP_DEC); if (IS_ERR(dev->fifo_mem)) { drm_err(&dev->drm, "Failed mapping FIFO memory.\n"); - pci_release_regions(pdev); return PTR_ERR(dev->fifo_mem); } } else { - pci_release_regions(pdev); return -EINVAL; } @@ -778,7 +768,7 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, * SVGA_REG_VRAM_SIZE. */ drm_info(&dev->drm, - "VRAM at %pa size is %llu kiB\n", + "VRAM at %pa size is %llu KiB\n", &dev->vram_start, (uint64_t)dev->vram_size / 1024); return 0; @@ -845,9 +835,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) int ret; enum vmw_res_type i; bool refuse_dma = false; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - - dev_priv->drm.dev_private = dev_priv; vmw_sw_context_init(dev_priv); @@ -863,7 +850,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) return ret; ret = vmw_detect_version(dev_priv); if (ret) - goto out_no_pci_or_version; + return ret; for (i = vmw_res_context; i < vmw_res_max; ++i) { @@ -891,6 +878,18 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) cap2_names, ARRAY_SIZE(cap2_names)); } + if (!vmwgfx_supported(dev_priv)) { + vmw_disable_backdoor(); + drm_err_once(&dev_priv->drm, + "vmwgfx seems to be running on an unsupported hypervisor."); + drm_err_once(&dev_priv->drm, + "This configuration is likely broken."); + drm_err_once(&dev_priv->drm, + "Please switch to a supported graphics device to avoid problems."); + } + + vmw_vkms_init(dev_priv); + ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { drm_info(&dev_priv->drm, @@ -936,13 +935,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) vmw_read(dev_priv, SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); - /* - * Workaround for low memory 2D VMs to compensate for the - * allocation taken by fbdev - */ - if (!(dev_priv->capabilities & SVGA_CAP_3D)) - mem_size *= 3; - dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE; dev_priv->max_primary_mem = vmw_read(dev_priv, SVGA_REG_MAX_PRIMARY_MEM); @@ -967,13 +959,13 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->max_primary_mem = dev_priv->vram_size; } drm_info(&dev_priv->drm, - "Legacy memory limits: VRAM = %llu kB, FIFO = %llu kB, surface = %u kB\n", + "Legacy memory limits: VRAM = %llu KiB, FIFO = %llu KiB, surface = %u KiB\n", (u64)dev_priv->vram_size / 1024, (u64)dev_priv->fifo_mem_size / 1024, dev_priv->memory_size / 1024); drm_info(&dev_priv->drm, - "MOB limits: max mob size = %u kB, max mob pages = %u\n", + "MOB limits: max mob size = %u KiB, max mob pages = %u\n", dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages); ret = vmw_dma_masks(dev_priv); @@ -991,7 +983,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) (unsigned)dev_priv->max_gmr_pages); } drm_info(&dev_priv->drm, - "Maximum display memory size is %llu kiB\n", + "Maximum display memory size is %llu KiB\n", (uint64_t)dev_priv->max_primary_mem / 1024); /* Need mmio memory to check for fifo pitchlock cap. */ @@ -1031,8 +1023,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->drm.dev, dev_priv->drm.anon_inode->i_mapping, dev_priv->drm.vma_offset_manager, - dev_priv->map_mode == vmw_dma_alloc_coherent, - false); + (dev_priv->map_mode == vmw_dma_alloc_coherent) ? + TTM_ALLOCATION_POOL_USE_DMA_ALLOC : 0); if (unlikely(ret != 0)) { drm_err(&dev_priv->drm, "Failed initializing TTM buffer object driver.\n"); @@ -1158,15 +1150,13 @@ out_err0: if (dev_priv->ctx.staged_bindings) vmw_binding_state_free(dev_priv->ctx.staged_bindings); -out_no_pci_or_version: - pci_release_regions(pdev); + return ret; } static void vmw_driver_unload(struct drm_device *dev) { struct vmw_private *dev_priv = vmw_priv(dev); - struct pci_dev *pdev = to_pci_dev(dev->dev); enum vmw_res_type i; unregister_pm_notifier(&dev_priv->pm_nb); @@ -1176,6 +1166,7 @@ static void vmw_driver_unload(struct drm_device *dev) vmw_svga_disable(dev_priv); + vmw_vkms_cleanup(dev_priv); vmw_kms_close(dev_priv); vmw_overlay_close(dev_priv); @@ -1201,8 +1192,6 @@ static void vmw_driver_unload(struct drm_device *dev) idr_destroy(&dev_priv->res_idr[i]); vmw_mksstat_remove_all(dev_priv); - - pci_release_regions(pdev); } static void vmw_postclose(struct drm_device *dev, @@ -1309,9 +1298,22 @@ static void vmw_master_set(struct drm_device *dev, static void vmw_master_drop(struct drm_device *dev, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); +} - vmw_kms_legacy_hotspot_clear(dev_priv); +bool vmwgfx_supported(struct vmw_private *vmw) +{ +#if defined(CONFIG_X86) + return hypervisor_is_type(X86_HYPER_VMWARE); +#elif defined(CONFIG_ARM64) + /* + * On aarch64 only svga3 is supported + */ + return vmw->pci_id == VMWGFX_PCI_ID_SVGA3; +#else + drm_warn_once(&vmw->drm, + "vmwgfx is running on an unknown architecture."); + return false; +#endif } /** @@ -1409,12 +1411,15 @@ static void vmw_debugfs_resource_managers_init(struct vmw_private *vmw) root, "system_ttm"); ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, TTM_PL_VRAM), root, "vram_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_GMR), - root, "gmr_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_MOB), - root, "mob_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_SYSTEM), - root, "system_mob_ttm"); + if (vmw->has_gmr) + ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_GMR), + root, "gmr_ttm"); + if (vmw->has_mob) { + ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_MOB), + root, "mob_ttm"); + ttm_resource_manager_create_debugfs(ttm_manager_type(&vmw->bdev, VMW_PL_SYSTEM), + root, "system_mob_ttm"); + } } static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, @@ -1565,18 +1570,19 @@ static const struct file_operations vmwgfx_driver_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = vmw_unlocked_ioctl, - .mmap = vmw_mmap, + .mmap = drm_gem_mmap, .poll = drm_poll, .read = drm_read, #if defined(CONFIG_COMPAT) .compat_ioctl = vmw_compat_ioctl, #endif .llseek = noop_llseek, + .fop_flags = FOP_UNSIGNED_OFFSET, }; static const struct drm_driver driver = { .driver_features = - DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM, + DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM | DRIVER_CURSOR_HOTSPOT, .ioctls = vmw_ioctls, .num_ioctls = ARRAY_SIZE(vmw_ioctls), .master_set = vmw_master_set, @@ -1589,11 +1595,13 @@ static const struct drm_driver driver = { .prime_fd_to_handle = vmw_prime_fd_to_handle, .prime_handle_to_fd = vmw_prime_handle_to_fd, + .gem_prime_import_sg_table = vmw_prime_import_sg_table, + + DRM_FBDEV_TTM_DRIVER_OPS, .fops = &vmwgfx_driver_fops, .name = VMWGFX_DRIVER_NAME, .desc = VMWGFX_DRIVER_DESC, - .date = VMWGFX_DRIVER_DATE, .major = VMWGFX_DRIVER_MAJOR, .minor = VMWGFX_DRIVER_MINOR, .patchlevel = VMWGFX_DRIVER_PATCHLEVEL @@ -1614,7 +1622,7 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct vmw_private *vmw; int ret; - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver); + ret = aperture_remove_conflicting_pci_devices(pdev, driver.name); if (ret) goto out_error; @@ -1641,7 +1649,7 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) vmw_fifo_resource_inc(vmw); vmw_svga_enable(vmw); - drm_fbdev_generic_setup(&vmw->drm, 0); + drm_client_setup(&vmw->drm, NULL); vmw_debugfs_gem_init(vmw); vmw_debugfs_resource_managers_init(vmw); |
