summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/virtio/virtgpu_vram.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2020-11-04 10:55:11 +1000
committerDave Airlie <airlied@redhat.com>2020-11-04 11:49:10 +1000
commit1cd260a7905e3ba2e5dfa39b110ad6cf8f466f49 (patch)
treebfb701fdb0fcb32f8e6e53fb1692361c8fa33a6a /drivers/gpu/drm/virtio/virtgpu_vram.c
parent3cea11cd5e3b00d91caf0b4730194039b45c5891 (diff)
parent4dfec0d1d7b9970f36931de714b379dbeaed83f8 (diff)
Merge tag 'drm-misc-next-2020-10-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.11: UAPI Changes: - doc: rules for EBUSY on non-blocking commits; requirements for fourcc modifiers; on parsing EDID - fbdev/sbuslib: Remove unused FBIOSCURSOR32 - fourcc: deprecate DRM_FORMAT_MOD_NONE - virtio: Support blob resources for memory allocations; Expose host-visible and cross-device features Cross-subsystem Changes: - devicetree: Add vendor Prefix for Yes Optoelectronics, Shanghai Top Display Optoelectronics - dma-buf: Add struct dma_buf_map that stores DMA pointer and I/O-memory flag; dma_buf_vmap()/vunmap() return address in dma_buf_map; Use struct_size() macro Core Changes: - atomic: pass full state to CRTC atomic enable/disable; warn for EBUSY during non-blocking commits - dp: Prepare for DP 2.0 DPCD - dp_mst: Receive extended DPCD caps - dma-buf: Documentation - doc: Format modifiers; dma-buf-map; Cleanups - fbdev: Don't use compat_alloc_user_space(); mark as orphaned - fb-helper: Take lock in drm_fb_helper_restore_work_fb() - gem: Convert implementation and drivers to GEM object functions, remove GEM callbacks from struct drm_driver (expect gem_prime_mmap) - panel: Cleanups - pci: Add legacy infix to drm_irq_by_busid() - sched: Avoid infinite waits in drm_sched_entity_destroy() - switcheroo: Cleanups - ttm: Remove AGP support; Don't modify caching during swapout; Major refactoring of the implementation and API that affects all depending drivers; Add ttm_bo_wait_ctx(); Add ttm_bo_pin()/unpin() in favor of TTM_PL_FLAG_NO_EVICT; Remove ttm_bo_create(); Remove fault_reserve_notify() callback; Push move() implementation into drivers; Remove TTM_PAGE_FLAG_WRITE; Replace caching flags with init-time cache setting; Push ttm_tt_bind() into drivers; Replace move_notify() with delete_mem_notify(); No overlapping memcpy(); no more ttm_set_populated() - vram-helper: Fix BO top-down placement; TTM-related changes; Init GEM object functions with defaults; Default placement in system memory; Cleanups Driver Changes: - amdgpu: Use GEM object functions - armada: Use GEM object functions - aspeed: Configure output via sysfs; Init struct drm_driver with - ast: Reload LUT after FB format changes - bridge: Add driver and DT bindings for anx7625; Cleanups - bridge/dw-hdmi: Constify ops - bridge/ti-sn65dsi86: Add retries for link training - bridge/lvds-codec: Add support for regulator - bridge/tc358768: Restore connector support DRM_GEM_CMA_DRIVEROPS; Cleanups - display/ti,j721e-dss: Add DT properies assigned-clocks, assigned-clocks-parent and dma-coherent - display/ti,am65s-dss: Add DT properies assigned-clocks, assigned-clocks-parent and dma-coherent - etnaviv: Use GEM object functions - exynos: Use GEM object functions - fbdev: Cleanups and compiler fixes throughout framebuffer drivers - fbdev/cirrusfb: Avoid division by 0 - gma500: Use GEM object functions; Fix double-free of connector; Cleanups - hisilicon/hibmc: I2C-based DDC support; Use to_hibmc_drm_device(); Cleanups - i915: Use GEM object functions - imx/dcss: Init driver with DRM_GEM_CMA_DRIVER_OPS; Cleanups - ingenic: Reset pixel clock when parent clock changes; support reserved memory; Alloc F0 and F1 DMA channels at once; Support different pixel formats; Revert support for cached mmap buffers on F0/F1; support 30-bit/24-bit/8-bit-palette modes - komeda: Use DEFINE_SHOW_ATTRIBUTE - mcde: Detect platform_get_irq() errors - mediatek: Use GEM object functions - msm: Use GEM object functions - nouveau: Cleanups; TTM-related changes; Use GEM object functions - omapdrm: Use GEM object functions - panel: Add driver and DT bindings for Novatak nt36672a; Add driver and DT bindings for YTC700TLAG-05-201C; Add driver and DT bindings for TDO TL070WSH30; Cleanups - panel/mantix: Fix reset; Fix deref of NULL pointer in mantix_get_modes() - panel/otm8009a: Allow non-continuous dsi clock; Cleanups - panel/rm68200: Allow non-continuous dsi clock; Fix mode to 50 FPS - panfrost: Fix job timeout handling; Cleanups - pl111: Use GEM object functions - qxl: Cleanups; TTM-related changes; Pin new BOs with ttm_bo_init_reserved() - radeon: Cleanups; TTM-related changes; Use GEM object functions - rockchip: Use GEM object functions - shmobile: Cleanups - tegra: Use GEM object functions - tidss: Set drm_plane_helper_funcs.prepare_fb - tilcdc: Don't keep vblank interrupt enabled all the time - tve200: Detect platform_get_irq() errors - vc4: Use GEM object functions; Only register components once DSI is attached; Add Maxime as maintainer - vgem: Use GEM object functions - via: Simplify critical section in via_mem_alloc() - virtgpu: Use GEM object functions - virtio: Implement blob resources, host-visible and cross-device features; Support mapping of host-allocated resources; Use UUID APi; Cleanups - vkms: Use GEM object functions; Switch to SHMEM - vmwgfx: TTM-related changes; Inline ttm_bo_swapout_all() - xen: Use GEM object functions - xlnx: Use GEM object functions Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20201027100936.GA4858@linux-uq9g
Diffstat (limited to 'drivers/gpu/drm/virtio/virtgpu_vram.c')
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vram.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c
new file mode 100644
index 000000000000..23c21bc4d01e
--- /dev/null
+++ b/drivers/gpu/drm/virtio/virtgpu_vram.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "virtgpu_drv.h"
+
+static void virtio_gpu_vram_free(struct drm_gem_object *obj)
+{
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_device *vgdev = obj->dev->dev_private;
+ struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
+ bool unmap;
+
+ if (bo->created) {
+ spin_lock(&vgdev->host_visible_lock);
+ unmap = drm_mm_node_allocated(&vram->vram_node);
+ spin_unlock(&vgdev->host_visible_lock);
+
+ if (unmap)
+ virtio_gpu_cmd_unmap(vgdev, bo);
+
+ virtio_gpu_cmd_unref_resource(vgdev, bo);
+ virtio_gpu_notify(vgdev);
+ return;
+ }
+}
+
+static const struct vm_operations_struct virtio_gpu_vram_vm_ops = {
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static int virtio_gpu_vram_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ int ret;
+ struct virtio_gpu_device *vgdev = obj->dev->dev_private;
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
+ unsigned long vm_size = vma->vm_end - vma->vm_start;
+
+ if (!(bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE))
+ return -EINVAL;
+
+ wait_event(vgdev->resp_wq, vram->map_state != STATE_INITIALIZING);
+ if (vram->map_state != STATE_OK)
+ return -EINVAL;
+
+ vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
+ vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+ vma->vm_ops = &virtio_gpu_vram_vm_ops;
+
+ if (vram->map_info == VIRTIO_GPU_MAP_CACHE_WC)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else if (vram->map_info == VIRTIO_GPU_MAP_CACHE_UNCACHED)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* Partial mappings of GEM buffers don't happen much in practice. */
+ if (vm_size != vram->vram_node.size)
+ return -EINVAL;
+
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ vram->vram_node.start >> PAGE_SHIFT,
+ vm_size, vma->vm_page_prot);
+ return ret;
+}
+
+static const struct drm_gem_object_funcs virtio_gpu_vram_funcs = {
+ .open = virtio_gpu_gem_object_open,
+ .close = virtio_gpu_gem_object_close,
+ .free = virtio_gpu_vram_free,
+ .mmap = virtio_gpu_vram_mmap,
+};
+
+bool virtio_gpu_is_vram(struct virtio_gpu_object *bo)
+{
+ return bo->base.base.funcs == &virtio_gpu_vram_funcs;
+}
+
+static int virtio_gpu_vram_map(struct virtio_gpu_object *bo)
+{
+ int ret;
+ uint64_t offset;
+ struct virtio_gpu_object_array *objs;
+ struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
+ struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
+
+ if (!vgdev->has_host_visible)
+ return -EINVAL;
+
+ spin_lock(&vgdev->host_visible_lock);
+ ret = drm_mm_insert_node(&vgdev->host_visible_mm, &vram->vram_node,
+ bo->base.base.size);
+ spin_unlock(&vgdev->host_visible_lock);
+
+ if (ret)
+ return ret;
+
+ objs = virtio_gpu_array_alloc(1);
+ if (!objs) {
+ ret = -ENOMEM;
+ goto err_remove_node;
+ }
+
+ virtio_gpu_array_add_obj(objs, &bo->base.base);
+ /*TODO: Add an error checking helper function in drm_mm.h */
+ offset = vram->vram_node.start - vgdev->host_visible_region.addr;
+
+ ret = virtio_gpu_cmd_map(vgdev, objs, offset);
+ if (ret) {
+ virtio_gpu_array_put_free(objs);
+ goto err_remove_node;
+ }
+
+ return 0;
+
+err_remove_node:
+ spin_lock(&vgdev->host_visible_lock);
+ drm_mm_remove_node(&vram->vram_node);
+ spin_unlock(&vgdev->host_visible_lock);
+ return ret;
+}
+
+int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object_params *params,
+ struct virtio_gpu_object **bo_ptr)
+{
+ struct drm_gem_object *obj;
+ struct virtio_gpu_object_vram *vram;
+ int ret;
+
+ vram = kzalloc(sizeof(*vram), GFP_KERNEL);
+ if (!vram)
+ return -ENOMEM;
+
+ obj = &vram->base.base.base;
+ obj->funcs = &virtio_gpu_vram_funcs;
+ drm_gem_private_object_init(vgdev->ddev, obj, params->size);
+
+ /* Create fake offset */
+ ret = drm_gem_create_mmap_offset(obj);
+ if (ret) {
+ kfree(vram);
+ return ret;
+ }
+
+ ret = virtio_gpu_resource_id_get(vgdev, &vram->base.hw_res_handle);
+ if (ret) {
+ kfree(vram);
+ return ret;
+ }
+
+ virtio_gpu_cmd_resource_create_blob(vgdev, &vram->base, params, NULL,
+ 0);
+ if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) {
+ ret = virtio_gpu_vram_map(&vram->base);
+ if (ret) {
+ virtio_gpu_vram_free(obj);
+ return ret;
+ }
+ }
+
+ *bo_ptr = &vram->base;
+ return 0;
+}