From: Dave Airlie Date: Wed, 3 Apr 2019 01:36:52 +0000 (+1000) Subject: Merge branch 'drm-next-5.2' of git://people.freedesktop.org/~agd5f/linux into drm... X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=457109829f4ee4107e8c7108237afba21fabbb5e;p=linux.git Merge branch 'drm-next-5.2' of git://people.freedesktop.org/~agd5f/linux into drm-next amdgpu: - Switch to HMM for userptr (reverted until HMM fixes land) - New experimental SMU 11 replacement for powerplay for vega20 (not enabled by default) - Initial RAS support for vega20 - BACO support for vega12 - BACO fixes for vega20 - Rework IH handling for page fault and retry interrupts - Cleanly split CPU and GPU paths for GPUVM updates - Powerplay fixes - XGMI fixes - Rework how DC interacts with atomic for planes - Clean up and simplify DC/Powerplay interfaces - Misc cleanups and bug fixes amdkfd: - Switch to HMM for userptr (reverted until HMM fixes land) - Add initial RAS support - MQD fixes ttm: - Unify DRM_FILE_PAGE_OFFSET handling - Account for kernel allocations in kernel zone only - Misc cleanups Signed-off-by: Dave Airlie From: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20190402170820.22197-1-alexander.deucher@amd.com --- 457109829f4ee4107e8c7108237afba21fabbb5e diff --cc drivers/gpu/drm/vboxvideo/vbox_drv.h index 0ecd0a44176e6,0000000000000..ece31f395540b mode 100644,000000..100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.h +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.h @@@ -1,273 -1,0 +1,271 @@@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2013-2017 Oracle Corporation + * This file is based on ast_drv.h + * Copyright 2012 Red Hat Inc. + * Authors: Dave Airlie + * Michael Thayer + */ +#ifndef __VBOX_DRV_H__ +#define __VBOX_DRV_H__ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vboxvideo_guest.h" +#include "vboxvideo_vbe.h" +#include "hgsmi_ch_setup.h" + +#define DRIVER_NAME "vboxvideo" +#define DRIVER_DESC "Oracle VM VirtualBox Graphics Card" +#define DRIVER_DATE "20130823" + +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define VBOX_MAX_CURSOR_WIDTH 64 +#define VBOX_MAX_CURSOR_HEIGHT 64 +#define CURSOR_PIXEL_COUNT (VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT) +#define CURSOR_DATA_SIZE (CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8) + +#define VBOX_MAX_SCREENS 32 + +#define GUEST_HEAP_OFFSET(vbox) ((vbox)->full_vram_size - \ + VBVA_ADAPTER_INFORMATION_SIZE) +#define GUEST_HEAP_SIZE VBVA_ADAPTER_INFORMATION_SIZE +#define GUEST_HEAP_USABLE_SIZE (VBVA_ADAPTER_INFORMATION_SIZE - \ + sizeof(struct hgsmi_host_flags)) +#define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE + +struct vbox_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; +}; + +struct vbox_private { + /* Must be first; or we must define our own release callback */ + struct drm_device ddev; + struct drm_fb_helper fb_helper; + struct vbox_framebuffer afb; + + u8 __iomem *guest_heap; + u8 __iomem *vbva_buffers; + struct gen_pool *guest_pool; + struct vbva_buf_ctx *vbva_info; + bool any_pitch; + u32 num_crtcs; + /* Amount of available VRAM, including space used for buffers. */ + u32 full_vram_size; + /* Amount of available VRAM, not including space used for buffers. */ + u32 available_vram_size; + /* Array of structures for receiving mode hints. */ + struct vbva_modehint *last_mode_hints; + + int fb_mtrr; + + struct { + struct ttm_bo_device bdev; + } ttm; + + struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */ + struct work_struct hotplug_work; + u32 input_mapping_width; + u32 input_mapping_height; + /* + * Is user-space using an X.Org-style layout of one large frame-buffer + * encompassing all screen ones or is the fbdev console active? + */ + bool single_framebuffer; + u8 cursor_data[CURSOR_DATA_SIZE]; +}; + +#undef CURSOR_PIXEL_COUNT +#undef CURSOR_DATA_SIZE + +struct vbox_gem_object; + +struct vbox_connector { + struct drm_connector base; + char name[32]; + struct vbox_crtc *vbox_crtc; + struct { + u32 width; + u32 height; + bool disconnected; + } mode_hint; +}; + +struct vbox_crtc { + struct drm_crtc base; + bool disconnected; + unsigned int crtc_id; + u32 fb_offset; + bool cursor_enabled; + u32 x_hint; + u32 y_hint; + /* + * When setting a mode we not only pass the mode to the hypervisor, + * but also information on how to map / translate input coordinates + * for the emulated USB tablet. This input-mapping may change when + * the mode on *another* crtc changes. + * + * This means that sometimes we must do a modeset on other crtc-s then + * the one being changed to update the input-mapping. Including crtc-s + * which may be disabled inside the guest (shown as a black window + * on the host unless closed by the user). + * + * With atomic modesetting the mode-info of disabled crtcs gets zeroed + * yet we need it when updating the input-map to avoid resizing the + * window as a side effect of a mode_set on another crtc. Therefor we + * cache the info of the last mode below. + */ + u32 width; + u32 height; + u32 x; + u32 y; +}; + +struct vbox_encoder { + struct drm_encoder base; +}; + +#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base) +#define to_vbox_connector(x) container_of(x, struct vbox_connector, base) +#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base) +#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base) + +bool vbox_check_supported(u16 id); +int vbox_hw_init(struct vbox_private *vbox); +void vbox_hw_fini(struct vbox_private *vbox); + +int vbox_mode_init(struct vbox_private *vbox); +void vbox_mode_fini(struct vbox_private *vbox); + +void vbox_report_caps(struct vbox_private *vbox); + +void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb, + struct drm_clip_rect *rects, + unsigned int num_rects); + +int vbox_framebuffer_init(struct vbox_private *vbox, + struct vbox_framebuffer *vbox_fb, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj); + +int vboxfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); +void vbox_fbdev_fini(struct vbox_private *vbox); + +struct vbox_bo { + struct ttm_buffer_object bo; + struct ttm_placement placement; + struct ttm_bo_kmap_obj kmap; + struct drm_gem_object gem; + struct ttm_place placements[3]; + int pin_count; +}; + +#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem) + +static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct vbox_bo, bo); +} + +#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base) + +static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo) +{ + return bo->bo.offset; +} + +int vbox_dumb_create(struct drm_file *file, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + +void vbox_gem_free_object(struct drm_gem_object *obj); +int vbox_dumb_mmap_offset(struct drm_file *file, + struct drm_device *dev, + u32 handle, u64 *offset); + - #define DRM_FILE_PAGE_OFFSET (0x10000000ULL >> PAGE_SHIFT) - +int vbox_mm_init(struct vbox_private *vbox); +void vbox_mm_fini(struct vbox_private *vbox); + +int vbox_bo_create(struct vbox_private *vbox, int size, int align, + u32 flags, struct vbox_bo **pvboxbo); + +int vbox_gem_create(struct vbox_private *vbox, + u32 size, bool iskernel, struct drm_gem_object **obj); + +int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag); +int vbox_bo_unpin(struct vbox_bo *bo); + +static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait) +{ + int ret; + + ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); + if (ret) { + if (ret != -ERESTARTSYS && ret != -EBUSY) + DRM_ERROR("reserve failed %p\n", bo); + return ret; + } + return 0; +} + +static inline void vbox_bo_unreserve(struct vbox_bo *bo) +{ + ttm_bo_unreserve(&bo->bo); +} + +void vbox_ttm_placement(struct vbox_bo *bo, int domain); +int vbox_bo_push_sysram(struct vbox_bo *bo); +int vbox_mmap(struct file *filp, struct vm_area_struct *vma); +void *vbox_bo_kmap(struct vbox_bo *bo); +void vbox_bo_kunmap(struct vbox_bo *bo); + +/* vbox_prime.c */ +int vbox_gem_prime_pin(struct drm_gem_object *obj); +void vbox_gem_prime_unpin(struct drm_gem_object *obj); +struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj); +struct drm_gem_object *vbox_gem_prime_import_sg_table( + struct drm_device *dev, struct dma_buf_attachment *attach, + struct sg_table *table); +void *vbox_gem_prime_vmap(struct drm_gem_object *obj); +void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +int vbox_gem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *area); + +/* vbox_irq.c */ +int vbox_irq_init(struct vbox_private *vbox); +void vbox_irq_fini(struct vbox_private *vbox); +void vbox_report_hotplug(struct vbox_private *vbox); +irqreturn_t vbox_irq_handler(int irq, void *arg); + +/* vbox_hgsmi.c */ +void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size, + u8 channel, u16 channel_info); +void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf); +int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf); + +static inline void vbox_write_ioport(u16 index, u16 data) +{ + outw(index, VBE_DISPI_IOPORT_INDEX); + outw(data, VBE_DISPI_IOPORT_DATA); +} + +#endif diff --cc drivers/gpu/drm/vboxvideo/vbox_ttm.c index 30f270027acf7,0000000000000..9d78438c28779 mode 100644,000000..100644 --- a/drivers/gpu/drm/vboxvideo/vbox_ttm.c +++ b/drivers/gpu/drm/vboxvideo/vbox_ttm.c @@@ -1,394 -1,0 +1,388 @@@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2013-2017 Oracle Corporation + * This file is based on ast_ttm.c + * Copyright 2012 Red Hat Inc. + * Authors: Dave Airlie + * Michael Thayer + */ +#include +#include +#include +#include "vbox_drv.h" + +static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd) +{ + return container_of(bd, struct vbox_private, ttm.bdev); +} + +static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo) +{ + struct vbox_bo *bo; + + bo = container_of(tbo, struct vbox_bo, bo); + + drm_gem_object_release(&bo->gem); + kfree(bo); +} + +static bool vbox_ttm_bo_is_vbox_bo(struct ttm_buffer_object *bo) +{ + if (bo->destroy == &vbox_bo_ttm_destroy) + return true; + + return false; +} + +static int +vbox_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type, + struct ttm_mem_type_manager *man) +{ + switch (type) { + case TTM_PL_SYSTEM: + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + break; + case TTM_PL_VRAM: + man->func = &ttm_bo_manager_func; + man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); + return -EINVAL; + } + + return 0; +} + +static void +vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) +{ + struct vbox_bo *vboxbo = vbox_bo(bo); + + if (!vbox_ttm_bo_is_vbox_bo(bo)) + return; + + vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM); + *pl = vboxbo->placement; +} + +static int vbox_bo_verify_access(struct ttm_buffer_object *bo, + struct file *filp) +{ + return 0; +} + +static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct vbox_private *vbox = vbox_bdev(bdev); + + mem->bus.addr = NULL; + mem->bus.offset = 0; + mem->bus.size = mem->num_pages << PAGE_SHIFT; + mem->bus.base = 0; + mem->bus.is_iomem = false; + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) + return -EINVAL; + switch (mem->mem_type) { + case TTM_PL_SYSTEM: + /* system memory */ + return 0; + case TTM_PL_VRAM: + mem->bus.offset = mem->start << PAGE_SHIFT; + mem->bus.base = pci_resource_start(vbox->ddev.pdev, 0); + mem->bus.is_iomem = true; + break; + default: + return -EINVAL; + } + return 0; +} + +static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ +} + +static void vbox_ttm_backend_destroy(struct ttm_tt *tt) +{ + ttm_tt_fini(tt); + kfree(tt); +} + +static struct ttm_backend_func vbox_tt_backend_func = { + .destroy = &vbox_ttm_backend_destroy, +}; + +static struct ttm_tt *vbox_ttm_tt_create(struct ttm_buffer_object *bo, + u32 page_flags) +{ + struct ttm_tt *tt; + + tt = kzalloc(sizeof(*tt), GFP_KERNEL); + if (!tt) + return NULL; + + tt->func = &vbox_tt_backend_func; + if (ttm_tt_init(tt, bo, page_flags)) { + kfree(tt); + return NULL; + } + + return tt; +} + +static struct ttm_bo_driver vbox_bo_driver = { + .ttm_tt_create = vbox_ttm_tt_create, + .init_mem_type = vbox_bo_init_mem_type, + .eviction_valuable = ttm_bo_eviction_valuable, + .evict_flags = vbox_bo_evict_flags, + .verify_access = vbox_bo_verify_access, + .io_mem_reserve = &vbox_ttm_io_mem_reserve, + .io_mem_free = &vbox_ttm_io_mem_free, +}; + +int vbox_mm_init(struct vbox_private *vbox) +{ + int ret; + struct drm_device *dev = &vbox->ddev; + struct ttm_bo_device *bdev = &vbox->ttm.bdev; + + ret = ttm_bo_device_init(&vbox->ttm.bdev, + &vbox_bo_driver, + dev->anon_inode->i_mapping, - DRM_FILE_PAGE_OFFSET, true); ++ true); + if (ret) { + DRM_ERROR("Error initialising bo driver; %d\n", ret); + return ret; + } + + ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, + vbox->available_vram_size >> PAGE_SHIFT); + if (ret) { + DRM_ERROR("Failed ttm VRAM init: %d\n", ret); + goto err_device_release; + } + +#ifdef DRM_MTRR_WC + vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0), + DRM_MTRR_WC); +#else + vbox->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); +#endif + return 0; + +err_device_release: + ttm_bo_device_release(&vbox->ttm.bdev); + return ret; +} + +void vbox_mm_fini(struct vbox_private *vbox) +{ +#ifdef DRM_MTRR_WC + drm_mtrr_del(vbox->fb_mtrr, + pci_resource_start(vbox->ddev.pdev, 0), + pci_resource_len(vbox->ddev.pdev, 0), DRM_MTRR_WC); +#else + arch_phys_wc_del(vbox->fb_mtrr); +#endif + ttm_bo_device_release(&vbox->ttm.bdev); +} + +void vbox_ttm_placement(struct vbox_bo *bo, int domain) +{ + unsigned int i; + u32 c = 0; + + bo->placement.placement = bo->placements; + bo->placement.busy_placement = bo->placements; + + if (domain & TTM_PL_FLAG_VRAM) + bo->placements[c++].flags = + TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + if (domain & TTM_PL_FLAG_SYSTEM) + bo->placements[c++].flags = + TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + if (!c) + bo->placements[c++].flags = + TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + + bo->placement.num_placement = c; + bo->placement.num_busy_placement = c; + + for (i = 0; i < c; ++i) { + bo->placements[i].fpfn = 0; + bo->placements[i].lpfn = 0; + } +} + +int vbox_bo_create(struct vbox_private *vbox, int size, int align, + u32 flags, struct vbox_bo **pvboxbo) +{ + struct vbox_bo *vboxbo; + size_t acc_size; + int ret; + + vboxbo = kzalloc(sizeof(*vboxbo), GFP_KERNEL); + if (!vboxbo) + return -ENOMEM; + + ret = drm_gem_object_init(&vbox->ddev, &vboxbo->gem, size); + if (ret) + goto err_free_vboxbo; + + vboxbo->bo.bdev = &vbox->ttm.bdev; + + vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); + + acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size, + sizeof(struct vbox_bo)); + + ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size, + ttm_bo_type_device, &vboxbo->placement, + align >> PAGE_SHIFT, false, acc_size, + NULL, NULL, vbox_bo_ttm_destroy); + if (ret) + goto err_free_vboxbo; + + *pvboxbo = vboxbo; + + return 0; + +err_free_vboxbo: + kfree(vboxbo); + return ret; +} + +int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag) +{ + struct ttm_operation_ctx ctx = { false, false }; + int i, ret; + + if (bo->pin_count) { + bo->pin_count++; + return 0; + } + + ret = vbox_bo_reserve(bo, false); + if (ret) + return ret; + + vbox_ttm_placement(bo, pl_flag); + + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; + + ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); + if (ret == 0) + bo->pin_count = 1; + + vbox_bo_unreserve(bo); + + return ret; +} + +int vbox_bo_unpin(struct vbox_bo *bo) +{ + struct ttm_operation_ctx ctx = { false, false }; + int i, ret; + + if (!bo->pin_count) { + DRM_ERROR("unpin bad %p\n", bo); + return 0; + } + bo->pin_count--; + if (bo->pin_count) + return 0; + + ret = vbox_bo_reserve(bo, false); + if (ret) { + DRM_ERROR("Error %d reserving bo, leaving it pinned\n", ret); + return ret; + } + + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; + + ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); + + vbox_bo_unreserve(bo); + + return ret; +} + +/* + * Move a vbox-owned buffer object to system memory if no one else has it + * pinned. The caller must have pinned it previously, and this call will + * release the caller's pin. + */ +int vbox_bo_push_sysram(struct vbox_bo *bo) +{ + struct ttm_operation_ctx ctx = { false, false }; + int i, ret; + + if (!bo->pin_count) { + DRM_ERROR("unpin bad %p\n", bo); + return 0; + } + bo->pin_count--; + if (bo->pin_count) + return 0; + + if (bo->kmap.virtual) { + ttm_bo_kunmap(&bo->kmap); + bo->kmap.virtual = NULL; + } + + vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); + + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; + + ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); + if (ret) { + DRM_ERROR("pushing to VRAM failed\n"); + return ret; + } + + return 0; +} + +int vbox_mmap(struct file *filp, struct vm_area_struct *vma) +{ - struct drm_file *file_priv; - struct vbox_private *vbox; - - if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) - return -EINVAL; - - file_priv = filp->private_data; - vbox = file_priv->minor->dev->dev_private; ++ struct drm_file *file_priv = filp->private_data; ++ struct vbox_private *vbox = file_priv->minor->dev->dev_private; + + return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev); +} + +void *vbox_bo_kmap(struct vbox_bo *bo) +{ + int ret; + + if (bo->kmap.virtual) + return bo->kmap.virtual; + + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { + DRM_ERROR("Error kmapping bo: %d\n", ret); + return NULL; + } + + return bo->kmap.virtual; +} + +void vbox_bo_kunmap(struct vbox_bo *bo) +{ + if (bo->kmap.virtual) { + ttm_bo_kunmap(&bo->kmap); + bo->kmap.virtual = NULL; + } +}