Files
linux-stable-mirror/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
T
Linus Torvalds 4b99990cdf Merge tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel
Pull drm updates from Dave Airlie:
 "Highlights:
   - xe: add initial CRI platform support
   - amdgpu: initial HDMI 2.1 FRL support
   - rust: add some new type concepts for device lifetimes
   - scheduler: moves to a fair algorithm and lots of cleanups

  But it's mostly the usual mountain of changes across the board.

  core:
   - add docbook for DRM_IOCTL_SYNCOBJ_EVENTFD
   - change signature of drm_connector_attach_hdr_output_metadata_property
   - dedup counter and timestamp retrieval in vblank code
   - parse AMD VSDB v3 in CTA extension blocks
   - add P230, Y7, XYYY2101010, T430, XVUY210101010 formats
   - don't call drop master on file close if not master
   - use drm_printf_indent in atomic / bridge
   - fix 32b format descriptions
   - docs: fix toctree
   - hdmi: add common TMDS character rates
   - fix drm_syncobj_find_fence leak

  rust:
   - introduce Higher-Ranked lifetime types
   - replace drvdata with scoped registration data
   - add GPUVM immediate mode abstraction for rust GPU drivers
   - introduce DeviceContext type state for drm::Device

  bridge:
   - clarify drm_bridge_get/put
   - create drm_get_bridge_by_endpoint and use it
   - analogix_dp: add panel probing
   - ite-it6211 - use drm audio hdmi helpers

  buddy:
   - add lockdep annotations

  dp:
   - add PR and VRR updates
   - mst: fix buffer overflows
   - add Adaptive Sync SDP decoding support
   - fix OOB reads in dp-mst

  ttm:
   - bump fpfn/lpfn to 64-bit

  scheduler:
   - change default to fair scheduler
   - map runqueue 1:1 with scheduler

  dma-buf:
   - port selftests to kunit
   - convert dma-buf system/heap allocators to module
   - add separate DMABUF_HEAPS_SYSTEM_CC_SHARED Kconfig

  udmabuf:
   - revert hugetlb support
   - fix error with CONFIG_DMA_API_DEBUG

  dma-fence:
   - fix tracepoints lifetime
   - remove unused signal on any support

  ras:
   - add clear error counter netlink command to drm ras

  gpusvm:
   - reject VMAs with VM_IO or VM_PFNMAP when creating SVM ranges
   - use IOVA allocations

  pagemap:
   - use IOVA allocations

  panels:
   - update to use ref counts
   - add support for CSW PNB601LS1-2, LGD LP116WHA-SPB1
   - add support for waveshare panels
   - CMN N116BCN-EA1, CMN N140HCA-EEK, IVO M140NWFQ R5,
   - IVO, R140NWFW R0, BOE NT140*, BOE NV133FHM-N4F,
   - AUO B140*, AUO B133HAN06.6 and AUO B116XTN02.3 eDP panels
   - Surface Pro 12 Panel

  xe:
   - add CRI PCI-IDs
   - debugfs add multi-lrc info
   - engine init cleanup
   - PF fair scheduling auto provisioning
   - system controller support for CRI/Xe3p
   - PXP state machine fixes
   - Reset/wedge/unload corner case fixes
   - Wedge path memory allocation fixes
   - PAT type cleanups
   - Reject unsafe PAT for CPU cached memory
   - OA improvements for CRI device memory
   - kernel doc syntax in xe headers
   - xe_drm.h documentation fixes
   - include guard cleanups
   - VF CCS memory pool
   - i915/xe step unification
   - Xe3p GT tuning fixes
   - forcewake cleanup in GT and GuC
   - admin-only PF mode
   - enable hwmon energy attributes for CRI
   - enable GT_MI_USER_INTERRUPT
   - refactor emit functions
   - oa workarounds
   - multi_queue: allow QUEUE_TIMESTAMP register
   - convert stolen memory to ttm range manager
   - use xe2 style blitter as a feature flag
   - make drm_driver const
   - add/use IRQ page to HW engine definition
   - fix oops when display disabled

  i915:
   - enable PIPEDMC_ERROR interrupt
   - more common display code refactoring
   - restructure DP/HDMI sink format handling
   - eliminate FB usage from lowlevel pinning code
   - panel replay bw optimization
   - integrate sharpness filter into the scaler
   - new fb_pin abstraction for xe/i915 fb transparent handling
   - skip inactive MST connectors on HDCP
   - start switching to display specific registers
   - use polling when irq unavailable
   - Adaptive-sync SDP prep

  amdgpu:
   - use drm_display_info for AMD VSDB data
   - Initial HDMI 2.1 FRL support
   - Initial DCN 4.2.1 support
   - GART fixes for non-4k pages
   - GC 11.5.6/SDMA 6.4.0/and other new IPs
   - GFX9/DCE6/Hawaii/SDMA4/GART/Userq fixes
   - Finish support for using multiple SDMA queues for TTM operations
   - SWSMU updates
   - GC 12.1 updates
   - SMU 15.0.8 updates
   - DCN 4.2 updates
   - DC type conversion fixes
   - Enable DC power module
   - Replay/PSR updates
   - SMU 13.x updates
   - Compute queue quantum MQD updates
   - ASPM fix
   - Align VKMS with common implementation
   - DC analog support fixes
   - UVD 3 fixes
   - TCC harvesting fixes for SI
   - GC 11 APU module reload fix
   - NBIO 6.3.2 support
   - IH 7.1 updates
   - DC cursor fixes
   - VCN/JPEG user fence fixes
   - DC support for connectors without DDC
   - Prefer ROM BAR for default VGA device
   - DC bandwidth fixes
   - Add PTL support for profiler
   - Introduce dc_plane_cm and migrate surface update color path
   - Add FRL registers for HDMI 2.1
   - Restructure VM state machine
   - Auxless ALPM support
   - GEM_OP locking/warning fixes
   - switch to system_dfl_wq

  amdkfd:
   - GPUVM TLB flush fix
   - Hotplug fix
   - Boundary check fixes
   - SVM fixes
   - CRIU fixes
   - add profiler API
   - MES 12.1 updates

  msm:
   - core:
     - fix shrinker documentation
     - IFPC enabled for gen8
     - PERFCNTR_CONFIG ioctl support
   - GPU:
     - reworked UBWC handling
     - a810 support
   - MDSS:
     - add support for Milos platform
     - reworked UBWC handling
   - DisplayPort:
     - reworked HPD handling as prep for MST
   - DPU:
     - Milos platform support
     - reworked UBWC handling
   - DSI:
     - Milos platform support

  nova:
   - Hopper/Blackwell enablement (GH100/GB100/GB202)
     - FSP support
     - 32-bit firmware support
     - HAL functions
   - refactor GSP boot/unload
   - GA100 support
   - VBIOS hardening/refactoring
   - Adopt higher order lifetime types

  tyr:
   - define register blocks
   - add shmem backed GEM objects
   - adopt higher order lifetime types
   - move clock cleanup into Drop

  radeon:
   - Hawaii SMU fixes
   - CS parser fix
   - use struct drm_edid instead of edid

  amdxdna:
   - export per-client BO memory via fdinfo
   - AIE4 device support
   - support medium/lower power modes
   - expandable device heap support
   - revert read-only user-pointer BO mappings

  ivpu:
   - support frequency limiting

  panthor:
   - enable GEM shrinker support
   - add eviction and reclaim info to fdinfo

  v3d:
   - enable runtime PM

  mgag200:
   - support XRGB1555 + C8

  ast:
   - support XRGB1555 + C8
   - use constants for lots of registers
   - fix register handling

  imagination:
   - fence handling refactoring

  nouveau:
   - fix sched double call
   - expose VBIOS on GSP-RM systems
   - add GA100 support

  virtio:
   - add VIRTIO_GPU_F_BLOB_ALIGNMENT flag
   - add deferred mapping support

  gud:
   - add RCade Display Adapter

  hibmc:
   - fix no connectors usage

  mediatek:
   - hdmi: convert error handling
   - simplify mtk_crtc allocation

  exynos:
   - move fbdev emulation to drm client buffers
   - use drm format helpers for geometry/size
   - adopt core DMA tracking
   - fix framebuffer offset handling

  renesas:
   - add RZ/T2H SOC support

  versilicon:
   - add cursor plane support

  tegra:
   - use drm client for framebuffer"

* tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel: (1731 commits)
  dma-buf: move system_cc_shared heap under separate Kconfig
  accel/amdxdna: Clear sva pointer after unbind
  agp/amd64: Fix broken error propagation in agp_amd64_probe()
  accel/amdxdna: Require carveout when PASID and force_iova are disabled
  drm/amdkfd: always resume_all after suspend_all
  drm/amdgpu/gfx: move fault and EOP IRQ get/put to hw_init/hw_fini
  drm/amd/display: Consult MCCS FreeSync cap only if requested & supported
  drm/amd/pm: Use strscpy in profile mode parsing
  drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
  drm/amdkfd: fix sysfs topology prop length on buffer truncation
  drm/amdgpu: drop retry loop in amdgpu_hmm_range_get_pages
  drm/amd/pm: bound OD parameter parsing to stack array size
  drm/amd/pm: Stop pp_od_clk_voltage emit at PAGE_SIZE
  drm/amdkfd: Unwind debug trap enable on copy_to_user failure
  drm/amdgpu: validate the mes firmware version for gfx12.1
  drm/amdgpu: validate the mes firmware version for gfx12
  drm/amdgpu: compare MES firmware version ucode for gfx11
  drm/amdkfd: Add bounds check for AMDKFD_IOC_WAIT_EVENTS
  drm/amdgpu: restart the CS if some parts of the VM are still invalidated
  drm/amd/display: use unsigned types for local pipe and REG_GET counters
  ...
2026-06-17 10:21:00 +01:00

341 lines
9.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 Microsoft
*/
#include <linux/hyperv.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_panic.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_vblank_helper.h>
#include "hyperv_drm.h"
static int hyperv_blit_to_vram_rect(struct drm_framebuffer *fb,
const struct iosys_map *vmap,
struct drm_rect *rect)
{
struct hyperv_drm_device *hv = to_hv(fb->dev);
struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(hv->vram);
int idx;
if (!drm_dev_enter(&hv->dev, &idx))
return -ENODEV;
iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, rect));
drm_fb_memcpy(&dst, fb->pitches, vmap, fb, rect);
drm_dev_exit(idx);
return 0;
}
static int hyperv_connector_get_modes(struct drm_connector *connector)
{
struct hyperv_drm_device *hv = to_hv(connector->dev);
int count;
count = drm_add_modes_noedid(connector,
connector->dev->mode_config.max_width,
connector->dev->mode_config.max_height);
drm_set_preferred_mode(connector, hv->preferred_width,
hv->preferred_height);
return count;
}
static const struct drm_connector_helper_funcs hyperv_connector_helper_funcs = {
.get_modes = hyperv_connector_get_modes,
};
static const struct drm_connector_funcs hyperv_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static inline int hyperv_conn_init(struct hyperv_drm_device *hv)
{
drm_connector_helper_add(&hv->connector, &hyperv_connector_helper_funcs);
return drm_connector_init(&hv->dev, &hv->connector,
&hyperv_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
}
static int hyperv_check_size(struct hyperv_drm_device *hv, int w, int h,
struct drm_framebuffer *fb)
{
u32 pitch = w * (hv->screen_depth / 8);
if (fb)
pitch = fb->pitches[0];
if (pitch * h > hv->fb_size)
return -EINVAL;
return 0;
}
static const uint32_t hyperv_formats[] = {
DRM_FORMAT_XRGB8888,
};
static const uint64_t hyperv_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static void hyperv_crtc_helper_atomic_enable(struct drm_crtc *crtc,
struct drm_atomic_commit *state)
{
struct hyperv_drm_device *hv = to_hv(crtc->dev);
struct drm_plane *plane = &hv->plane;
struct drm_plane_state *plane_state = plane->state;
struct drm_crtc_state *crtc_state = crtc->state;
hyperv_hide_hw_ptr(hv->hdev);
hyperv_update_situation(hv->hdev, 1, hv->screen_depth,
crtc_state->mode.hdisplay,
crtc_state->mode.vdisplay,
plane_state->fb->pitches[0]);
drm_crtc_vblank_on(crtc);
}
static const struct drm_crtc_helper_funcs hyperv_crtc_helper_funcs = {
.atomic_check = drm_crtc_helper_atomic_check,
.atomic_flush = drm_crtc_vblank_atomic_flush,
.atomic_enable = hyperv_crtc_helper_atomic_enable,
.atomic_disable = drm_crtc_vblank_atomic_disable,
};
static const struct drm_crtc_funcs hyperv_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
DRM_CRTC_VBLANK_TIMER_FUNCS,
};
static int hyperv_plane_atomic_check(struct drm_plane *plane,
struct drm_atomic_commit *state)
{
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
struct hyperv_drm_device *hv = to_hv(plane->dev);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_crtc *crtc = plane_state->crtc;
struct drm_crtc_state *crtc_state = NULL;
int ret;
if (crtc)
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
false, false);
if (ret)
return ret;
if (!plane_state->visible)
return 0;
if (fb->pitches[0] * fb->height > hv->fb_size) {
drm_err(&hv->dev, "fb size requested by %s for %dX%d (pitch %d) greater than %ld\n",
current->comm, fb->width, fb->height, fb->pitches[0], hv->fb_size);
return -EINVAL;
}
return 0;
}
static void hyperv_plane_atomic_update(struct drm_plane *plane,
struct drm_atomic_commit *state)
{
struct hyperv_drm_device *hv = to_hv(plane->dev);
struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state);
struct drm_rect damage;
struct drm_rect dst_clip;
struct drm_atomic_helper_damage_iter iter;
drm_atomic_helper_damage_iter_init(&iter, old_state, new_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
dst_clip = new_state->dst;
if (!drm_rect_intersect(&dst_clip, &damage))
continue;
hyperv_blit_to_vram_rect(new_state->fb, &shadow_plane_state->data[0], &damage);
hyperv_update_dirt(hv->hdev, &damage);
}
}
static int hyperv_plane_get_scanout_buffer(struct drm_plane *plane,
struct drm_scanout_buffer *sb)
{
struct hyperv_drm_device *hv = to_hv(plane->dev);
struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(hv->vram);
if (plane->state && plane->state->fb) {
sb->format = plane->state->fb->format;
sb->width = plane->state->fb->width;
sb->height = plane->state->fb->height;
sb->pitch[0] = plane->state->fb->pitches[0];
sb->map[0] = map;
return 0;
}
return -ENODEV;
}
static void hyperv_plane_panic_flush(struct drm_plane *plane)
{
struct hyperv_drm_device *hv = to_hv(plane->dev);
struct drm_rect rect;
if (plane->state && plane->state->fb) {
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = plane->state->fb->width;
rect.y2 = plane->state->fb->height;
hyperv_update_dirt(hv->hdev, &rect);
}
vmbus_initiate_unload(true);
}
static const struct drm_plane_helper_funcs hyperv_plane_helper_funcs = {
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
.atomic_check = hyperv_plane_atomic_check,
.atomic_update = hyperv_plane_atomic_update,
.get_scanout_buffer = hyperv_plane_get_scanout_buffer,
.panic_flush = hyperv_plane_panic_flush,
};
static const struct drm_plane_funcs hyperv_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
DRM_GEM_SHADOW_PLANE_FUNCS,
};
static const struct drm_encoder_funcs hyperv_drm_simple_encoder_funcs_cleanup = {
.destroy = drm_encoder_cleanup,
};
static inline int hyperv_pipe_init(struct hyperv_drm_device *hv)
{
struct drm_device *dev = &hv->dev;
struct drm_encoder *encoder = &hv->encoder;
struct drm_plane *plane = &hv->plane;
struct drm_crtc *crtc = &hv->crtc;
struct drm_connector *connector = &hv->connector;
int ret;
ret = drm_universal_plane_init(dev, plane, 0,
&hyperv_plane_funcs,
hyperv_formats, ARRAY_SIZE(hyperv_formats),
hyperv_modifiers,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret)
return ret;
drm_plane_helper_add(plane, &hyperv_plane_helper_funcs);
drm_plane_enable_fb_damage_clips(plane);
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
&hyperv_crtc_funcs, NULL);
if (ret)
return ret;
drm_crtc_helper_add(crtc, &hyperv_crtc_helper_funcs);
encoder->possible_crtcs = drm_crtc_mask(crtc);
ret = drm_encoder_init(dev, encoder,
&hyperv_drm_simple_encoder_funcs_cleanup,
DRM_MODE_ENCODER_NONE, NULL);
if (ret)
return ret;
ret = hyperv_conn_init(hv);
if (ret) {
drm_err(dev, "Failed to initialized connector.\n");
return ret;
}
return drm_connector_attach_encoder(connector, encoder);
}
static enum drm_mode_status
hyperv_mode_valid(struct drm_device *dev,
const struct drm_display_mode *mode)
{
struct hyperv_drm_device *hv = to_hv(dev);
if (hyperv_check_size(hv, mode->hdisplay, mode->vdisplay, NULL))
return MODE_BAD;
return MODE_OK;
}
static const struct drm_mode_config_funcs hyperv_mode_config_funcs = {
.fb_create = drm_gem_fb_create_with_dirty,
.mode_valid = hyperv_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
int hyperv_mode_config_init(struct hyperv_drm_device *hv)
{
struct drm_device *dev = &hv->dev;
int ret;
ret = drmm_mode_config_init(dev);
if (ret) {
drm_err(dev, "Failed to initialized mode setting.\n");
return ret;
}
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = hv->screen_width_max;
dev->mode_config.max_height = hv->screen_height_max;
dev->mode_config.preferred_depth = hv->screen_depth;
dev->mode_config.prefer_shadow = 0;
dev->mode_config.funcs = &hyperv_mode_config_funcs;
ret = hyperv_pipe_init(hv);
if (ret) {
drm_err(dev, "Failed to initialized pipe.\n");
return ret;
}
ret = drm_vblank_init(dev, 1);
if (ret)
return ret;
drm_mode_config_reset(dev);
return 0;
}