The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-08-07 14:37 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-08-07 14:37 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alessandro Rinaldi, Alex Deucher, Alex Hung, Chenyu Chen,
	Fangzhi Zuo, George Zhang, Leo Li, Linux Kernel Mailing List,
	Linux Next Mailing List, Mario Limonciello, Matthew Schwartz,
	Rafal Ostrowski, Timur Kristóf, Travis K. Bangs,
	WenTao Liang

[-- Attachment #1: Type: text/plain, Size: 316027 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

between commits:

  ff209cd04845d ("drm/amd: Disable DP audio spread spectrum for Cyan Skillfish")
  8419331e64d92 ("drm/amd/display: Exit idle optimizations before programming")
  fbbaca9e20873 ("drm/amd/display: Fix missing DCE check in dm_gpureset_toggle_interrupts()")
  f39283eab44fb ("Revert "drm/amd/display: Restore 5s vbl offdelay for NV3x+ DGPUs"")
  48ab86360af11 ("drm/amd/display: check GRPH_FLIP status before sending event")
  8382cd234981a ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
  9fa26b9eed619 ("drm/amd/display: set new_stream to NULL after release")
  bad177fa75e60 ("drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05")
  cea54c52d82dd ("drm/amd/display: Set native cursor mode for disabled CRTCs")
  f1b5d8f9cc54a ("drm/amd/display: Fix backlight max_brightness to match exported range")

from the origin tree and commits:

  05984e29520a2 ("drm/amd/display: Exit idle optimizations before programming")
  1a16dfe5359f1 ("drm/amd/display: Don't use tiling flags anymore")
  87a6dab12fc06 ("drm/amd/display: add cursor module")
  09dd9fbc0b2dc ("drm/amd/display: add FreeSync/VRR module")
  66517ca0cd8bb ("drm/amd/display: move GPU mem helpers to services")
  0b9bd593f0a2c ("drm/amd/display: move watermarks table to pp_smu")
  e278e0bf3ed30 ("drm/amd/display: move stutter quirk to quirks file")
  a648ed2bfafab ("drm/amd/display: move scaling helper to connector")
  c1199393ec559 ("drm/amd/display: Refactor surface_update_flags to flat struct with helpers")
  0e967e086e751 ("drm/amd/display: Extract connector and encoder code to amdgpu_dm_connector")
  0618dec494157 ("drm/amd/display: Move HPD and IRQ handler code to amdgpu_dm_irq")
  4734e045f49d9 ("drm/amd/display: Extract DMUB code to amdgpu_dm_dmub")
  ee55bf7d6a63f ("drm/amd/display: Extract audio code to amdgpu_dm_audio")
  f5165625b8b27 ("drm/amd/display: Extract backlight code to amdgpu_dm_backlight")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 941c1a3128249,e421c3c81778d..0000000000000
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@@ -66,6 -66,13 +66,13 @@@
  #endif
  #include "amdgpu_dm_psr.h"
  #include "amdgpu_dm_replay.h"
+ #include "amdgpu_dm_backlight.h"
+ #include "amdgpu_dm_audio.h"
+ #include "amdgpu_dm_dmub.h"
+ #include "amdgpu_dm_connector.h"
+ #include "amdgpu_dm_pp_smu.h"
+ #include "amdgpu_dm_freesync.h"
+ #include "amdgpu_dm_cursor.h"
  
  #include "ivsrcid/ivsrcid_vislands30.h"
  
@@@ -94,7 -101,6 +101,6 @@@
  #include <drm/drm_mode.h>
  #include <drm/drm_utils.h>
  #include <drm/drm_vblank.h>
- #include <drm/drm_audio_component.h>
  #include <drm/drm_colorop.h>
  #include <drm/drm_gem_atomic_helper.h>
  
@@@ -107,60 -113,9 +113,9 @@@
  #include "modules/inc/mod_power.h"
  #include "modules/power/power_helpers.h"
  
- static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch");
- 
- #define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB);
- #define FIRMWARE_SIENNA_CICHLID_DMUB "amdgpu/sienna_cichlid_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB);
- #define FIRMWARE_NAVY_FLOUNDER_DMUB "amdgpu/navy_flounder_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB);
- #define FIRMWARE_GREEN_SARDINE_DMUB "amdgpu/green_sardine_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB);
- #define FIRMWARE_VANGOGH_DMUB "amdgpu/vangogh_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB);
- #define FIRMWARE_DIMGREY_CAVEFISH_DMUB "amdgpu/dimgrey_cavefish_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB);
- #define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB);
- #define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB);
- #define FIRMWARE_DCN_314_DMUB "amdgpu/dcn_3_1_4_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_314_DMUB);
- #define FIRMWARE_DCN_315_DMUB "amdgpu/dcn_3_1_5_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB);
- #define FIRMWARE_DCN316_DMUB "amdgpu/dcn_3_1_6_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB);
- 
- #define FIRMWARE_DCN_V3_2_0_DMCUB "amdgpu/dcn_3_2_0_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_0_DMCUB);
- #define FIRMWARE_DCN_V3_2_1_DMCUB "amdgpu/dcn_3_2_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_1_DMCUB);
- 
- #define FIRMWARE_RAVEN_DMCU		"amdgpu/raven_dmcu.bin"
  MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU);
- 
- #define FIRMWARE_NAVI12_DMCU            "amdgpu/navi12_dmcu.bin"
  MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
  
- #define FIRMWARE_DCN_35_DMUB "amdgpu/dcn_3_5_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB);
- 
- #define FIRMWARE_DCN_351_DMUB "amdgpu/dcn_3_5_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB);
- 
- #define FIRMWARE_DCN_36_DMUB "amdgpu/dcn_3_6_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB);
- 
- #define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB);
- 
- #define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB);
- 
- #define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB);
- 
  /**
   * DOC: overview
   *
@@@ -174,46 -129,6 +129,6 @@@
  /* basic init/fini API */
  static int amdgpu_dm_init(struct amdgpu_device *adev);
  static void amdgpu_dm_fini(struct amdgpu_device *adev);
- static bool is_freesync_video_mode(const struct drm_display_mode *mode, struct amdgpu_dm_connector *aconnector);
- static void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
- static struct amdgpu_i2c_adapter *
- create_i2c(struct ddc_service *ddc_service, bool oem);
- 
- static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
- {
- 	switch (link->dpcd_caps.dongle_type) {
- 	case DISPLAY_DONGLE_NONE:
- 		return DRM_MODE_SUBCONNECTOR_Native;
- 	case DISPLAY_DONGLE_DP_VGA_CONVERTER:
- 		return DRM_MODE_SUBCONNECTOR_VGA;
- 	case DISPLAY_DONGLE_DP_DVI_CONVERTER:
- 	case DISPLAY_DONGLE_DP_DVI_DONGLE:
- 		return DRM_MODE_SUBCONNECTOR_DVID;
- 	case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
- 	case DISPLAY_DONGLE_DP_HDMI_DONGLE:
- 		return DRM_MODE_SUBCONNECTOR_HDMIA;
- 	case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
- 	default:
- 		return DRM_MODE_SUBCONNECTOR_Unknown;
- 	}
- }
- 
- static void update_subconnector_property(struct amdgpu_dm_connector *aconnector)
- {
- 	struct dc_link *link = aconnector->dc_link;
- 	struct drm_connector *connector = &aconnector->base;
- 	enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
- 		return;
- 
- 	if (aconnector->dc_sink)
- 		subconnector = get_subconnector_type(link);
- 
- 	drm_object_property_set_value(&connector->base,
- 			connector->dev->mode_config.dp_subconnector_property,
- 			subconnector);
- }
  
  /*
   * initializes drm_device display related structures, based on the information
@@@ -226,32 -141,19 +141,19 @@@ static int amdgpu_dm_initialize_drm_dev
  /* removes and deallocates the drm structures, created by the above function */
  static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
  
- static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
- 				    struct amdgpu_dm_connector *amdgpu_dm_connector,
- 				    u32 link_index,
- 				    struct amdgpu_encoder *amdgpu_encoder);
- static int amdgpu_dm_encoder_init(struct drm_device *dev,
- 				  struct amdgpu_encoder *aencoder,
- 				  uint32_t link_index);
- 
- static int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
- 
  static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state);
  static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state);
+ STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
  
  static int amdgpu_dm_atomic_check(struct drm_device *dev,
  				  struct drm_atomic_commit *state);
  
- static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
- static void handle_hpd_rx_irq(void *param);
+ static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
+ {
+ 	if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter)
+ 		dc_exit_ips_for_hw_access(dc);
+ }
  
- static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx,
- 					 u32 user_brightness);
- 
- static bool
- is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
- 				 struct drm_crtc_state *new_crtc_state);
  /*
   * dm_vblank_get_counter
   *
@@@ -265,7 -167,7 +167,7 @@@
   * @return
   * Counter for vertical blanks
   */
- static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+ STATIC_IFN_KUNIT u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
  {
  	struct amdgpu_crtc *acrtc = NULL;
  
@@@ -282,9 -184,10 +184,10 @@@
  
  	return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);
  }
+ EXPORT_IF_KUNIT(dm_vblank_get_counter);
  
- static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
- 				  u32 *vbl, u32 *position)
+ STATIC_IFN_KUNIT int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ 					    u32 *vbl, u32 *position)
  {
  	u32 v_blank_start = 0, v_blank_end = 0, h_position = 0, v_position = 0;
  	struct amdgpu_crtc *acrtc = NULL;
@@@ -319,70 -222,35 +222,35 @@@
  
  	return 0;
  }
+ EXPORT_IF_KUNIT(dm_crtc_get_scanoutpos);
  
- static bool dm_is_idle(struct amdgpu_ip_block *ip_block)
+ STATIC_IFN_KUNIT bool dm_is_idle(struct amdgpu_ip_block *ip_block)
  {
  	/* XXX todo */
  	return true;
  }
+ EXPORT_IF_KUNIT(dm_is_idle);
  
- static int dm_wait_for_idle(struct amdgpu_ip_block *ip_block)
+ STATIC_IFN_KUNIT int dm_wait_for_idle(struct amdgpu_ip_block *ip_block)
  {
  	/* XXX todo */
  	return 0;
  }
+ EXPORT_IF_KUNIT(dm_wait_for_idle);
  
- static bool dm_check_soft_reset(struct amdgpu_ip_block *ip_block)
- {
- 	return false;
- }
- 
- static int dm_soft_reset(struct amdgpu_ip_block *ip_block)
+ STATIC_IFN_KUNIT int dm_soft_reset(struct amdgpu_ip_block *ip_block)
  {
  	/* XXX todo */
  	return 0;
  }
- 
- static struct amdgpu_crtc *
- get_crtc_by_otg_inst(struct amdgpu_device *adev,
- 		     int otg_inst)
- {
- 	struct drm_device *dev = adev_to_drm(adev);
- 	struct drm_crtc *crtc;
- 	struct amdgpu_crtc *amdgpu_crtc;
- 
- 	if (WARN_ON(otg_inst == -1))
- 		return adev->mode_info.crtcs[0];
- 
- 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- 		amdgpu_crtc = to_amdgpu_crtc(crtc);
- 
- 		if (amdgpu_crtc->otg_inst == otg_inst)
- 			return amdgpu_crtc;
- 	}
- 
- 	return NULL;
- }
- 
- static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
- 					      struct dm_crtc_state *new_state)
- {
- 	if (new_state->stream->adjust.timing_adjust_pending)
- 		return true;
- 	if (new_state->freesync_config.state ==  VRR_STATE_ACTIVE_FIXED)
- 		return true;
- 	else if (amdgpu_dm_crtc_vrr_active(old_state) != amdgpu_dm_crtc_vrr_active(new_state))
- 		return true;
- 	else
- 		return false;
- }
+ EXPORT_IF_KUNIT(dm_soft_reset);
  
  /*
   * DC will program planes with their z-order determined by their ordering
   * in the dc_surface_updates array. This comparator is used to sort them
   * by descending zpos.
   */
- static int dm_plane_layer_index_cmp(const void *a, const void *b)
+ STATIC_IFN_KUNIT int dm_plane_layer_index_cmp(const void *a, const void *b)
  {
  	const struct dc_surface_update *sa = (struct dc_surface_update *)a;
  	const struct dc_surface_update *sb = (struct dc_surface_update *)b;
@@@ -390,6 -258,7 +258,7 @@@
  	/* Sort by descending dc_plane layer_index (i.e. normalized_zpos) */
  	return sb->surface->layer_index - sa->surface->layer_index;
  }
+ EXPORT_IF_KUNIT(dm_plane_layer_index_cmp);
  
  /**
   * update_planes_and_stream_adapter() - Send planes to be updated in DC
@@@ -430,1098 -299,24 +299,24 @@@ static inline bool update_planes_and_st
  					   stream_update);
  }
  
- /**
-  * dm_pflip_high_irq() - Handle pageflip interrupt
-  * @interrupt_params: ignored
-  *
-  * Handles the pageflip interrupt by notifying all interested parties
-  * that the pageflip has been completed.
-  */
- static void dm_pflip_high_irq(void *interrupt_params)
- {
- 	struct amdgpu_crtc *amdgpu_crtc;
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct drm_device *dev = adev_to_drm(adev);
- 	unsigned long flags;
- 	struct drm_pending_vblank_event *e;
- 	u32 vpos, hpos, v_blank_start, v_blank_end;
- 	bool vrr_active;
- 
- 	amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
- 
- 	/* IRQ could occur when in initial stage */
- 	/* TODO work and BO cleanup */
- 	if (amdgpu_crtc == NULL) {
- 		drm_dbg_state(dev, "CRTC is null, returning.\n");
- 		return;
- 	}
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 
- 	if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
- 		drm_dbg_state(dev,
- 			      "amdgpu_crtc->pflip_status = %d != AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p]\n",
- 			      amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED,
- 			      amdgpu_crtc->crtc_id, amdgpu_crtc);
- 		spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 		return;
- 	}
- 
- 	/* page flip completed. */
- 	e = amdgpu_crtc->event;
- 	amdgpu_crtc->event = NULL;
- 
- 	WARN_ON(!e);
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(amdgpu_crtc);
- 
- 	/* Fixed refresh rate, or VRR scanout position outside front-porch? */
- 	if (!vrr_active ||
- 	    !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start,
- 				      &v_blank_end, &hpos, &vpos) ||
- 	    (vpos < v_blank_start)) {
- 		/* Update to correct count and vblank timestamp if racing with
- 		 * vblank irq. This also updates to the correct vblank timestamp
- 		 * even in VRR mode, as scanout is past the front-porch atm.
- 		 */
- 		drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
- 
- 		/* Wake up userspace by sending the pageflip event with proper
- 		 * count and timestamp of vblank of flip completion.
- 		 */
- 		if (e) {
- 			drm_crtc_send_vblank_event(&amdgpu_crtc->base, e);
- 
- 			/* Event sent, so done with vblank for this flip */
- 			drm_crtc_vblank_put(&amdgpu_crtc->base);
- 		}
- 	} else if (e) {
- 		/* VRR active and inside front-porch: vblank count and
- 		 * timestamp for pageflip event will only be up to date after
- 		 * drm_crtc_handle_vblank() has been executed from late vblank
- 		 * irq handler after start of back-porch (vline 0). We queue the
- 		 * pageflip event for send-out by drm_crtc_handle_vblank() with
- 		 * updated timestamp and count, once it runs after us.
- 		 *
- 		 * We need to open-code this instead of using the helper
- 		 * drm_crtc_arm_vblank_event(), as that helper would
- 		 * call drm_crtc_accurate_vblank_count(), which we must
- 		 * not call in VRR mode while we are in front-porch!
- 		 */
- 
- 		/* sequence will be replaced by real count during send-out. */
- 		e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base);
- 		e->pipe = amdgpu_crtc->crtc_id;
- 
- 		list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list);
- 		e = NULL;
- 	}
- 
- 	/* Keep track of vblank of this flip for flip throttling. We use the
- 	 * cooked hw counter, as that one incremented at start of this vblank
- 	 * of pageflip completion, so last_flip_vblank is the forbidden count
- 	 * for queueing new pageflips if vsync + VRR is enabled.
- 	 */
- 	amdgpu_crtc->dm_irq_params.last_flip_vblank =
- 		amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base);
- 
- 	amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 
- 	drm_dbg_state(dev,
- 		      "crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
- 		      amdgpu_crtc->crtc_id, amdgpu_crtc, vrr_active, (int)!e);
- }
- 
- static void dm_handle_vmin_vmax_update(struct work_struct *offload_work)
- {
- 	struct vupdate_offload_work *work = container_of(offload_work, struct vupdate_offload_work, work);
- 	struct amdgpu_device *adev = work->adev;
- 	struct dc_stream_state *stream = work->stream;
- 	struct dc_crtc_timing_adjust *adjust = work->adjust;
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	dc_stream_adjust_vmin_vmax(adev->dm.dc, stream, adjust);
- 	mutex_unlock(&adev->dm.dc_lock);
- 
- 	dc_stream_release(stream);
- 	kfree(work->adjust);
- 	kfree(work);
- }
- 
- static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
- 	struct dc_stream_state *stream,
- 	struct dc_crtc_timing_adjust *adjust)
- {
- 	struct vupdate_offload_work *offload_work = kzalloc_obj(*offload_work,
- 								GFP_NOWAIT);
- 	if (!offload_work) {
- 		drm_dbg_driver(adev_to_drm(adev), "Failed to allocate vupdate_offload_work\n");
- 		return;
- 	}
- 
- 	struct dc_crtc_timing_adjust *adjust_copy = kzalloc_obj(*adjust_copy,
- 								GFP_NOWAIT);
- 	if (!adjust_copy) {
- 		drm_dbg_driver(adev_to_drm(adev), "Failed to allocate adjust_copy\n");
- 		kfree(offload_work);
- 		return;
- 	}
- 
- 	dc_stream_retain(stream);
- 	memcpy(adjust_copy, adjust, sizeof(*adjust_copy));
- 
- 	INIT_WORK(&offload_work->work, dm_handle_vmin_vmax_update);
- 	offload_work->adev = adev;
- 	offload_work->stream = stream;
- 	offload_work->adjust = adjust_copy;
- 
- 	queue_work(system_percpu_wq, &offload_work->work);
- }
- 
- /**
-  * dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling
-  * @adev: amdgpu device
-  * @acrtc: the CRTC to service
-  *
-  * Performs writeback completion, vblank event handling, CRC processing, VRR BTR
-  * updates and pageflip completion delivery.
-  *
-  * On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from
-  * dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank
-  * from dm_crtc_high_irq().
-  */
- static void dm_crtc_high_irq_handler(struct amdgpu_device *adev,
- 				     struct amdgpu_crtc *acrtc)
- {
- 	struct drm_writeback_job *job;
- 	unsigned long flags;
- 	int vrr_active;
- 	bool is_dcn = amdgpu_ip_version(adev, DCE_HWIP, 0) != 0;
- 
- 	if (acrtc->wb_conn) {
- 		spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
- 
- 		if (acrtc->wb_pending) {
- 			job = list_first_entry_or_null(&acrtc->wb_conn->job_queue,
- 						       struct drm_writeback_job,
- 						       list_entry);
- 			acrtc->wb_pending = false;
- 			spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
- 
- 			if (job) {
- 				unsigned int v_total, refresh_hz;
- 				struct dc_stream_state *stream = acrtc->dm_irq_params.stream;
- 
- 				v_total = stream->adjust.v_total_max ?
- 					  stream->adjust.v_total_max : stream->timing.v_total;
- 				refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz *
- 					     100LL, (v_total * stream->timing.h_total));
- 				mdelay(1000 / refresh_hz);
- 
- 				drm_writeback_signal_completion(acrtc->wb_conn, 0);
- 				dc_stream_fc_disable_writeback(adev->dm.dc,
- 							       acrtc->dm_irq_params.stream, 0);
- 			}
- 		} else
- 			spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
- 	}
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
- 
- 	drm_dbg_vbl(adev_to_drm(adev),
- 		    "crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
- 		    vrr_active, acrtc->dm_irq_params.active_planes);
- 
- 	/**
- 	 * Core vblank handling.
- 	 *
- 	 * On DCN this handler runs at VUPDATE_NO_LOCK, the register latch
- 	 * point, which is the correct place to timestamp both VRR and non-VRR
- 	 * vblanks.
- 	 *
- 	 * On DCE this handler runs at the start of front-porch, where only
- 	 * non-VRR timestamping is valid; VRR vblank is deferred to
- 	 * dm_vupdate_high_irq() after end of front-porch.
- 	 */
- 	if (is_dcn || !vrr_active)
- 		amdgpu_dm_crtc_handle_vblank(acrtc);
- 
- 	/**
- 	 * Following stuff must happen at start of vblank, for crc
- 	 * computation and below-the-range btr support in vrr mode.
- 	 */
- 	amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
- 
- 	/* BTR updates need to happen before VUPDATE on Vega and above. */
- 	if (adev->family < AMDGPU_FAMILY_AI)
- 		return;
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 
- 	if (acrtc->dm_irq_params.stream &&
- 		acrtc->dm_irq_params.vrr_params.supported) {
- 		bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
- 		bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
- 		bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE;
- 
- 		mod_freesync_handle_v_update(adev->dm.freesync_module,
- 					     acrtc->dm_irq_params.stream,
- 					     &acrtc->dm_irq_params.vrr_params);
- 
- 		/* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */
- 		if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
- 			schedule_dc_vmin_vmax(adev, acrtc->dm_irq_params.stream,
- 					&acrtc->dm_irq_params.vrr_params.adjust);
- 		}
- 	}
- 
- 	/*
- 	 * Deliver pageflip completion events (DCN only).
- 	 *
- 	 * Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch
- 	 * point. Deliver any pending pageflip completion event from here,
- 	 * once HW has consumed the new address (the OTG no longer reports a
- 	 * pending flip).
- 	 *
- 	 * Also handle the case here where there aren't any active planes and
- 	 * DCN HUBP may be clock-gated, so the flip-pending status may be
- 	 * undefined.
- 	 */
- 	if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
- 	    acrtc->event) {
- 
- 		if (!dc_get_flip_pending_on_otg(adev->dm.dc, acrtc->otg_inst)) {
- 			drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
- 			acrtc->event = NULL;
- 			drm_crtc_vblank_put(&acrtc->base);
- 			acrtc->pflip_status = AMDGPU_FLIP_NONE;
- 		}
- 		/*
- 		 * If the flip is still pending, leave it armed and
- 		 * retry on the next vupdate.
- 		 */
- 	} else if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
- 		   acrtc->dm_irq_params.active_planes == 0) {
- 
- 		if (acrtc->event) {
- 			drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
- 			acrtc->event = NULL;
- 			drm_crtc_vblank_put(&acrtc->base);
- 		}
- 		acrtc->pflip_status = AMDGPU_FLIP_NONE;
- 	}
- 
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- }
- 
- static void dm_vupdate_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 	struct drm_device *drm_dev;
- 	struct drm_vblank_crtc *vblank;
- 	ktime_t frame_duration_ns, previous_timestamp;
- 	unsigned long flags;
- 	int vrr_active;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);
- 	if (!acrtc)
- 		return;
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
- 	drm_dev = acrtc->base.dev;
- 	vblank = drm_crtc_vblank_crtc(&acrtc->base);
- 	previous_timestamp = atomic64_read(&irq_params->previous_timestamp);
- 	frame_duration_ns = vblank->time - previous_timestamp;
- 
- 	if (frame_duration_ns > 0) {
- 		trace_amdgpu_refresh_rate_track(acrtc->base.index,
- 					frame_duration_ns,
- 					ktime_divns(NSEC_PER_SEC, frame_duration_ns));
- 		atomic64_set(&irq_params->previous_timestamp, vblank->time);
- 	}
- 
- 	drm_dbg_vbl(drm_dev,
- 		    "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
- 		    vrr_active);
- 
- 	/*
- 	 * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver
- 	 * vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are
- 	 * not used. Run the full handler here.
- 	 */
- 	if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
- 		dm_crtc_high_irq_handler(adev, acrtc);
- 		return;
- 	}
- 
- 	/* DCE only below. */
- 
- 	/* Core vblank handling is done here after end of front-porch in
- 	 * vrr mode, as vblank timestamping will give valid results
- 	 * while now done after front-porch. This will also deliver
- 	 * page-flip completion events that have been queued to us
- 	 * if a pageflip happened inside front-porch.
- 	 */
- 	if (vrr_active && acrtc->dm_irq_params.stream) {
- 		bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
- 		bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
- 		bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state
- 			== VRR_STATE_ACTIVE_VARIABLE;
- 
- 		amdgpu_dm_crtc_handle_vblank(acrtc);
- 
- 		/* BTR processing for pre-DCE12 ASICs */
- 		if (adev->family < AMDGPU_FAMILY_AI) {
- 			spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 			mod_freesync_handle_v_update(
- 				adev->dm.freesync_module,
- 				acrtc->dm_irq_params.stream,
- 				&acrtc->dm_irq_params.vrr_params);
- 
- 			if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
- 				schedule_dc_vmin_vmax(adev,
- 					acrtc->dm_irq_params.stream,
- 					&acrtc->dm_irq_params.vrr_params.adjust);
- 			}
- 			spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 		}
- 	}
- }
- 
- /**
-  * dm_crtc_high_irq() - Handles CRTC interrupt
-  * @interrupt_params: used for determining the CRTC instance
-  *
-  * Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler.
-  *
-  * Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is
-  * driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq().
-  */
- static void dm_crtc_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
- 	if (!acrtc)
- 		return;
- 
- 	dm_crtc_high_irq_handler(adev, acrtc);
- }
- 
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- /**
-  * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
-  * DCN generation ASICs
-  * @interrupt_params: interrupt parameters
-  *
-  * Used to set crc window/read out crc value at vertical line 0 position
-  */
- static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VLINE0);
- 
- 	if (!acrtc)
- 		return;
- 
- 	amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base);
- }
- #endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
- 
- /**
-  * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * Dmub AUX or SET_CONFIG command completion processing callback
-  * Copies dmub notification to DM which is to be read by AUX command.
-  * issuing thread and also signals the event to wake up the thread.
-  */
- static void dmub_aux_setconfig_callback(struct amdgpu_device *adev,
- 					struct dmub_notification *notify)
- {
- 	if (adev->dm.dmub_notify)
- 		memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification));
- 	if (notify->type == DMUB_NOTIFICATION_AUX_REPLY)
- 		complete(&adev->dm.dmub_aux_transfer_done);
- }
- 
- static void dmub_aux_fused_io_callback(struct amdgpu_device *adev,
- 					struct dmub_notification *notify)
- {
- 	if (!adev || !notify) {
- 		ASSERT(false);
- 		return;
- 	}
- 
- 	const struct dmub_cmd_fused_request *req = &notify->fused_request;
- 	const uint8_t ddc_line = req->u.aux.ddc_line;
- 
- 	if (ddc_line >= ARRAY_SIZE(adev->dm.fused_io)) {
- 		ASSERT(false);
- 		return;
- 	}
- 
- 	struct fused_io_sync *sync = &adev->dm.fused_io[ddc_line];
- 
- 	static_assert(sizeof(*req) <= sizeof(sync->reply_data), "Size mismatch");
- 	memcpy(sync->reply_data, req, sizeof(*req));
- 	complete(&sync->replied);
- }
- 
- /**
-  * dmub_hpd_callback - DMUB HPD interrupt processing callback.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * Dmub Hpd interrupt processing callback. Gets displayindex through the
-  * ink index and calls helper to do the processing.
-  */
- static void dmub_hpd_callback(struct amdgpu_device *adev,
- 			      struct dmub_notification *notify)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct amdgpu_dm_connector *hpd_aconnector = NULL;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter iter;
- 	struct dc_link *link;
- 	u8 link_index = 0;
- 	struct drm_device *dev;
- 
- 	if (adev == NULL)
- 		return;
- 
- 	if (notify == NULL) {
- 		drm_err(adev_to_drm(adev), "DMUB HPD callback notification was NULL");
- 		return;
- 	}
- 
- 	if (notify->link_index > adev->dm.dc->link_count) {
- 		drm_err(adev_to_drm(adev), "DMUB HPD index (%u)is abnormal", notify->link_index);
- 		return;
- 	}
- 
- 	/* Skip DMUB HPD IRQ in suspend/resume. We will probe them later. */
- 	if (notify->type == DMUB_NOTIFICATION_HPD && adev->in_suspend) {
- 		drm_info(adev_to_drm(adev), "Skip DMUB HPD IRQ callback in suspend/resume\n");
- 		return;
- 	}
- 
- 	link_index = notify->link_index;
- 	link = adev->dm.dc->links[link_index];
- 	dev = adev->dm.ddev;
- 
- 	drm_connector_list_iter_begin(dev, &iter);
- 	drm_for_each_connector_iter(connector, &iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (link && aconnector->dc_link == link) {
- 			if (notify->type == DMUB_NOTIFICATION_HPD)
- 				drm_info(adev_to_drm(adev), "DMUB HPD IRQ callback: link_index=%u\n", link_index);
- 			else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ)
- 				drm_info(adev_to_drm(adev), "DMUB HPD RX IRQ callback: link_index=%u\n", link_index);
- 			else
- 				drm_warn(adev_to_drm(adev), "DMUB Unknown HPD callback type %d, link_index=%u\n",
- 						notify->type, link_index);
- 
- 			hpd_aconnector = aconnector;
- 			break;
- 		}
- 	}
- 	drm_connector_list_iter_end(&iter);
- 
- 	if (hpd_aconnector) {
- 		if (notify->type == DMUB_NOTIFICATION_HPD) {
- 			if (hpd_aconnector->dc_link->hpd_status == (notify->hpd_status == DP_HPD_PLUG))
- 				drm_warn(adev_to_drm(adev), "DMUB reported hpd status unchanged. link_index=%u\n", link_index);
- 			handle_hpd_irq_helper(hpd_aconnector);
- 		} else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) {
- 			handle_hpd_rx_irq(hpd_aconnector);
- 		}
- 	}
- }
- 
- /**
-  * dmub_hpd_sense_callback - DMUB HPD sense processing callback.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * HPD sense changes can occur during low power states and need to be
-  * notified from firmware to driver.
-  */
- static void dmub_hpd_sense_callback(struct amdgpu_device *adev,
- 			      struct dmub_notification *notify)
- {
- 	drm_dbg_driver(adev_to_drm(adev), "DMUB HPD SENSE callback.\n");
- }
- 
- /**
-  * register_dmub_notify_callback - Sets callback for DMUB notify
-  * @adev: amdgpu_device pointer
-  * @type: Type of dmub notification
-  * @callback: Dmub interrupt callback function
-  * @dmub_int_thread_offload: offload indicator
-  *
-  * API to register a dmub callback handler for a dmub notification
-  * Also sets indicator whether callback processing to be offloaded.
-  * to dmub interrupt handling thread
-  * Return: true if successfully registered, false if there is existing registration
-  */
- static bool register_dmub_notify_callback(struct amdgpu_device *adev,
- 					  enum dmub_notification_type type,
- 					  dmub_notify_interrupt_callback_t callback,
- 					  bool dmub_int_thread_offload)
- {
- 	if (callback != NULL && type < ARRAY_SIZE(adev->dm.dmub_thread_offload)) {
- 		adev->dm.dmub_callback[type] = callback;
- 		adev->dm.dmub_thread_offload[type] = dmub_int_thread_offload;
- 	} else
- 		return false;
- 
- 	return true;
- }
- 
- static void dm_handle_hpd_work(struct work_struct *work)
- {
- 	struct dmub_hpd_work *dmub_hpd_wrk;
- 
- 	dmub_hpd_wrk = container_of(work, struct dmub_hpd_work, handle_hpd_work);
- 
- 	if (!dmub_hpd_wrk->dmub_notify) {
- 		drm_err(adev_to_drm(dmub_hpd_wrk->adev), "dmub_hpd_wrk dmub_notify is NULL");
- 		return;
- 	}
- 
- 	if (dmub_hpd_wrk->dmub_notify->type < ARRAY_SIZE(dmub_hpd_wrk->adev->dm.dmub_callback)) {
- 		dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev,
- 		dmub_hpd_wrk->dmub_notify);
- 	}
- 
- 	kfree(dmub_hpd_wrk->dmub_notify);
- 	kfree(dmub_hpd_wrk);
- 
- }
- 
- static const char *dmub_notification_type_str(enum dmub_notification_type e)
- {
- 	switch (e) {
- 	case DMUB_NOTIFICATION_NO_DATA:
- 		return "NO_DATA";
- 	case DMUB_NOTIFICATION_AUX_REPLY:
- 		return "AUX_REPLY";
- 	case DMUB_NOTIFICATION_HPD:
- 		return "HPD";
- 	case DMUB_NOTIFICATION_HPD_IRQ:
- 		return "HPD_IRQ";
- 	case DMUB_NOTIFICATION_SET_CONFIG_REPLY:
- 		return "SET_CONFIG_REPLY";
- 	case DMUB_NOTIFICATION_DPIA_NOTIFICATION:
- 		return "DPIA_NOTIFICATION";
- 	case DMUB_NOTIFICATION_HPD_SENSE_NOTIFY:
- 		return "HPD_SENSE_NOTIFY";
- 	case DMUB_NOTIFICATION_FUSED_IO:
- 		return "FUSED_IO";
- 	default:
- 		return "<unknown>";
- 	}
- }
- 
- #define DMUB_TRACE_MAX_READ 64
- /**
-  * dm_dmub_outbox1_low_irq() - Handles Outbox interrupt
-  * @interrupt_params: used for determining the Outbox instance
-  *
-  * Handles the Outbox Interrupt
-  * event handler.
-  */
- static void dm_dmub_outbox1_low_irq(void *interrupt_params)
- {
- 	struct dmub_notification notify = {0};
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_display_manager *dm = &adev->dm;
- 	struct dmcub_trace_buf_entry entry = { 0 };
- 	u32 count = 0;
- 	struct dmub_hpd_work *dmub_hpd_wrk;
- 
- 	do {
- 		if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) {
- 			trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count,
- 							entry.param0, entry.param1);
- 
- 			drm_dbg_driver(adev_to_drm(adev), "trace_code:%u, tick_count:%u, param0:%u, param1:%u\n",
- 				 entry.trace_code, entry.tick_count, entry.param0, entry.param1);
- 		} else
- 			break;
- 
- 		count++;
- 
- 	} while (count <= DMUB_TRACE_MAX_READ);
- 
- 	if (count > DMUB_TRACE_MAX_READ)
- 		drm_dbg_driver(adev_to_drm(adev), "Warning : count > DMUB_TRACE_MAX_READ");
- 
- 	if (dc_enable_dmub_notifications(adev->dm.dc) &&
- 		irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) {
- 
- 		do {
- 			dc_stat_get_dmub_notification(adev->dm.dc, &notify);
- 			if (notify.type >= ARRAY_SIZE(dm->dmub_thread_offload)) {
- 				drm_err(adev_to_drm(adev), "DM: notify type %d invalid!", notify.type);
- 				continue;
- 			}
- 			if (!dm->dmub_callback[notify.type]) {
- 				drm_warn(adev_to_drm(adev), "DMUB notification skipped due to no handler: type=%s\n",
- 					dmub_notification_type_str(notify.type));
- 				continue;
- 			}
- 			if (dm->dmub_thread_offload[notify.type] == true) {
- 				dmub_hpd_wrk = kzalloc_obj(*dmub_hpd_wrk,
- 							   GFP_ATOMIC);
- 				if (!dmub_hpd_wrk) {
- 					drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk");
- 					return;
- 				}
- 				dmub_hpd_wrk->dmub_notify = kmemdup(&notify, sizeof(struct dmub_notification),
- 								    GFP_ATOMIC);
- 				if (!dmub_hpd_wrk->dmub_notify) {
- 					kfree(dmub_hpd_wrk);
- 					drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk->dmub_notify");
- 					return;
- 				}
- 				INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work);
- 				dmub_hpd_wrk->adev = adev;
- 				queue_work(adev->dm.delayed_hpd_wq, &dmub_hpd_wrk->handle_hpd_work);
- 			} else {
- 				dm->dmub_callback[notify.type](adev, &notify);
- 			}
- 		} while (notify.pending_notification);
- 	}
- }
- 
- static int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
- 		  enum amd_clockgating_state state)
+ STATIC_IFN_KUNIT int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
+ 					      enum amd_clockgating_state state)
  {
  	return 0;
  }
+ EXPORT_IF_KUNIT(dm_set_clockgating_state);
  
- static int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
- 		  enum amd_powergating_state state)
+ STATIC_IFN_KUNIT int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
+ 					      enum amd_powergating_state state)
  {
  	return 0;
  }
+ EXPORT_IF_KUNIT(dm_set_powergating_state);
  
  /* Prototypes of private functions */
  static int dm_early_init(struct amdgpu_ip_block *ip_block);
  
  /* Allocate memory for FBC compressed data  */
- static void amdgpu_dm_fbc_init(struct drm_connector *connector)
- {
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct dm_compressor_info *compressor = &adev->dm.compressor;
- 	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
- 	struct drm_display_mode *mode;
- 	unsigned long max_size = 0;
- 
- 	if (adev->dm.dc->fbc_compressor == NULL)
- 		return;
- 
- 	if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP)
- 		return;
- 
- 	if (compressor->bo_ptr)
- 		return;
- 
- 
- 	list_for_each_entry(mode, &connector->modes, head) {
- 		if (max_size < (unsigned long) mode->htotal * mode->vtotal)
- 			max_size = (unsigned long) mode->htotal * mode->vtotal;
- 	}
- 
- 	if (max_size) {
- 		int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE,
- 			    AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr,
- 			    &compressor->gpu_addr, &compressor->cpu_addr);
- 
- 		if (r)
- 			drm_err(adev_to_drm(adev), "DM: Failed to initialize FBC\n");
- 		else {
- 			adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr;
- 			drm_info(adev_to_drm(adev), "DM: FBC alloc %lu\n", max_size*4);
- 		}
- 
- 	}
- 
- }
- 
- static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
- 					  int pipe, bool *enabled,
- 					  unsigned char *buf, int max_bytes)
- {
- 	struct drm_device *dev = dev_get_drvdata(kdev);
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter conn_iter;
- 	struct amdgpu_dm_connector *aconnector;
- 	int ret = 0;
- 
- 	*enabled = false;
- 
- 	mutex_lock(&adev->dm.audio_lock);
- 
- 	drm_connector_list_iter_begin(dev, &conn_iter);
- 	drm_for_each_connector_iter(connector, &conn_iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (aconnector->audio_inst != port)
- 			continue;
- 
- 		*enabled = true;
- 		mutex_lock(&connector->eld_mutex);
- 		ret = drm_eld_size(connector->eld);
- 		memcpy(buf, connector->eld, min(max_bytes, ret));
- 		mutex_unlock(&connector->eld_mutex);
- 
- 		break;
- 	}
- 	drm_connector_list_iter_end(&conn_iter);
- 
- 	mutex_unlock(&adev->dm.audio_lock);
- 
- 	drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
- 
- 	return ret;
- }
- 
- static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
- 	.get_eld = amdgpu_dm_audio_component_get_eld,
- };
- 
- static int amdgpu_dm_audio_component_bind(struct device *kdev,
- 				       struct device *hda_kdev, void *data)
- {
- 	struct drm_device *dev = dev_get_drvdata(kdev);
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct drm_audio_component *acomp = data;
- 
- 	acomp->ops = &amdgpu_dm_audio_component_ops;
- 	acomp->dev = kdev;
- 	adev->dm.audio_component = acomp;
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_audio_component_unbind(struct device *kdev,
- 					  struct device *hda_kdev, void *data)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
- 	struct drm_audio_component *acomp = data;
- 
- 	acomp->ops = NULL;
- 	acomp->dev = NULL;
- 	adev->dm.audio_component = NULL;
- }
- 
- static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
- 	.bind	= amdgpu_dm_audio_component_bind,
- 	.unbind	= amdgpu_dm_audio_component_unbind,
- };
- 
- static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
- {
- 	int i, ret;
- 
- 	if (!amdgpu_audio)
- 		return 0;
- 
- 	adev->mode_info.audio.enabled = true;
- 
- 	adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
- 
- 	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
- 		adev->mode_info.audio.pin[i].channels = -1;
- 		adev->mode_info.audio.pin[i].rate = -1;
- 		adev->mode_info.audio.pin[i].bits_per_sample = -1;
- 		adev->mode_info.audio.pin[i].status_bits = 0;
- 		adev->mode_info.audio.pin[i].category_code = 0;
- 		adev->mode_info.audio.pin[i].connected = false;
- 		adev->mode_info.audio.pin[i].id =
- 			adev->dm.dc->res_pool->audios[i]->inst;
- 		adev->mode_info.audio.pin[i].offset = 0;
- 	}
- 
- 	ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
- 	if (ret < 0)
- 		return ret;
- 
- 	adev->dm.audio_registered = true;
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
- {
- 	if (!amdgpu_audio)
- 		return;
- 
- 	if (!adev->mode_info.audio.enabled)
- 		return;
- 
- 	if (adev->dm.audio_registered) {
- 		component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
- 		adev->dm.audio_registered = false;
- 	}
- 
- 	/* TODO: Disable audio? */
- 
- 	adev->mode_info.audio.enabled = false;
- }
- 
- static  void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
- {
- 	struct drm_audio_component *acomp = adev->dm.audio_component;
- 
- 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
- 		drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
- 
- 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
- 						 pin, -1);
- 	}
- }
- 
- static int dm_dmub_hw_init(struct amdgpu_device *adev)
- {
- 	const struct dmcub_firmware_header_v1_0 *hdr;
- 	struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
- 	struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info;
- 	const struct firmware *dmub_fw = adev->dm.dmub_fw;
- 	struct dc *dc = adev->dm.dc;
- 	struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
- 	struct abm *abm = adev->dm.dc->res_pool->abm;
- 	struct dc_context *ctx = adev->dm.dc->ctx;
- 	struct dmub_srv_hw_params hw_params;
- 	enum dmub_status status;
- 	const unsigned char *fw_inst_const, *fw_bss_data;
- 	u32 i, fw_inst_const_size, fw_bss_data_size;
- 	bool has_hw_support;
- 
- 	if (!dmub_srv)
- 		/* DMUB isn't supported on the ASIC. */
- 		return 0;
- 
- 	if (!fb_info) {
- 		drm_err(adev_to_drm(adev), "No framebuffer info for DMUB service.\n");
- 		return -EINVAL;
- 	}
- 
- 	if (!dmub_fw) {
- 		/* Firmware required for DMUB support. */
- 		drm_err(adev_to_drm(adev), "No firmware provided for DMUB.\n");
- 		return -EINVAL;
- 	}
- 
- 	/* initialize register offsets for ASICs with runtime initialization available */
- 	if (dmub_srv->hw_funcs.init_reg_offsets)
- 		dmub_srv->hw_funcs.init_reg_offsets(dmub_srv, ctx);
- 
- 	status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error checking HW support for DMUB: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	if (!has_hw_support) {
- 		drm_info(adev_to_drm(adev), "DMUB unsupported on ASIC\n");
- 		return 0;
- 	}
- 
- 	/* Reset DMCUB if it was previously running - before we overwrite its memory. */
- 	status = dmub_srv_hw_reset(dmub_srv);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "Error resetting DMUB HW: %d\n", status);
- 
- 	hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data;
- 
- 	fw_inst_const = dmub_fw->data +
- 			le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 			PSP_HEADER_BYTES_256;
- 
- 	fw_bss_data = dmub_fw->data +
- 		      le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 		      le32_to_cpu(hdr->inst_const_bytes);
- 
- 	/* Copy firmware and bios info into FB memory. */
- 	fw_inst_const_size = adev->dm.fw_inst_size;
- 
- 	fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
- 
- 	/* if adev->firmware.load_type == AMDGPU_FW_LOAD_PSP,
- 	 * amdgpu_ucode_init_single_fw will load dmub firmware
- 	 * fw_inst_const part to cw0; otherwise, the firmware back door load
- 	 * will be done by dm_dmub_hw_init
- 	 */
- 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- 		memcpy(fb_info->fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const,
- 				fw_inst_const_size);
- 	}
- 
- 	if (fw_bss_data_size)
- 		memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr,
- 		       fw_bss_data, fw_bss_data_size);
- 
- 	/* Copy firmware bios info into FB memory. */
- 	memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios,
- 	       adev->bios_size);
- 
- 	/* Reset regions that need to be reset. */
- 	memset(fb_info->fb[DMUB_WINDOW_4_MAILBOX].cpu_addr, 0,
- 	fb_info->fb[DMUB_WINDOW_4_MAILBOX].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_6_FW_STATE].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_SHARED_STATE].size);
- 
- 	/* Initialize hardware. */
- 	memset(&hw_params, 0, sizeof(hw_params));
- 	hw_params.soc_fb_info.fb_base = adev->gmc.fb_start;
- 	hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset;
- 
- 	/* backdoor load firmware and trigger dmub running */
- 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- 		hw_params.load_inst_const = true;
- 
- 	if (dmcu)
- 		hw_params.psp_version = dmcu->psp_version;
- 
- 	for (i = 0; i < fb_info->num_fb; ++i)
- 		hw_params.fb[i] = &fb_info->fb[i];
- 
- 	/* Enable usb4 dpia in the FW APU */
- 	if (dc->caps.is_apu &&
- 		dc->res_pool->usb4_dpia_count != 0 &&
- 		!dc->debug.dpia_debug.bits.disable_dpia) {
- 		hw_params.dpia_supported = true;
- 		hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia;
- 		hw_params.dpia_hpd_int_enable_supported = false;
- 		hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt;
- 		hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support;
- 	}
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 5, 1):
- 	case IP_VERSION(3, 6, 0):
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		hw_params.ips_sequential_ono = adev->external_rev_id > 0x10;
- 		hw_params.lower_hbr3_phy_ssc = true;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	status = dmub_srv_hw_init(dmub_srv, &hw_params);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error initializing DMUB HW: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/* Wait for firmware load to finish. */
- 	status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
- 
- 	/* Init DMCU and ABM if available. */
- 	if (dmcu && abm) {
- 		dmcu->funcs->dmcu_init(dmcu);
- 		abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
- 	}
- 
- 	if (!adev->dm.dc->ctx->dmub_srv)
- 		adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv);
- 	if (!adev->dm.dc->ctx->dmub_srv) {
- 		drm_err(adev_to_drm(adev), "Couldn't allocate DC DMUB server!\n");
- 		return -ENOMEM;
- 	}
- 
- 	drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n",
- 		 adev->dm.dmcub_fw_version);
- 
- 	/* Keeping sanity checks off if
- 	 * DCN31 >= 4.0.59.0
- 	 * DCN314 >= 8.0.16.0
- 	 * Otherwise, turn on sanity checks
- 	 */
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		if (adev->dm.dmcub_fw_version &&
- 			adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
- 			adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59))
- 				adev->dm.dc->debug.sanity_checks = true;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		if (adev->dm.dmcub_fw_version &&
- 			adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
- 			adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16))
- 				adev->dm.dc->debug.sanity_checks = true;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	return 0;
- }
- 
- static void dm_dmub_hw_resume(struct amdgpu_device *adev)
- {
- 	struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
- 	enum dmub_status status;
- 	bool init;
- 	int r;
- 
- 	if (!dmub_srv) {
- 		/* DMUB isn't supported on the ASIC. */
- 		return;
- 	}
- 
- 	status = dmub_srv_is_hw_init(dmub_srv, &init);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "DMUB hardware init check failed: %d\n", status);
- 
- 	if (status == DMUB_STATUS_OK && init) {
- 		/* Wait for firmware load to finish. */
- 		status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
- 		if (status != DMUB_STATUS_OK)
- 			drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
- 	} else {
- 		/* Perform the full hardware initialization. */
- 		r = dm_dmub_hw_init(adev);
- 		if (r)
- 			drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r);
- 	}
- }
- 
  static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
  {
  	u64 pt_base;
@@@ -1599,349 -394,6 +394,6 @@@
  
  }
  
- static void force_connector_state(
- 	struct amdgpu_dm_connector *aconnector,
- 	enum drm_connector_force force_state)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 
- 	mutex_lock(&connector->dev->mode_config.mutex);
- 	aconnector->base.force = force_state;
- 	mutex_unlock(&connector->dev->mode_config.mutex);
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 	drm_kms_helper_connector_hotplug_event(connector);
- 	mutex_unlock(&aconnector->hpd_lock);
- }
- 
- static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
- {
- 	struct hpd_rx_irq_offload_work *offload_work;
- 	struct amdgpu_dm_connector *aconnector;
- 	struct dc_link *dc_link;
- 	struct amdgpu_device *adev;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	unsigned long flags;
- 	union test_response test_response;
- 
- 	memset(&test_response, 0, sizeof(test_response));
- 
- 	offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
- 	aconnector = offload_work->offload_wq->aconnector;
- 	adev = offload_work->adev;
- 
- 	if (!aconnector) {
- 		drm_err(adev_to_drm(adev), "Can't retrieve aconnector in hpd_rx_irq_offload_work");
- 		goto skip;
- 	}
- 
- 	dc_link = aconnector->dc_link;
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 	if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
- 		drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 	mutex_unlock(&aconnector->hpd_lock);
- 
- 	if (new_connection_type == dc_connection_none)
- 		goto skip;
- 
- 	if (amdgpu_in_reset(adev))
- 		goto skip;
- 
- 	if (offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
- 		offload_work->data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
- 		dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, DOWN_OR_UP_MSG_RDY_EVENT);
- 		spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
- 		offload_work->offload_wq->is_handling_mst_msg_rdy_event = false;
- 		spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
- 		goto skip;
- 	}
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
- 		dc_link_dp_handle_automated_test(dc_link);
- 
- 		if (aconnector->timing_changed) {
- 			/* force connector disconnect and reconnect */
- 			force_connector_state(aconnector, DRM_FORCE_OFF);
- 			msleep(100);
- 			force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
- 		}
- 
- 		test_response.bits.ACK = 1;
- 
- 		core_link_write_dpcd(
- 		dc_link,
- 		DP_TEST_RESPONSE,
- 		&test_response.raw,
- 		sizeof(test_response));
- 	} else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
- 			dc_link_check_link_loss_status(dc_link, &offload_work->data) &&
- 			dc_link_dp_allow_hpd_rx_irq(dc_link)) {
- 		/* offload_work->data is from handle_hpd_rx_irq->
- 		 * schedule_hpd_rx_offload_work.this is defer handle
- 		 * for hpd short pulse. upon here, link status may be
- 		 * changed, need get latest link status from dpcd
- 		 * registers. if link status is good, skip run link
- 		 * training again.
- 		 */
- 		union hpd_irq_data irq_data;
- 
- 		memset(&irq_data, 0, sizeof(irq_data));
- 
- 		/* before dc_link_dp_handle_link_loss, allow new link lost handle
- 		 * request be added to work queue if link lost at end of dc_link_
- 		 * dp_handle_link_loss
- 		 */
- 		spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
- 		offload_work->offload_wq->is_handling_link_loss = false;
- 		spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
- 
- 		if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
- 			dc_link_check_link_loss_status(dc_link, &irq_data))
- 			dc_link_dp_handle_link_loss(dc_link);
- 	}
- 	mutex_unlock(&adev->dm.dc_lock);
- 
- skip:
- 	kfree(offload_work);
- 
- }
- 
- static struct hpd_rx_irq_offload_work_queue *hpd_rx_irq_create_workqueue(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	int max_caps = dc->caps.max_links;
- 	int i = 0;
- 	struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq = NULL;
- 
- 	hpd_rx_offload_wq = kzalloc_objs(*hpd_rx_offload_wq, max_caps);
- 
- 	if (!hpd_rx_offload_wq)
- 		return NULL;
- 
- 
- 	for (i = 0; i < max_caps; i++) {
- 		hpd_rx_offload_wq[i].wq =
- 				    create_singlethread_workqueue("amdgpu_dm_hpd_rx_offload_wq");
- 
- 		if (hpd_rx_offload_wq[i].wq == NULL) {
- 			drm_err(adev_to_drm(adev), "create amdgpu_dm_hpd_rx_offload_wq fail!");
- 			goto out_err;
- 		}
- 
- 		spin_lock_init(&hpd_rx_offload_wq[i].offload_lock);
- 	}
- 
- 	return hpd_rx_offload_wq;
- 
- out_err:
- 	for (i = 0; i < max_caps; i++) {
- 		if (hpd_rx_offload_wq[i].wq)
- 			destroy_workqueue(hpd_rx_offload_wq[i].wq);
- 	}
- 	kfree(hpd_rx_offload_wq);
- 	return NULL;
- }
- 
- struct amdgpu_stutter_quirk {
- 	u16 chip_vendor;
- 	u16 chip_device;
- 	u16 subsys_vendor;
- 	u16 subsys_device;
- 	u8 revision;
- };
- 
- static const struct amdgpu_stutter_quirk amdgpu_stutter_quirk_list[] = {
- 	/* https://bugzilla.kernel.org/show_bug.cgi?id=214417 */
- 	{ 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc8 },
- 	{ 0, 0, 0, 0, 0 },
- };
- 
- static bool dm_should_disable_stutter(struct pci_dev *pdev)
- {
- 	const struct amdgpu_stutter_quirk *p = amdgpu_stutter_quirk_list;
- 
- 	while (p && p->chip_device != 0) {
- 		if (pdev->vendor == p->chip_vendor &&
- 		    pdev->device == p->chip_device &&
- 		    pdev->subsystem_vendor == p->subsys_vendor &&
- 		    pdev->subsystem_device == p->subsys_device &&
- 		    pdev->revision == p->revision) {
- 			return true;
- 		}
- 		++p;
- 	}
- 	return false;
- }
- 
- 
- void*
- dm_allocate_gpu_mem(
- 		struct amdgpu_device *adev,
- 		enum dc_gpu_mem_alloc_type type,
- 		size_t size,
- 		long long *addr)
- {
- 	struct dal_allocation *da;
- 	u32 domain = (type == DC_MEM_ALLOC_TYPE_GART) ?
- 		AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM;
- 	int ret;
- 
- 	da = kzalloc_obj(struct dal_allocation);
- 	if (!da)
- 		return NULL;
- 
- 	ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
- 				      domain, &da->bo,
- 				      &da->gpu_addr, &da->cpu_ptr);
- 
- 	*addr = da->gpu_addr;
- 
- 	if (ret) {
- 		kfree(da);
- 		return NULL;
- 	}
- 
- 	/* add da to list in dm */
- 	list_add(&da->list, &adev->dm.da_list);
- 
- 	return da->cpu_ptr;
- }
- 
- void
- dm_free_gpu_mem(
- 		struct amdgpu_device *adev,
- 		enum dc_gpu_mem_alloc_type type,
- 		void *pvMem)
- {
- 	struct dal_allocation *da;
- 
- 	/* walk the da list in DM */
- 	list_for_each_entry(da, &adev->dm.da_list, list) {
- 		if (pvMem == da->cpu_ptr) {
- 			amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr);
- 			list_del(&da->list);
- 			kfree(da);
- 			break;
- 		}
- 	}
- 
- }
- 
- static enum dmub_status
- dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev,
- 				 enum dmub_gpint_command command_code,
- 				 uint16_t param,
- 				 uint32_t timeout_us)
- {
- 	union dmub_gpint_data_register reg, test;
- 	uint32_t i;
- 
- 	/* Assume that VBIOS DMUB is ready to take commands */
- 
- 	reg.bits.status = 1;
- 	reg.bits.command_code = command_code;
- 	reg.bits.param = param;
- 
- 	cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all);
- 
- 	for (i = 0; i < timeout_us; ++i) {
- 		udelay(1);
- 
- 		/* Check if our GPINT got acked */
- 		reg.bits.status = 0;
- 		test = (union dmub_gpint_data_register)
- 			cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8);
- 
- 		if (test.all == reg.all)
- 			return DMUB_STATUS_OK;
- 	}
- 
- 	return DMUB_STATUS_TIMEOUT;
- }
- 
- static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
- {
- 	void *bb;
- 	long long addr;
- 	unsigned int bb_size;
- 	int i = 0;
- 	uint16_t chunk;
- 	enum dmub_gpint_command send_addrs[] = {
- 		DMUB_GPINT__SET_BB_ADDR_WORD0,
- 		DMUB_GPINT__SET_BB_ADDR_WORD1,
- 		DMUB_GPINT__SET_BB_ADDR_WORD2,
- 		DMUB_GPINT__SET_BB_ADDR_WORD3,
- 	};
- 	enum dmub_status ret;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(4, 0, 1):
- 		bb_size = sizeof(struct dml2_soc_bb);
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		bb_size = sizeof(struct dml2_soc_bb);
- 		break;
- 	default:
- 		return NULL;
- 	}
- 
- 	bb =  dm_allocate_gpu_mem(adev,
- 				  DC_MEM_ALLOC_TYPE_GART,
- 				  bb_size,
- 				  &addr);
- 	if (!bb)
- 		return NULL;
- 
- 	for (i = 0; i < 4; i++) {
- 		/* Extract 16-bit chunk */
- 		chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF;
- 		/* Send the chunk */
- 		ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000);
- 		if (ret != DMUB_STATUS_OK)
- 			goto free_bb;
- 	}
- 
- 	/* Now ask DMUB to copy the bb */
- 	ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000);
- 	if (ret != DMUB_STATUS_OK)
- 		goto free_bb;
- 
- 	return bb;
- 
- free_bb:
- 	dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb);
- 	return NULL;
- 
- }
- 
- static enum dmub_ips_disable_type dm_get_default_ips_mode(
- 	struct amdgpu_device *adev)
- {
- 	enum dmub_ips_disable_type ret = DMUB_IPS_ENABLE;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 6, 0):
- 	case IP_VERSION(3, 5, 1):
- 		ret =  DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		ret =  DMUB_IPS_ENABLE;
- 		break;
- 	default:
- 		/* ASICs older than DCN35 do not have IPSs */
- 		if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 5, 0))
- 			ret = DMUB_IPS_DISABLE_ALL;
- 		break;
- 	}
- 
- 	return ret;
- }
- 
  static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm)
  {
  	struct mod_power_init_params init_data[MAX_NUM_EDP];
@@@ -2006,40 -458,6 +458,6 @@@
  	return 0;
  }
  
- static void hdmi_frl_status_polling_work(struct work_struct *work)
- {
- 	struct amdgpu_display_manager *dm =
- 		container_of(to_delayed_work(work), struct amdgpu_display_manager,
- 				hdmi_frl_status_polling_work);
- 	struct dc *dc = dm->dc;
- 	struct dc_link *dc_link;
- 	bool link_update = false;
- 
- 	for (int i = 0; i < MAX_LINKS; i++) {
- 		dc_link = dc->links[i];
- 
- 		if (!dc_link || !dc_link->local_sink)
- 			continue;
- 
- 		if (!dc_is_hdmi_signal(dc_link->connector_signal))
- 			continue;
- 
- 		if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
- 			continue;
- 
- 		link_update = dc_link_frl_poll_status_flag(dc_link);
- 		if (link_update) {
- 			mutex_lock(&dm->dc_lock);
- 			dc_link_detect(dc_link, DETECT_REASON_RETRAIN);
- 			mutex_unlock(&dm->dc_lock);
- 		}
- 	}
- 
- 	queue_delayed_work(dm->hdmi_frl_status_polling_wq,
- 			   &dm->hdmi_frl_status_polling_work,
- 			   msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms));
- }
- 
  static int amdgpu_dm_init(struct amdgpu_device *adev)
  {
  	struct dc_init_data init_data;
@@@ -2189,11 -607,6 +607,11 @@@
  		init_data.flags.unify_link_enc_assignment = true;
  		init_data.flags.usb4_bw_alloc_support = true;
  	}
 +
 +	/* DCN201 audio desyncs using DP SS */
 +	if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2)
 +		init_data.flags.ignore_dpref_ss = true;
 +
  	retrieve_dmi_info(&adev->dm);
  	if (adev->dm.edp0_on_dp1_quirk)
  		init_data.flags.support_edp0_on_dp1 = true;
@@@ -2271,7 -684,15 +689,15 @@@
  
  	dc_hardware_init(adev->dm.dc);
  
- 	adev->dm.hpd_rx_offload_wq = hpd_rx_irq_create_workqueue(adev);
+ 	/* GOP/vBIOS may leave an OPTC enabled for a display present at power-on
+ 	 * but no longer driven (e.g. an external DP unplugged at boot). Such a
+ 	 * dangling pipe keeps DCN out of idle and blocks s0i3. Power it down
+ 	 * here when nothing needs to be preserved.
+ 	 */
+ 	if (adev->flags & AMD_IS_APU)
+ 		dc_disable_dangling_timing_generators(adev->dm.dc);
+ 
+ 	adev->dm.hpd_rx_offload_wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
  	if (!adev->dm.hpd_rx_offload_wq) {
  		drm_err(adev_to_drm(adev), "failed to create hpd rx offload workqueue.\n");
  		goto error;
@@@ -2324,8 -745,6 +750,6 @@@
  			create_singlethread_workqueue("hdmi_frl_status_polling_workqueue");
  		if (!adev->dm.hdmi_frl_status_polling_wq)
  			drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n");
- 		adev->dm.hdmi_frl_status_polling_delay_ms = 200;
- 		INIT_DELAYED_WORK(&adev->dm.hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
  	}
  	if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
  		init_completion(&adev->dm.dmub_aux_transfer_done);
@@@ -2342,8 -761,8 +766,8 @@@
  		}
  
  		amdgpu_dm_outbox_init(adev);
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY,
- 			dmub_aux_setconfig_callback, false)) {
+ 		if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY,
+ 			dm_dmub_aux_setconfig_callback, false)) {
  			drm_err(adev_to_drm(adev), "fail to register dmub aux callback");
  			goto error;
  		}
@@@ -2351,16 -770,17 +775,17 @@@
  		for (size_t i = 0; i < ARRAY_SIZE(adev->dm.fused_io); i++)
  			init_completion(&adev->dm.fused_io[i].replied);
  
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO,
- 			dmub_aux_fused_io_callback, false)) {
+ 		if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO,
+ 			dm_dmub_aux_fused_io_callback, false)) {
  			drm_err(adev_to_drm(adev), "fail to register dmub fused io callback");
  			goto error;
  		}
  		/* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
  		 * It is expected that DMUB will resend any pending notifications at this point. Note
- 		 * that hpd and hpd_irq handler registration are deferred to register_hpd_handlers() to
- 		 * align legacy interface initialization sequence. Connection status will be proactivly
- 		 * detected once in the amdgpu_dm_initialize_drm_device.
+ 		 * that hpd and hpd_irq handler registration are deferred to
+ 		 * amdgpu_dm_register_hpd_handlers() to align legacy interface initialization
+ 		 * sequence. Connection status will be proactivly detected once in the
+ 		 * amdgpu_dm_initialize_drm_device.
  		 */
  		dc_enable_dmub_outbox(adev->dm.dc);
  
@@@ -2503,14 -923,11 +928,11 @@@ static void amdgpu_dm_fini(struct amdgp
  		adev->dm.hpd_rx_offload_wq = NULL;
  	}
  
+ 	amdgpu_dm_irq_fini(adev);
+ 
  	/* DC Destroy TODO: Replace destroy DAL */
  	if (adev->dm.dc)
  		dc_destroy(&adev->dm.dc);
- 	/*
- 	 * TODO: pageflip, vlank interrupt
- 	 *
- 	 * amdgpu_dm_irq_fini(adev);
- 	 */
  
  	if (adev->dm.cgs_device) {
  		amdgpu_cgs_destroy_device(adev->dm.cgs_device);
@@@ -2640,224 -1057,6 +1062,6 @@@ static int load_dmcu_fw(struct amdgpu_d
  	return 0;
  }
  
- static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address)
- {
- 	struct amdgpu_device *adev = ctx;
- 
- 	return dm_read_reg(adev->dm.dc->ctx, address);
- }
- 
- static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address,
- 				     uint32_t value)
- {
- 	struct amdgpu_device *adev = ctx;
- 
- 	return dm_write_reg(adev->dm.dc->ctx, address, value);
- }
- 
- static int dm_dmub_sw_init(struct amdgpu_device *adev)
- {
- 	struct dmub_srv_create_params create_params;
- 	struct dmub_srv_fw_meta_info_params fw_meta_info_params;
- 	struct dmub_srv_region_params region_params;
- 	struct dmub_srv_region_info region_info;
- 	struct dmub_srv_memory_params memory_params;
- 	struct dmub_fw_meta_info fw_info;
- 	struct dmub_srv_fb_info *fb_info;
- 	struct dmub_srv *dmub_srv;
- 	const struct dmcub_firmware_header_v1_0 *hdr;
- 	enum dmub_asic dmub_asic;
- 	enum dmub_status status;
- 	static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = {
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_0_INST_CONST
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_1_STACK
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_2_BSS_DATA
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_3_VBIOS
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_4_MAILBOX
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_5_TRACEBUFF
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_6_FW_STATE
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_7_SCRATCH_MEM
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_IB_MEM
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_SHARED_STATE
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_LSDMA_BUFFER
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_CURSOR_OFFLOAD
- 	};
- 	int r;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(2, 1, 0):
- 		dmub_asic = DMUB_ASIC_DCN21;
- 		break;
- 	case IP_VERSION(3, 0, 0):
- 		dmub_asic = DMUB_ASIC_DCN30;
- 		break;
- 	case IP_VERSION(3, 0, 1):
- 		dmub_asic = DMUB_ASIC_DCN301;
- 		break;
- 	case IP_VERSION(3, 0, 2):
- 		dmub_asic = DMUB_ASIC_DCN302;
- 		break;
- 	case IP_VERSION(3, 0, 3):
- 		dmub_asic = DMUB_ASIC_DCN303;
- 		break;
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		dmub_asic = DMUB_ASIC_DCN314;
- 		break;
- 	case IP_VERSION(3, 1, 5):
- 		dmub_asic = DMUB_ASIC_DCN315;
- 		break;
- 	case IP_VERSION(3, 1, 6):
- 		dmub_asic = DMUB_ASIC_DCN316;
- 		break;
- 	case IP_VERSION(3, 2, 0):
- 		dmub_asic = DMUB_ASIC_DCN32;
- 		break;
- 	case IP_VERSION(3, 2, 1):
- 		dmub_asic = DMUB_ASIC_DCN321;
- 		break;
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 5, 1):
- 		dmub_asic = DMUB_ASIC_DCN35;
- 		break;
- 	case IP_VERSION(3, 6, 0):
- 		dmub_asic = DMUB_ASIC_DCN36;
- 		break;
- 	case IP_VERSION(4, 0, 1):
- 		dmub_asic = DMUB_ASIC_DCN401;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 		dmub_asic = DMUB_ASIC_DCN42;
- 		break;
- 	case IP_VERSION(4, 2, 1):
- 		dmub_asic = DMUB_ASIC_DCN42B;
- 		break;
- 	default:
- 		/* ASIC doesn't support DMUB. */
- 		return 0;
- 	}
- 
- 	hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
- 	adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version);
- 
- 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
- 		adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id =
- 			AMDGPU_UCODE_ID_DMCUB;
- 		adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw =
- 			adev->dm.dmub_fw;
- 		adev->firmware.fw_size +=
- 			ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE);
- 
- 		drm_info(adev_to_drm(adev), "Loading DMUB firmware via PSP: version=0x%08X\n",
- 			 adev->dm.dmcub_fw_version);
- 	}
- 
- 
- 	adev->dm.dmub_srv = kzalloc_obj(*adev->dm.dmub_srv);
- 	dmub_srv = adev->dm.dmub_srv;
- 
- 	if (!dmub_srv) {
- 		drm_err(adev_to_drm(adev), "Failed to allocate DMUB service!\n");
- 		return -ENOMEM;
- 	}
- 
- 	memset(&create_params, 0, sizeof(create_params));
- 	create_params.user_ctx = adev;
- 	create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read;
- 	create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write;
- 	create_params.asic = dmub_asic;
- 
- 	/* Create the DMUB service. */
- 	status = dmub_srv_create(dmub_srv, &create_params);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error creating DMUB service: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/* Extract the FW meta info. */
- 	memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params));
- 
- 	fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) -
- 					      PSP_HEADER_BYTES_256;
- 	fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
- 	fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data +
- 					    le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 					    PSP_HEADER_BYTES_256;
- 	fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data +
- 					  le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 					  le32_to_cpu(hdr->inst_const_bytes) : NULL;
- 	fw_meta_info_params.custom_psp_footer_size = 0;
- 
- 	status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info);
- 	if (status != DMUB_STATUS_OK) {
- 		/* Skip returning early, just log the error. */
- 		drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status);
- 		// return -EINVAL;
- 	}
- 
- 	/* Calculate the size of all the regions for the DMUB service. */
- 	memset(&region_params, 0, sizeof(region_params));
- 
- 	region_params.inst_const_size = fw_meta_info_params.inst_const_size;
- 	region_params.bss_data_size = fw_meta_info_params.bss_data_size;
- 	region_params.vbios_size = adev->bios_size;
- 	region_params.fw_bss_data = fw_meta_info_params.fw_bss_data;
- 	region_params.fw_inst_const = fw_meta_info_params.fw_inst_const;
- 	region_params.window_memory_type = window_memory_type;
- 	region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL;
- 
- 	status = dmub_srv_calc_region_info(dmub_srv, &region_params,
- 					   &region_info);
- 
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error calculating DMUB region info: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/*
- 	 * Allocate a framebuffer based on the total size of all the regions.
- 	 * TODO: Move this into GART.
- 	 */
- 	r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE,
- 				    AMDGPU_GEM_DOMAIN_VRAM |
- 				    AMDGPU_GEM_DOMAIN_GTT,
- 				    &adev->dm.dmub_bo,
- 				    &adev->dm.dmub_bo_gpu_addr,
- 				    &adev->dm.dmub_bo_cpu_addr);
- 	if (r)
- 		return r;
- 
- 	/* Rebase the regions on the framebuffer address. */
- 	memset(&memory_params, 0, sizeof(memory_params));
- 	memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr;
- 	memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr;
- 	memory_params.region_info = &region_info;
- 	memory_params.window_memory_type = window_memory_type;
- 
- 	adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info);
- 	fb_info = adev->dm.dmub_fb_info;
- 
- 	if (!fb_info) {
- 		drm_err(adev_to_drm(adev),
- 			"Failed to allocate framebuffer info for DMUB service!\n");
- 		return -ENOMEM;
- 	}
- 
- 	status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error calculating DMUB FB info: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev);
- 	adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size;
- 
- 	return 0;
- }
- 
  static int dm_sw_init(struct amdgpu_ip_block *ip_block)
  {
  	struct amdgpu_device *adev = ip_block->adev;
@@@ -2911,41 -1110,6 +1115,6 @@@ static int dm_sw_fini(struct amdgpu_ip_
  	return 0;
  }
  
- static int detect_mst_link_for_all_connectors(struct drm_device *dev)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter iter;
- 	int ret = 0;
- 
- 	drm_connector_list_iter_begin(dev, &iter);
- 	drm_for_each_connector_iter(connector, &iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (aconnector->dc_link->type == dc_connection_mst_branch &&
- 		    aconnector->mst_mgr.aux) {
- 			drm_dbg_kms(dev, "DM_MST: starting TM on aconnector: %p [id: %d]\n",
- 					 aconnector,
- 					 aconnector->base.base.id);
- 
- 			ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
- 			if (ret < 0) {
- 				drm_err(dev, "DM_MST: Failed to start MST\n");
- 				aconnector->dc_link->type =
- 					dc_connection_single;
- 				ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx,
- 								     aconnector->dc_link);
- 				break;
- 			}
- 		}
- 	}
- 	drm_connector_list_iter_end(&iter);
- 
- 	return ret;
- }
  
  static void amdgpu_dm_boot_time_crc_init(struct amdgpu_device *adev)
  {
@@@ -3043,7 -1207,7 +1212,7 @@@ static int dm_late_init(struct amdgpu_i
  		}
  	}
  
- 	return detect_mst_link_for_all_connectors(adev_to_drm(adev));
+ 	return amdgpu_dm_detect_mst_link_for_all_connectors(adev_to_drm(adev));
  }
  
  static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
@@@ -3097,48 -1261,6 +1266,6 @@@ out_fail
  	mutex_unlock(&mgr->lock);
  }
  
- void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
- {
- 	struct cec_notifier *n = aconnector->notifier;
- 
- 	if (!n)
- 		return;
- 
- 	cec_notifier_phys_addr_invalidate(n);
- }
- 
- void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct cec_notifier *n = aconnector->notifier;
- 
- 	if (!n)
- 		return;
- 
- 	cec_notifier_set_phys_addr(n,
- 				   connector->display_info.source_physical_address);
- }
- 
- static void s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter conn_iter;
- 
- 	drm_connector_list_iter_begin(ddev, &conn_iter);
- 	drm_for_each_connector_iter(connector, &conn_iter) {
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (suspend)
- 			hdmi_cec_unset_edid(aconnector);
- 		else
- 			hdmi_cec_set_edid(aconnector);
- 	}
- 	drm_connector_list_iter_end(&conn_iter);
- }
- 
  static void s3_handle_mst(struct drm_device *dev, bool suspend)
  {
  	struct amdgpu_dm_connector *aconnector;
@@@ -3181,57 -1303,6 +1308,6 @@@
  	drm_connector_list_iter_end(&iter);
  }
  
- static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
- {
- 	int ret = 0;
- 
- 	/* This interface is for dGPU Navi1x.Linux dc-pplib interface depends
- 	 * on window driver dc implementation.
- 	 * For Navi1x, clock settings of dcn watermarks are fixed. the settings
- 	 * should be passed to smu during boot up and resume from s3.
- 	 * boot up: dc calculate dcn watermark clock settings within dc_create,
- 	 * dcn20_resource_construct
- 	 * then call pplib functions below to pass the settings to smu:
- 	 * smu_set_watermarks_for_clock_ranges
- 	 * smu_set_watermarks_table
- 	 * navi10_set_watermarks_table
- 	 * smu_write_watermarks_table
- 	 *
- 	 * For Renoir, clock settings of dcn watermark are also fixed values.
- 	 * dc has implemented different flow for window driver:
- 	 * dc_hardware_init / dc_set_power_state
- 	 * dcn10_init_hw
- 	 * notify_wm_ranges
- 	 * set_wm_ranges
- 	 * -- Linux
- 	 * smu_set_watermarks_for_clock_ranges
- 	 * renoir_set_watermarks_table
- 	 * smu_write_watermarks_table
- 	 *
- 	 * For Linux,
- 	 * dc_hardware_init -> amdgpu_dm_init
- 	 * dc_set_power_state --> dm_resume
- 	 *
- 	 * therefore, this function apply to navi10/12/14 but not Renoir
- 	 * *
- 	 */
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(2, 0, 2):
- 	case IP_VERSION(2, 0, 0):
- 		break;
- 	default:
- 		return 0;
- 	}
- 
- 	ret = amdgpu_dpm_write_watermarks_table(adev);
- 	if (ret) {
- 		drm_err(adev_to_drm(adev), "Failed to update WMTABLE!\n");
- 		return ret;
- 	}
- 
- 	return 0;
- }
- 
  static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
  {
  	struct amdgpu_display_manager *dm = &adev->dm;
@@@ -3241,7 -1312,7 +1317,7 @@@
  
  	oem_ddc_service = dc_get_oem_i2c_device(adev->dm.dc);
  	if (oem_ddc_service) {
- 		oem_i2c = create_i2c(oem_ddc_service, true);
+ 		oem_i2c = amdgpu_dm_create_i2c(oem_ddc_service, true);
  		if (!oem_i2c) {
  			drm_info(adev_to_drm(adev), "Failed to create oem i2c adapter data\n");
  			return -ENOMEM;
@@@ -3284,17 -1355,26 +1360,26 @@@ static int dm_hw_init(struct amdgpu_ip_
  	struct amdgpu_device *adev = ip_block->adev;
  	int r;
  
+ 	adev->dm.i2c_devres_group = devres_open_group(adev->dev, NULL, GFP_KERNEL);
+ 	if (!adev->dm.i2c_devres_group)
+ 		return -ENOMEM;
+ 
  	/* Create DAL display manager */
  	r = amdgpu_dm_init(adev);
  	if (r)
- 		return r;
+ 		goto err_release_i2c;
  	amdgpu_dm_hpd_init(adev);
  
  	r = dm_oem_i2c_hw_init(adev);
  	if (r)
  		drm_info(adev_to_drm(adev), "Failed to add OEM i2c bus\n");
  
+ 	devres_close_group(adev->dev, adev->dm.i2c_devres_group);
  	return 0;
+ 
+ err_release_i2c:
+ 	devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+ 	return r;
  }
  
  /**
@@@ -3309,9 -1389,11 +1394,11 @@@ static int dm_hw_fini(struct amdgpu_ip_
  {
  	struct amdgpu_device *adev = ip_block->adev;
  
+ 	if (adev->dm.i2c_devres_group)
+ 		devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+ 
  	amdgpu_dm_hpd_fini(adev);
  
- 	amdgpu_dm_irq_fini(adev);
  	amdgpu_dm_fini(adev);
  	return 0;
  }
@@@ -3326,7 -1408,7 +1413,7 @@@ static void dm_gpureset_toggle_interrup
  	int i = 0;
  
  	for (i = 0; i < state->stream_count; i++) {
- 		acrtc = get_crtc_by_otg_inst(
+ 		acrtc = amdgpu_dm_get_crtc_by_otg_inst(
  				adev, state->stream_status[i].primary_otg_inst);
  
  		if (acrtc && state->stream_status[i].plane_count != 0 &&
@@@ -3411,16 -1493,6 +1498,6 @@@ static enum dc_status amdgpu_dm_commit_
  	return dc_commit_streams(dc, &params);
  }
  
- static void hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm)
- {
- 	int i;
- 
- 	if (dm->hpd_rx_offload_wq) {
- 		for (i = 0; i < dm->dc->caps.max_links; i++)
- 			flush_workqueue(dm->hpd_rx_offload_wq[i].wq);
- 	}
- }
- 
  static int dm_cache_state(struct amdgpu_device *adev)
  {
  	int r;
@@@ -3453,7 -1525,7 +1530,7 @@@ static void dm_destroy_cached_state(str
  	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
  		new_crtc_state->active_changed = true;
  		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
- 		reset_freesync_config_for_crtc(dm_new_crtc_state);
+ 		amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
  	}
  
  	/*
@@@ -3516,7 -1588,7 +1593,7 @@@ static int dm_suspend(struct amdgpu_ip_
  
  		amdgpu_dm_irq_suspend(adev);
  
- 		hpd_rx_irq_work_suspend(dm);
+ 		amdgpu_dm_hpd_rx_irq_work_suspend(dm);
  
  		return 0;
  	}
@@@ -3528,7 -1600,7 +1605,7 @@@
  			return r;
  	}
  
- 	s3_handle_hdmi_cec(adev_to_drm(adev), true);
+ 	amdgpu_dm_s3_handle_hdmi_cec(adev_to_drm(adev), true);
  
  	s3_handle_mst(adev_to_drm(adev), true);
  
@@@ -3542,7 -1614,7 +1619,7 @@@
  	scoped_guard(mutex, &dm->dc_lock)
  		amdgpu_dm_ism_force_full_power(dm);
  
- 	hpd_rx_irq_work_suspend(dm);
+ 	amdgpu_dm_hpd_rx_irq_work_suspend(dm);
  
  	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
  
@@@ -3554,26 -1626,7 +1631,7 @@@
  	return 0;
  }
  
- struct drm_connector *
- amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state,
- 					     struct drm_crtc *crtc)
- {
- 	u32 i;
- 	struct drm_connector_state *new_con_state;
- 	struct drm_connector *connector;
- 	struct drm_crtc *crtc_from_state;
- 
- 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
- 		crtc_from_state = new_con_state->crtc;
- 
- 		if (crtc_from_state == crtc)
- 			return connector;
- 	}
- 
- 	return NULL;
- }
- 
- static void emulated_link_detect(struct dc_link *link)
+ void amdgpu_dm_emulated_link_detect(struct dc_link *link)
  {
  	struct dc_sink_init_data sink_init_data = { 0 };
  	struct display_sink_capability sink_caps = { 0 };
@@@ -3694,8 -1747,8 +1752,8 @@@ static void dm_gpureset_commit_state(st
  	}
  }
  
- static void apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
- 					    struct dc_sink *sink)
+ void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
+ 											   struct dc_sink *sink)
  {
  	struct dc_panel_patch *ppatch = NULL;
  
@@@ -3711,6 -1764,7 +1769,7 @@@
  			       ppatch->wait_after_dpcd_poweroff_ms / 1000);
  	}
  }
+ EXPORT_IF_KUNIT(amdgpu_dm_apply_delay_after_dpcd_poweroff);
  
  /**
   * amdgpu_dm_dump_links_and_sinks - Debug dump of all DC links and their sinks
@@@ -3838,8 -1892,7 +1897,7 @@@ static int dm_resume(struct amdgpu_ip_b
  		for (i = 0; i < dc_state->stream_count; i++) {
  			dc_state->streams[i]->mode_changed = true;
  			for (j = 0; j < dc_state->stream_status[i].plane_count; j++) {
- 				dc_state->stream_status[i].plane_states[j]->update_flags.raw
- 					= 0xffffffff;
+ 				dc_pipe_update_bits_set_full(&dc_state->stream_status[i].plane_states[j]->update_bits);
  			}
  		}
  
@@@ -3902,7 -1955,7 +1960,7 @@@
  	 */
  	amdgpu_dm_irq_resume_early(adev);
  
- 	s3_handle_hdmi_cec(ddev, false);
+ 	amdgpu_dm_s3_handle_hdmi_cec(ddev, false);
  
  	/* On resume we need to rewrite the MSTM control bits to enable MST*/
  	s3_handle_mst(ddev, false);
@@@ -3937,14 -1990,14 +1995,14 @@@
  			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
  
  		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(aconnector->dc_link);
+ 			amdgpu_dm_emulated_link_detect(aconnector->dc_link);
  		} else {
  			guard(mutex)(&dm->dc_lock);
  			dc_exit_ips_for_hw_access(dm->dc);
  			ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_RESUMEFROMS3S4);
  			if (ret) {
  				/* w/a delay for certain panels */
- 				apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
+ 				amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
  			}
  		}
  
@@@ -4022,7 -2075,6 +2080,6 @@@ static const struct amd_ip_funcs amdgpu
  	.resume = dm_resume,
  	.is_idle = dm_is_idle,
  	.wait_for_idle = dm_wait_for_idle,
- 	.check_soft_reset = dm_check_soft_reset,
  	.soft_reset = dm_soft_reset,
  	.set_clockgating_state = dm_set_clockgating_state,
  	.set_powergating_state = dm_set_powergating_state,
@@@ -4055,1004 -2107,6 +2112,6 @@@ static struct drm_mode_config_helper_fu
  	.atomic_commit_setup = amdgpu_dm_atomic_setup_commit,
  };
  
- #define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C
- 
- static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_display_info *display_info = &connector->display_info;
- 	struct dc_link *link = aconnector->dc_link;
- 	struct amdgpu_device *adev;
- 
- 	adev = drm_to_adev(connector->dev);
- 
- 	link->panel_type = PANEL_TYPE_NONE;
- 
- 	switch (display_info->amd_vsdb.panel_type) {
- 	case AMD_VSDB_PANEL_TYPE_OLED:
- 		link->panel_type = PANEL_TYPE_OLED;
- 		break;
- 	case AMD_VSDB_PANEL_TYPE_MINILED:
- 		link->panel_type = PANEL_TYPE_MINILED;
- 		break;
- 	}
- 
- 	/* If VSDB didn't determine panel type, check DPCD ext caps */
- 	if (link->panel_type == PANEL_TYPE_NONE) {
- 		if (link->dpcd_sink_ext_caps.bits.miniled == 1)
- 			link->panel_type = PANEL_TYPE_MINILED;
- 		if (link->dpcd_sink_ext_caps.bits.oled == 1)
- 			link->panel_type = PANEL_TYPE_OLED;
- 	}
- 
- 	/*
- 	 * TODO: get panel type from DID2 that has device technology field
- 	 * to specify if it's OLED or not. But we need to wait for DID2
- 	 * support in DC and EDID parser to be able to use it here.
- 	 */
- 
- 	if (link->panel_type == PANEL_TYPE_NONE) {
- 		struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb;
- 		u32 lum1_max = vsdb->luminance_range1.max_luminance;
- 		u32 lum2_max = vsdb->luminance_range2.max_luminance;
- 
- 		if (vsdb->version && link->local_sink &&
- 		    link->local_sink->edid_caps.manufacturer_id ==
- 		    DDC_MANUFACTURERNAME_SAMSUNG &&
- 		    lum1_max >= ((lum2_max * 3) / 2))
- 			link->panel_type = PANEL_TYPE_MINILED;
- 	}
- 
- 	if (link->panel_type == PANEL_TYPE_OLED)
- 		drm_object_property_set_value(&connector->base,
- 		    adev_to_drm(adev)->mode_config.panel_type_property,
- 		    DRM_MODE_PANEL_TYPE_OLED);
- 	else
- 		drm_object_property_set_value(&connector->base,
- 		    adev_to_drm(adev)->mode_config.panel_type_property,
- 		    DRM_MODE_PANEL_TYPE_UNKNOWN);
- 
- 	drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type);
- }
- 
- static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
- {
- 	const struct drm_panel_backlight_quirk *panel_backlight_quirk;
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct drm_connector *conn_base;
- 	struct amdgpu_device *adev;
- 	struct drm_luminance_range_info *luminance_range;
- 	struct drm_device *drm;
- 
- 	if (aconnector->bl_idx == -1 ||
- 	    aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
- 		return;
- 
- 	conn_base = &aconnector->base;
- 	drm = conn_base->dev;
- 	adev = drm_to_adev(drm);
- 
- 	caps = &adev->dm.backlight_caps[aconnector->bl_idx];
- 	caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
- 	caps->aux_support = false;
- 
- 	panel_backlight_quirk = drm_get_panel_backlight_quirk(aconnector->drm_edid);
- 
- 	if (caps->ext_caps->bits.oled == 1
- 	    /*
- 	     * ||
- 	     * caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
- 	     * caps->ext_caps->bits.hdr_aux_backlight_control == 1
- 	     */)
- 		caps->aux_support = true;
- 
- 	if (amdgpu_backlight == 0)
- 		caps->aux_support = false;
- 	else if (amdgpu_backlight == 1)
- 		caps->aux_support = true;
- 	else if (!IS_ERR_OR_NULL(panel_backlight_quirk) &&
- 		 panel_backlight_quirk->force_pwm)
- 		caps->aux_support = false;
- 	if (caps->aux_support)
- 		aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX;
- 
- 	luminance_range = &conn_base->display_info.luminance_range;
- 
- 	if (luminance_range->max_luminance)
- 		caps->aux_max_input_signal = luminance_range->max_luminance;
- 	else
- 		caps->aux_max_input_signal = 512;
- 
- 	if (luminance_range->min_luminance)
- 		caps->aux_min_input_signal = luminance_range->min_luminance;
- 	else
- 		caps->aux_min_input_signal = 1;
- 
- 	if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
- 		if (panel_backlight_quirk->min_brightness) {
- 			caps->min_input_signal =
- 				panel_backlight_quirk->min_brightness - 1;
- 			drm_info(drm,
- 				 "Applying panel backlight quirk, min_brightness: %d\n",
- 				 caps->min_input_signal);
- 		}
- 		if (panel_backlight_quirk->brightness_mask) {
- 			drm_info(drm,
- 				 "Applying panel backlight quirk, brightness_mask: 0x%X\n",
- 				 panel_backlight_quirk->brightness_mask);
- 			caps->brightness_mask =
- 				panel_backlight_quirk->brightness_mask;
- 		}
- 	}
- }
- 
- DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
- 
- void amdgpu_dm_update_connector_after_detect(
- 		struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct dc_sink *sink __free(sink_release) = NULL;
- 	struct drm_device *dev = connector->dev;
- 
- 	/* MST handled by drm_mst framework */
- 	if (aconnector->mst_mgr.mst_state == true)
- 		return;
- 
- 	sink = aconnector->dc_link->local_sink;
- 	if (sink)
- 		dc_sink_retain(sink);
- 
- 	/*
- 	 * Edid mgmt connector gets first update only in mode_valid hook and then
- 	 * the connector sink is set to either fake or physical sink depends on link status.
- 	 * Skip if already done during boot.
- 	 */
- 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED
- 			&& aconnector->dc_em_sink) {
- 
- 		/*
- 		 * For S3 resume with headless use eml_sink to fake stream
- 		 * because on resume connector->sink is set to NULL
- 		 */
- 		guard(mutex)(&dev->mode_config.mutex);
- 
- 		if (sink) {
- 			if (aconnector->dc_sink) {
- 				amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 				/*
- 				 * retain and release below are used to
- 				 * bump up refcount for sink because the link doesn't point
- 				 * to it anymore after disconnect, so on next crtc to connector
- 				 * reshuffle by UMD we will get into unwanted dc_sink release
- 				 */
- 				dc_sink_release(aconnector->dc_sink);
- 			}
- 			aconnector->dc_sink = sink;
- 			dc_sink_retain(aconnector->dc_sink);
- 			amdgpu_dm_update_freesync_caps(connector,
- 					aconnector->drm_edid, true);
- 		} else {
- 			amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 			if (!aconnector->dc_sink) {
- 				aconnector->dc_sink = aconnector->dc_em_sink;
- 				dc_sink_retain(aconnector->dc_sink);
- 			}
- 		}
- 
- 		return;
- 	}
- 
- 	/*
- 	 * TODO: temporary guard to look for proper fix
- 	 * if this sink is MST sink, we should not do anything
- 	 */
- 	if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- 		return;
- 
- 	if (aconnector->dc_sink == sink) {
- 		/*
- 		 * We got a DP short pulse (Link Loss, DP CTS, etc...).
- 		 * Do nothing!!
- 		 */
- 		drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n",
- 				 aconnector->connector_id);
- 		return;
- 	}
- 
- 	drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
- 		    aconnector->connector_id, aconnector->dc_sink, sink);
- 
- 	/* When polling, DRM has already locked the mutex for us. */
- 	if (!drm_kms_helper_is_poll_worker())
- 		mutex_lock(&dev->mode_config.mutex);
- 
- 	/*
- 	 * 1. Update status of the drm connector
- 	 * 2. Send an event and let userspace tell us what to do
- 	 */
- 	if (sink) {
- 		/*
- 		 * TODO: check if we still need the S3 mode update workaround.
- 		 * If yes, put it here.
- 		 */
- 		if (aconnector->dc_sink) {
- 			amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 			dc_sink_release(aconnector->dc_sink);
- 		}
- 
- 		aconnector->dc_sink = sink;
- 		dc_sink_retain(aconnector->dc_sink);
- 		drm_edid_free(aconnector->drm_edid);
- 		aconnector->drm_edid = NULL;
- 		if (sink->dc_edid.length == 0) {
- 			hdmi_cec_unset_edid(aconnector);
- 			if (aconnector->dc_link->aux_mode) {
- 				drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
- 			}
- 		} else {
- 			const struct edid *edid = (const struct edid *)sink->dc_edid.raw_edid;
- 
- 			aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length);
- 			drm_edid_connector_update(connector, aconnector->drm_edid);
- 
- 			hdmi_cec_set_edid(aconnector);
- 			if (aconnector->dc_link->aux_mode)
- 				drm_dp_cec_attach(&aconnector->dm_dp_aux.aux,
- 						  connector->display_info.source_physical_address);
- 		}
- 
- 		if (!aconnector->timing_requested) {
- 			aconnector->timing_requested =
- 				kzalloc_obj(struct dc_crtc_timing);
- 			if (!aconnector->timing_requested)
- 				drm_err(dev,
- 					"failed to create aconnector->requested_timing\n");
- 		}
- 
- 		amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, true);
- 		update_connector_ext_caps(aconnector);
- 		dm_set_panel_type(aconnector);
- 	} else {
- 		hdmi_cec_unset_edid(aconnector);
- 		drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
- 		amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 		aconnector->num_modes = 0;
- 		dc_sink_release(aconnector->dc_sink);
- 		aconnector->dc_sink = NULL;
- 		drm_edid_free(aconnector->drm_edid);
- 		aconnector->drm_edid = NULL;
- 		kfree(aconnector->timing_requested);
- 		aconnector->timing_requested = NULL;
- 		/* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
- 		if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
- 			connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
- 	}
- 
- 	update_subconnector_property(aconnector);
- 
- 	/* When polling, the mutex will be unlocked for us by DRM. */
- 	if (!drm_kms_helper_is_poll_worker())
- 		mutex_unlock(&dev->mode_config.mutex);
- }
- 
- static bool are_sinks_equal(const struct dc_sink *sink1, const struct dc_sink *sink2)
- {
- 	if (!sink1 || !sink2)
- 		return false;
- 	if (sink1->sink_signal != sink2->sink_signal)
- 		return false;
- 
- 	if (sink1->dc_edid.length != sink2->dc_edid.length)
- 		return false;
- 
- 	if (memcmp(sink1->dc_edid.raw_edid, sink2->dc_edid.raw_edid,
- 		   sink1->dc_edid.length) != 0)
- 		return false;
- 	return true;
- }
- 
- 
- /**
-  * DOC: hdmi_hpd_debounce_work
-  *
-  * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
-  * (such as during power save transitions), this delay determines how long to
-  * wait before processing the HPD event. This allows distinguishing between a
-  * physical unplug (>hdmi_hpd_debounce_delay)
-  * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
-  *
-  * If the toggle is less than this delay, the driver compares sink capabilities
-  * and permits a hotplug event if they changed.
-  *
-  * The default value of 1500ms was chosen based on experimental testing with
-  * various monitors that exhibit spontaneous HPD toggling behavior.
-  */
- static void hdmi_hpd_debounce_work(struct work_struct *work)
- {
- 	struct amdgpu_dm_connector *aconnector =
- 		container_of(to_delayed_work(work), struct amdgpu_dm_connector,
- 			     hdmi_hpd_debounce_work);
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 	bool fake_reconnect = false;
- 	bool reallow_idle = false;
- 	bool ret = false;
- 	guard(mutex)(&aconnector->hpd_lock);
- 
- 	/* Re-detect the display */
- 	scoped_guard(mutex, &adev->dm.dc_lock) {
- 		if (dc->caps.ips_support && dc->ctx->dmub_srv->idle_allowed) {
- 			dc_allow_idle_optimizations(dc, false);
- 			reallow_idle = true;
- 		}
- 		ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
- 	}
- 
- 	if (ret) {
- 		/* Apply workaround delay for certain panels */
- 		apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
- 		/* Compare sinks to determine if this was a spontaneous HPD toggle */
- 		if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
- 			/*
- 			* Sinks match - this was a spontaneous HDMI HPD toggle.
- 			*/
- 			drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
- 			fake_reconnect = true;
- 		}
- 
- 		/* Update connector state */
- 		amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 		drm_modeset_lock_all(dev);
- 		dm_restore_drm_connector_state(dev, connector);
- 		drm_modeset_unlock_all(dev);
- 
- 		/* Only notify OS if sink actually changed */
- 		if (!fake_reconnect && aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 			drm_kms_helper_hotplug_event(dev);
- 	}
- 
- 	/* Release the cached sink reference */
- 	if (aconnector->hdmi_prev_sink) {
- 		dc_sink_release(aconnector->hdmi_prev_sink);
- 		aconnector->hdmi_prev_sink = NULL;
- 	}
- 
- 	scoped_guard(mutex, &adev->dm.dc_lock) {
- 		if (reallow_idle && dc->caps.ips_support)
- 			dc_allow_idle_optimizations(dc, true);
- 	}
- }
- 
- static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 	bool ret = false;
- 	bool debounce_required = false;
- 
- 	if (adev->dm.disable_hpd_irq)
- 		return;
- 
- 	/*
- 	 * In case of failure or MST no need to update connector status or notify the OS
- 	 * since (for MST case) MST does this in its own context.
- 	 */
- 	guard(mutex)(&aconnector->hpd_lock);
- 
- 	if (adev->dm.hdcp_workqueue) {
- 		hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index);
- 		dm_con_state->update_hdcp = true;
- 	}
- 	if (aconnector->fake_enable)
- 		aconnector->fake_enable = false;
- 
- 	aconnector->timing_changed = false;
- 
- 	if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
- 		drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 
- 	/*
- 	 * Check for HDMI disconnect with debounce enabled.
- 	 */
- 	debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 &&
- 			      dc_is_hdmi_signal(aconnector->dc_link->connector_signal) &&
- 			      new_connection_type == dc_connection_none &&
- 			      aconnector->dc_link->local_sink != NULL);
- 
- 	if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 		emulated_link_detect(aconnector->dc_link);
- 
- 		drm_modeset_lock_all(dev);
- 		dm_restore_drm_connector_state(dev, connector);
- 		drm_modeset_unlock_all(dev);
- 
- 		if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 			drm_kms_helper_connector_hotplug_event(connector);
- 	} else if (debounce_required) {
- 		/*
- 		 * HDMI disconnect detected - schedule delayed work instead of
- 		 * processing immediately. This allows us to coalesce spurious
- 		 * HDMI signals from physical unplugs.
- 		 */
- 		drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
- 			    aconnector->hdmi_hpd_debounce_delay_ms);
- 
- 		/* Cache the current sink for later comparison */
- 		if (aconnector->hdmi_prev_sink)
- 			dc_sink_release(aconnector->hdmi_prev_sink);
- 		aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
- 		if (aconnector->hdmi_prev_sink)
- 			dc_sink_retain(aconnector->hdmi_prev_sink);
- 
- 		/* Schedule delayed detection. */
- 		if (mod_delayed_work(system_percpu_wq,
- 				 &aconnector->hdmi_hpd_debounce_work,
- 				 msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
- 			drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
- 
- 	} else {
- 
- 		/* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
- 		if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
- 			return;
- 
- 		scoped_guard(mutex, &adev->dm.dc_lock) {
- 			dc_exit_ips_for_hw_access(dc);
- 			ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
- 		}
- 		if (ret) {
- 			/* w/a delay for certain panels */
- 			apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
- 			amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 			drm_modeset_lock_all(dev);
- 			dm_restore_drm_connector_state(dev, connector);
- 			drm_modeset_unlock_all(dev);
- 
- 			if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 				drm_kms_helper_connector_hotplug_event(connector);
- 		}
- 	}
- }
- 
- static void handle_hpd_irq(void *param)
- {
- 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
- 
- 	handle_hpd_irq_helper(aconnector);
- 
- }
- 
- static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_rx_irq_offload_work_queue *offload_wq,
- 							union hpd_irq_data hpd_irq_data)
- {
- 	struct hpd_rx_irq_offload_work *offload_work = kzalloc_obj(*offload_work);
- 
- 	if (!offload_work) {
- 		drm_err(adev_to_drm(adev), "Failed to allocate hpd_rx_irq_offload_work.\n");
- 		return;
- 	}
- 
- 	INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
- 	offload_work->data = hpd_irq_data;
- 	offload_work->offload_wq = offload_wq;
- 	offload_work->adev = adev;
- 
- 	queue_work(offload_wq->wq, &offload_work->work);
- 	drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work");
- }
- 
- static void handle_hpd_rx_irq(void *param)
- {
- 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
- 	bool result = false;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	union hpd_irq_data hpd_irq_data;
- 	bool link_loss = false;
- 	bool has_left_work = false;
- 	int idx = dc_link->link_index;
- 	struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx];
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 
- 	memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
- 
- 	if (adev->dm.disable_hpd_irq)
- 		return;
- 
- 	/*
- 	 * TODO:Temporary add mutex to protect hpd interrupt not have a gpio
- 	 * conflict, after implement i2c helper, this mutex should be
- 	 * retired.
- 	 */
- 	mutex_lock(&aconnector->hpd_lock);
- 
- 	result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data,
- 						&link_loss, true, &has_left_work);
- 
- 	if (!has_left_work)
- 		goto out;
- 
- 	if (hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
- 		schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 		goto out;
- 	}
- 
- 	if (dc_link_dp_allow_hpd_rx_irq(dc_link)) {
- 		if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
- 			hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
- 			bool skip = false;
- 
- 			/*
- 			 * DOWN_REP_MSG_RDY is also handled by polling method
- 			 * mgr->cbs->poll_hpd_irq()
- 			 */
- 			spin_lock(&offload_wq->offload_lock);
- 			skip = offload_wq->is_handling_mst_msg_rdy_event;
- 
- 			if (!skip)
- 				offload_wq->is_handling_mst_msg_rdy_event = true;
- 
- 			spin_unlock(&offload_wq->offload_lock);
- 
- 			if (!skip)
- 				schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 
- 			goto out;
- 		}
- 
- 		if (link_loss) {
- 			bool skip = false;
- 
- 			spin_lock(&offload_wq->offload_lock);
- 			skip = offload_wq->is_handling_link_loss;
- 
- 			if (!skip)
- 				offload_wq->is_handling_link_loss = true;
- 
- 			spin_unlock(&offload_wq->offload_lock);
- 
- 			if (!skip)
- 				schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 
- 			goto out;
- 		}
- 	}
- 
- out:
- 	if (result && !is_mst_root_connector) {
- 		/* Downstream Port status changed. */
- 		if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
- 			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 
- 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(dc_link);
- 
- 			if (aconnector->fake_enable)
- 				aconnector->fake_enable = false;
- 
- 			amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 
- 			drm_modeset_lock_all(dev);
- 			dm_restore_drm_connector_state(dev, connector);
- 			drm_modeset_unlock_all(dev);
- 
- 			drm_kms_helper_connector_hotplug_event(connector);
- 		} else {
- 			bool ret = false;
- 
- 			mutex_lock(&adev->dm.dc_lock);
- 			dc_exit_ips_for_hw_access(dc);
- 			ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX);
- 			mutex_unlock(&adev->dm.dc_lock);
- 
- 			if (ret) {
- 				if (aconnector->fake_enable)
- 					aconnector->fake_enable = false;
- 
- 				amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 				drm_modeset_lock_all(dev);
- 				dm_restore_drm_connector_state(dev, connector);
- 				drm_modeset_unlock_all(dev);
- 
- 				drm_kms_helper_connector_hotplug_event(connector);
- 			}
- 		}
- 	}
- 	if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) {
- 		if (adev->dm.hdcp_workqueue)
- 			hdcp_handle_cpirq(adev->dm.hdcp_workqueue,  aconnector->base.index);
- 	}
- 
- 	if (dc_link->type != dc_connection_mst_branch)
- 		drm_dp_cec_irq(&aconnector->dm_dp_aux.aux);
- 
- 	mutex_unlock(&aconnector->hpd_lock);
- }
- 
- static int register_hpd_handlers(struct amdgpu_device *adev)
- {
- 	struct drm_device *dev = adev_to_drm(adev);
- 	struct drm_connector *connector;
- 	struct amdgpu_dm_connector *aconnector;
- 	const struct dc_link *dc_link;
- 	struct dc_interrupt_params int_params = {0};
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD,
- 			dmub_hpd_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd callback");
- 			return -EINVAL;
- 		}
- 
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ,
- 			dmub_hpd_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd callback");
- 			return -EINVAL;
- 		}
- 
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_SENSE_NOTIFY,
- 			dmub_hpd_sense_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd sense callback");
- 			return -EINVAL;
- 		}
- 	}
- 
- 	list_for_each_entry(connector,
- 			&dev->mode_config.connector_list, head)	{
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		dc_link = aconnector->dc_link;
- 
- 		if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
- 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 			int_params.irq_source = dc_link->irq_source_hpd;
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_HPD1 ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_HPD6) {
- 				drm_err(adev_to_drm(adev), "Failed to register hpd irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				handle_hpd_irq, (void *) aconnector))
- 				return -ENOMEM;
- 		}
- 
- 		if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- 
- 			/* Also register for DP short pulse (hpd_rx). */
- 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 			int_params.irq_source =	dc_link->irq_source_hpd_rx;
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_HPD1RX ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_HPD6RX) {
- 				drm_err(adev_to_drm(adev), "Failed to register hpd rx irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				handle_hpd_rx_irq, (void *) aconnector))
- 				return -ENOMEM;
- 		}
- 	}
- 	return 0;
- }
- 
- /* Register IRQ sources and initialize IRQ callbacks */
- static int dce110_register_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r;
- 	int i;
- 	unsigned int src_id;
- 	unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
- 	/* Use different interrupts for VBLANK on DCE 6 vs. newer. */
- 	const unsigned int vblank_d1 =
- 		adev->dm.dc->ctx->dce_version >= DCE_VERSION_8_0
- 		? VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 : 1;
- 
- 	if (adev->family >= AMDGPU_FAMILY_AI)
- 		client_id = SOC15_IH_CLIENTID_DCE;
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	/*
- 	 * Actions of amdgpu_irq_add_id():
- 	 * 1. Register a set() function with base driver.
- 	 *    Base driver will call set() function to enable/disable an
- 	 *    interrupt in DC hardware.
- 	 * 2. Register amdgpu_dm_irq_handler().
- 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
- 	 *    coming from DC hardware.
- 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
- 	 *    for acknowledging and handling.
- 	 */
- 
- 	/* Use VBLANK interrupt */
- 	for (i = 0; i < adev->mode_info.num_crtc; i++) {
- 		src_id = vblank_d1 + i;
- 		r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->crtc_irq);
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, src_id, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_VBLANK1 ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_VBLANK6) {
- 			drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_crtc_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	if (dc_supports_vrr(adev->dm.dc->ctx->dce_version)) {
- 		/* Use VUPDATE interrupt */
- 		for (i = 0; i < adev->mode_info.num_crtc; i++) {
- 			src_id = VISLANDS30_IV_SRCID_D1_V_UPDATE_INT + i * 2;
- 			r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->vupdate_irq);
- 			if (r) {
- 				drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n");
- 				return r;
- 			}
- 
- 			int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 			int_params.irq_source =
- 				dc_interrupt_to_irq_source(dc, src_id, 0);
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_VUPDATE1 ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_VUPDATE6) {
- 				drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			c_irq_params = &adev->dm.vupdate_params[
- 				int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1];
- 			c_irq_params->adev = adev;
- 			c_irq_params->irq_src = int_params.irq_source;
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				dm_vupdate_high_irq, c_irq_params))
- 				return -ENOMEM;
- 		}
- 	}
- 
- 	/* Use GRPH_PFLIP interrupt */
- 	for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP;
- 			i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) {
- 		r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq);
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_PFLIP_FIRST ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_PFLIP_LAST) {
- 			drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_pflip_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	/* HPD */
- 	r = amdgpu_irq_add_id(adev, client_id,
- 			VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n");
- 		return r;
- 	}
- 
- 	r = register_hpd_handlers(adev);
- 
- 	return r;
- }
- 
- /* Register IRQ sources and initialize IRQ callbacks */
- static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r;
- 	int i;
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- 	static const unsigned int vrtl_int_srcid[] = {
- 		DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
- 	};
- #endif
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	/*
- 	 * Actions of amdgpu_irq_add_id():
- 	 * 1. Register a set() function with base driver.
- 	 *    Base driver will call set() function to enable/disable an
- 	 *    interrupt in DC hardware.
- 	 * 2. Register amdgpu_dm_irq_handler().
- 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
- 	 *    coming from DC hardware.
- 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
- 	 *    for acknowledging and handling.
- 	 */
- 
- 	/* Use otg vertical line interrupt */
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- 	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
- 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
- 				vrtl_int_srcid[i], &adev->vline0_irq);
- 
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
- 			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
- 			drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
- 					- DC_IRQ_SOURCE_DC1_VLINE0];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_dcn_vertical_interrupt0_high_irq,
- 			c_irq_params))
- 			return -ENOMEM;
- 	}
- #endif
- 
- 	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
- 	 * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
- 	 * to trigger at end of each vblank, regardless of state of the lock,
- 	 * matching DCE behaviour.
- 	 */
- 	for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT;
- 	     i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1;
- 	     i++) {
- 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq);
- 
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_VUPDATE1 ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_VUPDATE6) {
- 			drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_vupdate_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	/* HPD */
- 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
- 			&adev->hpd_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n");
- 		return r;
- 	}
- 
- 	r = register_hpd_handlers(adev);
- 
- 	return r;
- }
- /* Register Outbox IRQ sources and initialize IRQ callbacks */
- static int register_outbox_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r, i;
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT,
- 			&adev->dmub_outbox_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add outbox irq id!\n");
- 		return r;
- 	}
- 
- 	if (dc->ctx->dmub_srv) {
- 		i = DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT;
- 		int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 		int_params.irq_source =
- 		dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		c_irq_params = &adev->dm.dmub_outbox_params[0];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_dmub_outbox1_low_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	return 0;
- }
- 
  /*
   * Acquires the lock for the atomic state object and returns
   * the new atomic state.
@@@ -5079,7 -2133,7 +2138,7 @@@ int dm_atomic_get_state(struct drm_atom
  	return 0;
  }
  
- static struct dm_atomic_state *
+ STATIC_IFN_KUNIT struct dm_atomic_state *
  dm_atomic_get_new_state(struct drm_atomic_commit *state)
  {
  	struct drm_device *dev = state->dev;
@@@ -5096,6 -2150,7 +2155,7 @@@
  
  	return NULL;
  }
+ EXPORT_IF_KUNIT(dm_atomic_get_new_state);
  
  static struct drm_private_state *
  dm_atomic_duplicate_state(struct drm_private_obj *obj)
@@@ -5121,8 -2176,8 +2181,8 @@@
  	return &new_state->base;
  }
  
- static void dm_atomic_destroy_state(struct drm_private_obj *obj,
- 				    struct drm_private_state *state)
+ STATIC_IFN_KUNIT void dm_atomic_destroy_state(struct drm_private_obj *obj,
+ 					      struct drm_private_state *state)
  {
  	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
  
@@@ -5131,6 -2186,7 +2191,7 @@@
  
  	kfree(dm_state);
  }
+ EXPORT_IF_KUNIT(dm_atomic_destroy_state);
  
  static struct drm_private_state *
  dm_atomic_create_state(struct drm_private_obj *obj)
@@@ -5202,420 -2258,6 +2263,6 @@@ static int amdgpu_dm_mode_config_init(s
  	return 0;
  }
  
- #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12
- #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
- #define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
- #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50
- 
- void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
- 				     int bl_idx)
- {
- 	struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[bl_idx];
- 
- 	if (caps->caps_valid)
- 		return;
- 
- #if defined(CONFIG_ACPI)
- 	amdgpu_acpi_get_backlight_caps(caps);
- 
- 	/* validate the firmware value is sane */
- 	if (caps->caps_valid) {
- 		int spread = caps->max_input_signal - caps->min_input_signal;
- 
- 		if (caps->max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
- 		    caps->min_input_signal < 0 ||
- 		    spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
- 		    spread < AMDGPU_DM_MIN_SPREAD) {
- 			drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n",
- 				      caps->min_input_signal, caps->max_input_signal);
- 			caps->caps_valid = false;
- 		}
- 	}
- 
- 	if (!caps->caps_valid) {
- 		caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- 		caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
- 		caps->caps_valid = true;
- 	}
- #else
- 	if (caps->aux_support)
- 		return;
- 
- 	caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- 	caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
- 	caps->caps_valid = true;
- #endif
- }
- 
- static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
- 				unsigned int *min, unsigned int *max)
- {
- 	if (!caps)
- 		return 0;
- 
- 	if (caps->aux_support) {
- 		// Firmware limits are in nits, DC API wants millinits.
- 		*max = 1000 * caps->aux_max_input_signal;
- 		*min = 1000 * caps->aux_min_input_signal;
- 	} else {
- 		// Firmware limits are 8-bit, PWM control is 16-bit.
- 		*max = 0x101 * caps->max_input_signal;
- 		*min = 0x101 * caps->min_input_signal;
- 	}
- 	return 1;
- }
- 
- /* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
- static inline u32 scale_input_to_fw(int min, int max, u64 input)
- {
- 	return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
- }
- 
- /* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
- static inline u32 scale_fw_to_input(int min, int max, u64 input)
- {
- 	return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL);
- }
- 
- static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
- 				      unsigned int min, unsigned int max,
- 				      uint32_t *user_brightness)
- {
- 	u32 brightness = scale_input_to_fw(min, max, *user_brightness);
- 	u8 lower_signal, upper_signal, upper_lum, lower_lum, lum;
- 	int left, right;
- 
- 	if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)
- 		return;
- 
- 	if (!caps->data_points)
- 		return;
- 
- 	/*
- 	 * Handle the case where brightness is below the first data point
- 	 * Interpolate between (0,0) and (first_signal, first_lum)
- 	 */
- 	if (brightness < caps->luminance_data[0].input_signal) {
- 		lum = DIV_ROUND_CLOSEST(caps->luminance_data[0].luminance * brightness,
- 					caps->luminance_data[0].input_signal);
- 		goto scale;
- 	}
- 
- 	left = 0;
- 	right = caps->data_points - 1;
- 	while (left <= right) {
- 		int mid = left + (right - left) / 2;
- 		u8 signal = caps->luminance_data[mid].input_signal;
- 
- 		/* Exact match found */
- 		if (signal == brightness) {
- 			lum = caps->luminance_data[mid].luminance;
- 			goto scale;
- 		}
- 
- 		if (signal < brightness)
- 			left = mid + 1;
- 		else
- 			right = mid - 1;
- 	}
- 
- 	/* verify bound */
- 	if (left >= caps->data_points)
- 		left = caps->data_points - 1;
- 
- 	/* At this point, left > right */
- 	lower_signal = caps->luminance_data[right].input_signal;
- 	upper_signal = caps->luminance_data[left].input_signal;
- 	lower_lum = caps->luminance_data[right].luminance;
- 	upper_lum = caps->luminance_data[left].luminance;
- 
- 	/* interpolate */
- 	if (right == left || !lower_lum)
- 		lum = upper_lum;
- 	else
- 		lum = lower_lum + DIV_ROUND_CLOSEST((upper_lum - lower_lum) *
- 						    (brightness - lower_signal),
- 						    upper_signal - lower_signal);
- scale:
- 	*user_brightness = scale_fw_to_input(min, max,
- 					     DIV_ROUND_CLOSEST(lum * brightness, 101));
- }
- 
- static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
- 					uint32_t brightness)
- {
- 	unsigned int min, max;
- 
- 	if (!get_brightness_range(caps, &min, &max))
- 		return brightness;
- 
- 	convert_custom_brightness(caps, min, max, &brightness);
- 
- 	// Rescale 0..max to min..max
- 	return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max);
- }
- 
- static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps,
- 				      uint32_t brightness)
- {
- 	unsigned int min, max;
- 
- 	if (!get_brightness_range(caps, &min, &max))
- 		return brightness;
- 
- 	if (brightness < min)
- 		return 0;
- 	// Rescale min..max to 0..max
- 	return DIV_ROUND_CLOSEST_ULL((u64)max * (brightness - min),
- 				 max - min);
- }
- 
- static struct dc_stream_state *dm_find_stream_with_link(
- 	struct amdgpu_display_manager *dm,
- 	struct dc_link *link)
- {
- 	struct dc_state *cur_dc_state = dm->dc->current_state;
- 	struct dc_stream_state *stream = NULL;
- 	int i;
- 
- 	for (i = 0; i < cur_dc_state->stream_count; i++) {
- 		stream = cur_dc_state->streams[i];
- 		if (stream->link == link)
- 			return stream;
- 	}
- 
- 	return NULL;
- }
- 
- static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx,
- 					 u32 user_brightness)
- {
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct dc_link *link;
- 	u32 brightness = 0;
- 	bool rc = false, reallow_idle = false;
- 	struct drm_connector *connector;
- 	struct dc_stream_state *stream;
- 	unsigned int min, max;
- 
- 	list_for_each_entry(connector, &dm->ddev->mode_config.connector_list, head) {
- 		struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 		if (aconnector->bl_idx != bl_idx)
- 			continue;
- 
- 		/* if connector is off, save the brightness for next time it's on */
- 		if (!aconnector->base.encoder) {
- 			dm->brightness[bl_idx] = user_brightness;
- 			dm->actual_brightness[bl_idx] = 0;
- 			return;
- 		}
- 	}
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	caps = &dm->backlight_caps[bl_idx];
- 
- 	dm->brightness[bl_idx] = user_brightness;
- 	/* update scratch register */
- 	if (bl_idx == 0)
- 		amdgpu_atombios_scratch_regs_set_backlight_level(dm->adev, dm->brightness[bl_idx]);
- 	brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
- 	link = (struct dc_link *)dm->backlight_link[bl_idx];
- 
- 	/* Apply brightness quirk */
- 	if (caps->brightness_mask)
- 		brightness |= caps->brightness_mask;
- 
- 	if (trace_amdgpu_dm_brightness_enabled()) {
- 		trace_amdgpu_dm_brightness(__builtin_return_address(0),
- 					   user_brightness,
- 					   brightness,
- 					   caps->aux_support,
- 					   power_supply_is_system_supplied() > 0);
- 	}
- 
- 	stream = dm_find_stream_with_link(dm, link);
- 	if (!stream)
- 		return;
- 
- 	mutex_lock(&dm->dc_lock);
- 	if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
- 		dc_allow_idle_optimizations(dm->dc, false);
- 		reallow_idle = true;
- 	}
- 
- 	if (caps->aux_support) {
- 		rc = mod_power_set_backlight_nits(dm->power_module, stream, brightness,
- 			AUX_BL_DEFAULT_TRANSITION_TIME_MS, false, true);
- 	} else {
- 		/* power module uses millipercent */
- 		get_brightness_range(caps, &min, &max);
- 		brightness = DIV_ROUND_CLOSEST(brightness * 100, (max - min)) * 1000;
- 		rc = mod_power_set_backlight_percent(dm->power_module, stream,
- 						     brightness, 0, false);
- 	}
- 
- 	/*
- 	 * Some kms clients create a ramped backlight transition effect
- 	 * by rapidly changing the backlight. Yet we must wait on dmcub
- 	 * fw to exit psr/replay before programming backlight. To
- 	 * prevent lag, keep disable psr/replay and let the next atomic
- 	 * flip clear the event.
- 	 *
- 	 * ToDo: use ISM to handle rapidly backlight change
- 	 *
- 	 * Rapidly backlight change is similar to rapidly cursor events,
- 	 * which is now handled by ISM. ISM can delay the event until system
- 	 * is really idle, so we may use ISM to handle backlight change as well.
- 	 */
- 	amdgpu_dm_psr_set_event(dm, stream, true,
- 		psr_event_hw_programming, true);
- 	amdgpu_dm_replay_set_event(dm, stream, true,
- 		replay_event_hw_programming, true);
- 
- 	if (dm->dc->caps.ips_support && reallow_idle)
- 		dc_allow_idle_optimizations(dm->dc, true);
- 
- 	mutex_unlock(&dm->dc_lock);
- 
- 	if (rc)
- 		dm->actual_brightness[bl_idx] = user_brightness;
- }
- 
- static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
- {
- 	struct amdgpu_display_manager *dm = bl_get_data(bd);
- 	int i;
- 
- 	for (i = 0; i < dm->num_of_edps; i++) {
- 		if (bd == dm->backlight_dev[i])
- 			break;
- 	}
- 	if (i >= AMDGPU_DM_MAX_NUM_EDP)
- 		i = 0;
- 	amdgpu_dm_backlight_set_level(dm, i, bd->props.brightness);
- 
- 	return 0;
- }
- 
- static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx)
- {
- 	int ret;
- 	struct amdgpu_dm_backlight_caps caps;
- 	struct dc_link *link = (struct dc_link *)dm->backlight_link[bl_idx];
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	caps = dm->backlight_caps[bl_idx];
- 
- 	if (caps.aux_support) {
- 		u32 avg, peak;
- 
- 		if (!dc_link_get_backlight_level_nits(link, &avg, &peak))
- 			return dm->brightness[bl_idx];
- 		return convert_brightness_to_user(&caps, avg);
- 	}
- 
- 	ret = dc_link_get_backlight_level(link);
- 
- 	if (ret == DC_ERROR_UNEXPECTED)
- 		return dm->brightness[bl_idx];
- 
- 	return convert_brightness_to_user(&caps, ret);
- }
- 
- static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
- {
- 	struct amdgpu_display_manager *dm = bl_get_data(bd);
- 	int i;
- 
- 	for (i = 0; i < dm->num_of_edps; i++) {
- 		if (bd == dm->backlight_dev[i])
- 			break;
- 	}
- 	if (i >= AMDGPU_DM_MAX_NUM_EDP)
- 		i = 0;
- 	return amdgpu_dm_backlight_get_level(dm, i);
- }
- 
- static const struct backlight_ops amdgpu_dm_backlight_ops = {
- 	.options = BL_CORE_SUSPENDRESUME,
- 	.get_brightness = amdgpu_dm_backlight_get_brightness,
- 	.update_status	= amdgpu_dm_backlight_update_status,
- };
- 
- static void
- amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_device *drm = aconnector->base.dev;
- 	struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
- 	struct backlight_properties props = { 0 };
- 	struct amdgpu_dm_backlight_caps *caps;
- 	char bl_name[16];
- 	int min, max;
- 	int real_brightness;
- 	int init_brightness;
- 
- 	if (aconnector->bl_idx == -1)
- 		return;
- 
- 	if (!acpi_video_backlight_use_native()) {
- 		drm_info(drm, "Skipping amdgpu DM backlight registration\n");
- 		/* Try registering an ACPI video backlight device instead. */
- 		acpi_video_register_backlight();
- 		return;
- 	}
- 
- 	caps = &dm->backlight_caps[aconnector->bl_idx];
- 	if (get_brightness_range(caps, &min, &max)) {
- 		if (power_supply_is_system_supplied() > 0)
- 			props.brightness = DIV_ROUND_CLOSEST(max * caps->ac_level, 100);
- 		else
- 			props.brightness = DIV_ROUND_CLOSEST(max * caps->dc_level, 100);
- 		/* min is zero, so max needs to be adjusted */
- 		props.max_brightness = max;
- 		drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
- 			caps->ac_level, caps->dc_level);
- 	} else
- 		props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL;
- 
- 	init_brightness = props.brightness;
- 
- 	if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) {
- 		drm_info(drm, "Using custom brightness curve\n");
- 		props.scale = BACKLIGHT_SCALE_NON_LINEAR;
- 	} else
- 		props.scale = BACKLIGHT_SCALE_LINEAR;
- 	props.type = BACKLIGHT_RAW;
- 
- 	snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
- 		 drm->primary->index + aconnector->bl_idx);
- 
- 	dm->backlight_dev[aconnector->bl_idx] =
- 		backlight_device_register(bl_name, aconnector->base.kdev, dm,
- 					  &amdgpu_dm_backlight_ops, &props);
- 	dm->brightness[aconnector->bl_idx] = props.brightness;
- 
- 	if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) {
- 		drm_err(drm, "DM: Backlight registration failed!\n");
- 		dm->backlight_dev[aconnector->bl_idx] = NULL;
- 	} else {
- 		/*
- 		 * dm->brightness[x] can be inconsistent just after startup until
- 		 * ops.get_brightness is called.
- 		 */
- 		real_brightness =
- 			amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]);
- 
- 		if (real_brightness != init_brightness) {
- 			dm->actual_brightness[aconnector->bl_idx] = real_brightness;
- 			dm->brightness[aconnector->bl_idx] = real_brightness;
- 		}
- 		drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name);
- 	}
- }
- 
  static int initialize_plane(struct amdgpu_display_manager *dm,
  			    struct amdgpu_mode_info *mode_info, int plane_id,
  			    enum drm_plane_type plane_type,
@@@ -5657,42 -2299,6 +2304,6 @@@
  }
  
  
- static void setup_backlight_device(struct amdgpu_display_manager *dm,
- 				   struct amdgpu_dm_connector *aconnector)
- {
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct dc_link *link = aconnector->dc_link;
- 	int bl_idx = dm->num_of_edps;
- 
- 	if (!(link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) ||
- 	    link->type == dc_connection_none)
- 		return;
- 
- 	if (dm->num_of_edps >= AMDGPU_DM_MAX_NUM_EDP) {
- 		drm_warn(adev_to_drm(dm->adev), "Too much eDP connections, skipping backlight setup for additional eDPs\n");
- 		return;
- 	}
- 
- 	aconnector->bl_idx = bl_idx;
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	dm->backlight_link[bl_idx] = link;
- 	dm->num_of_edps++;
- 
- 	update_connector_ext_caps(aconnector);
- 	caps = &dm->backlight_caps[aconnector->bl_idx];
- 
- 	/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
- 	if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
- 		drm_object_attach_property(&aconnector->base.base,
- 					   dm->adev->mode_info.abm_level_property,
- 					   ABM_SYSFS_CONTROL);
- }
- 
- static void amdgpu_set_panel_orientation(struct drm_connector *connector);
- 
- 
- 
  /*
   * In this architecture, the association
   * connector -> encoder -> crtc
@@@ -5804,7 -2410,7 +2415,7 @@@ static int amdgpu_dm_initialize_drm_dev
  	case IP_VERSION(4, 0, 1):
  	case IP_VERSION(4, 2, 0):
  	case IP_VERSION(4, 2, 1):
- 		if (register_outbox_irq_handlers(dm->adev)) {
+ 		if (amdgpu_dm_register_outbox_irq_handlers(dm->adev)) {
  			drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  			goto fail;
  		}
@@@ -5917,7 -2523,7 +2528,7 @@@
  			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
  
  		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(link);
+ 			amdgpu_dm_emulated_link_detect(link);
  			amdgpu_dm_update_connector_after_detect(aconnector);
  		} else {
  			bool ret = false;
@@@ -5929,7 -2535,7 +2540,7 @@@
  
  			if (ret) {
  				amdgpu_dm_update_connector_after_detect(aconnector);
- 				setup_backlight_device(dm, aconnector);
+ 				amdgpu_dm_setup_backlight_device(dm, aconnector);
  
  				/* Disable PSR if Replay can be enabled */
  				if (replay_feature_enabled)
@@@ -5981,7 -2587,7 +2592,7 @@@
  	case CHIP_VEGA10:
  	case CHIP_VEGA12:
  	case CHIP_VEGA20:
- 		if (dce110_register_irq_handlers(dm->adev)) {
+ 		if (amdgpu_dm_dce110_register_irq_handlers(dm->adev)) {
  			drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  			goto fail;
  		}
@@@ -6011,7 -2617,7 +2622,7 @@@
  		case IP_VERSION(4, 0, 1):
  		case IP_VERSION(4, 2, 0):
  		case IP_VERSION(4, 2, 1):
- 			if (dcn10_register_irq_handlers(dm->adev)) {
+ 			if (amdgpu_dm_dcn10_register_irq_handlers(dm->adev)) {
  				drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  				goto fail;
  			}
@@@ -6049,10 -2655,11 +2660,11 @@@ static void amdgpu_dm_destroy_drm_devic
   *
   * Calculate and program the display watermarks and line buffer allocation.
   */
- static void dm_bandwidth_update(struct amdgpu_device *adev)
+ STATIC_IFN_KUNIT void dm_bandwidth_update(struct amdgpu_device *adev)
  {
  	/* TODO: implement later */
  }
+ EXPORT_IF_KUNIT(dm_bandwidth_update);
  
  static const struct amdgpu_display_funcs dm_display_funcs = {
  	.bandwidth_update = dm_bandwidth_update, /* called unconditionally */
@@@ -6102,78 -2709,6 +2714,6 @@@ DEVICE_ATTR_WO(s3_debug)
  
  #endif
  
- static int dm_init_microcode(struct amdgpu_device *adev)
- {
- 	char *fw_name_dmub;
- 	int r;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(2, 1, 0):
- 		fw_name_dmub = FIRMWARE_RENOIR_DMUB;
- 		if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
- 			fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 0):
- 		if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0))
- 			fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB;
- 		else
- 			fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 1):
- 		fw_name_dmub = FIRMWARE_VANGOGH_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 2):
- 		fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 3):
- 		fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		fw_name_dmub = FIRMWARE_DCN_314_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 5):
- 		fw_name_dmub = FIRMWARE_DCN_315_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 6):
- 		fw_name_dmub = FIRMWARE_DCN316_DMUB;
- 		break;
- 	case IP_VERSION(3, 2, 0):
- 		fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB;
- 		break;
- 	case IP_VERSION(3, 2, 1):
- 		fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB;
- 		break;
- 	case IP_VERSION(3, 5, 0):
- 		fw_name_dmub = FIRMWARE_DCN_35_DMUB;
- 		break;
- 	case IP_VERSION(3, 5, 1):
- 		fw_name_dmub = FIRMWARE_DCN_351_DMUB;
- 		break;
- 	case IP_VERSION(3, 6, 0):
- 		fw_name_dmub = FIRMWARE_DCN_36_DMUB;
- 		break;
- 	case IP_VERSION(4, 0, 1):
- 		fw_name_dmub = FIRMWARE_DCN_401_DMUB;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 		fw_name_dmub = FIRMWARE_DCN_42_DMUB;
- 		break;
- 	case IP_VERSION(4, 2, 1):
- 		fw_name_dmub = FIRMWARE_DCN_42B_DMUB;
- 		break;
- 	default:
- 		/* ASIC doesn't support DMUB. */
- 		return 0;
- 	}
- 	r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, AMDGPU_UCODE_REQUIRED,
- 				 "%s", fw_name_dmub);
- 	return r;
- }
- 
  static int dm_early_init(struct amdgpu_ip_block *ip_block)
  {
  	struct amdgpu_device *adev = ip_block->adev;
@@@ -6324,22 -2859,13 +2864,13 @@@
  	return dm_init_microcode(adev);
  }
  
- static bool modereset_required(struct drm_crtc_state *crtc_state)
+ STATIC_IFN_KUNIT bool modereset_required(struct drm_crtc_state *crtc_state)
  {
  	return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
  }
+ EXPORT_IF_KUNIT(modereset_required);
  
- static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
- {
- 	drm_encoder_cleanup(encoder);
- 	kfree(encoder);
- }
- 
- static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
- 	.destroy = amdgpu_dm_encoder_destroy,
- };
- 
- static int
+ STATIC_IFN_KUNIT int
  fill_plane_color_attributes(const struct drm_plane_state *plane_state,
  			    const enum surface_pixel_format format,
  			    enum dc_color_space *color_space)
@@@ -6386,11 -2912,11 +2917,11 @@@
  
  	return 0;
  }
+ EXPORT_IF_KUNIT(fill_plane_color_attributes);
  
  static int
  fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
  			    const struct drm_plane_state *plane_state,
- 			    const u64 tiling_flags,
  			    struct dc_plane_info *plane_info,
  			    struct dc_plane_address *address,
  			    bool tmz_surface)
@@@ -6488,7 -3014,7 +3019,7 @@@
  		return ret;
  
  	ret = amdgpu_dm_plane_fill_plane_buffer_attributes(adev, afb, plane_info->format,
- 					   plane_info->rotation, tiling_flags,
+ 					   plane_info->rotation,
  					   &plane_info->tiling_info,
  					   &plane_info->plane_size,
  					   &plane_info->dcc, address,
@@@ -6524,7 -3050,6 +3055,6 @@@ static int fill_dc_plane_attributes(str
  	dc_plane_state->scaling_quality = scaling_info.scaling_quality;
  
  	ret = fill_dc_plane_info_and_addr(adev, plane_state,
- 					  afb->tiling_flags,
  					  &plane_info,
  					  &dc_plane_state->address,
  					  afb->tmz_surface);
@@@ -6724,2119 -3249,6 +3254,6 @@@ ffu
  			   &flip_addrs->dirty_rect_count, true);
  }
  
- static void update_stream_scaling_settings(struct drm_device *dev,
- 					   const struct drm_display_mode *mode,
- 					   const struct dm_connector_state *dm_state,
- 					   struct dc_stream_state *stream)
- {
- 	enum amdgpu_rmx_type rmx_type;
- 
- 	struct rect src = { 0 }; /* viewport in composition space*/
- 	struct rect dst = { 0 }; /* stream addressable area */
- 
- 	/* no mode. nothing to be done */
- 	if (!mode)
- 		return;
- 
- 	/* Full screen scaling by default */
- 	src.width = mode->hdisplay;
- 	src.height = mode->vdisplay;
- 	dst.width = stream->timing.h_addressable;
- 	dst.height = stream->timing.v_addressable;
- 
- 	if (dm_state) {
- 		rmx_type = dm_state->scaling;
- 		if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) {
- 			if (src.width * dst.height <
- 					src.height * dst.width) {
- 				/* height needs less upscaling/more downscaling */
- 				dst.width = src.width *
- 						dst.height / src.height;
- 			} else {
- 				/* width needs less upscaling/more downscaling */
- 				dst.height = src.height *
- 						dst.width / src.width;
- 			}
- 		} else if (rmx_type == RMX_CENTER) {
- 			dst = src;
- 		}
- 
- 		dst.x = (stream->timing.h_addressable - dst.width) / 2;
- 		dst.y = (stream->timing.v_addressable - dst.height) / 2;
- 
- 		if (dm_state->underscan_enable) {
- 			dst.x += dm_state->underscan_hborder / 2;
- 			dst.y += dm_state->underscan_vborder / 2;
- 			dst.width -= dm_state->underscan_hborder;
- 			dst.height -= dm_state->underscan_vborder;
- 		}
- 	}
- 
- 	stream->src = src;
- 	stream->dst = dst;
- 
- 	drm_dbg_kms(dev, "Destination Rectangle x:%d  y:%d  width:%d  height:%d\n",
- 		    dst.x, dst.y, dst.width, dst.height);
- 
- }
- 
- static enum dc_color_depth
- convert_color_depth_from_display_info(const struct drm_connector *connector,
- 				      bool is_y420, int requested_bpc)
- {
- 	u8 bpc;
- 
- 	if (is_y420) {
- 		bpc = 8;
- 
- 		/* Cap display bpc based on HDMI 2.0 HF-VSDB */
- 		if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)
- 			bpc = 16;
- 		else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
- 			bpc = 12;
- 		else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
- 			bpc = 10;
- 	} else {
- 		bpc = (uint8_t)connector->display_info.bpc;
- 		/* Assume 8 bpc by default if no bpc is specified. */
- 		bpc = bpc ? bpc : 8;
- 	}
- 
- 	if (requested_bpc > 0) {
- 		/*
- 		 * Cap display bpc based on the user requested value.
- 		 *
- 		 * The value for state->max_bpc may not correctly updated
- 		 * depending on when the connector gets added to the state
- 		 * or if this was called outside of atomic check, so it
- 		 * can't be used directly.
- 		 */
- 		bpc = min_t(u8, bpc, requested_bpc);
- 
- 		/* Round down to the nearest even number. */
- 		bpc = bpc - (bpc & 1);
- 	}
- 
- 	switch (bpc) {
- 	case 0:
- 		/*
- 		 * Temporary Work around, DRM doesn't parse color depth for
- 		 * EDID revision before 1.4
- 		 * TODO: Fix edid parsing
- 		 */
- 		return COLOR_DEPTH_888;
- 	case 6:
- 		return COLOR_DEPTH_666;
- 	case 8:
- 		return COLOR_DEPTH_888;
- 	case 10:
- 		return COLOR_DEPTH_101010;
- 	case 12:
- 		return COLOR_DEPTH_121212;
- 	case 14:
- 		return COLOR_DEPTH_141414;
- 	case 16:
- 		return COLOR_DEPTH_161616;
- 	default:
- 		return COLOR_DEPTH_UNDEFINED;
- 	}
- }
- 
- static enum dc_aspect_ratio
- get_aspect_ratio(const struct drm_display_mode *mode_in)
- {
- 	/* 1-1 mapping, since both enums follow the HDMI spec. */
- 	return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio;
- }
- 
- static enum dc_color_space
- get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
- 		       const struct drm_connector_state *connector_state)
- {
- 	enum dc_color_space color_space = COLOR_SPACE_SRGB;
- 
- 	switch (connector_state->colorspace) {
- 	case DRM_MODE_COLORIMETRY_BT601_YCC:
- 		if (dc_crtc_timing->flags.Y_ONLY)
- 			color_space = COLOR_SPACE_YCBCR601_LIMITED;
- 		else
- 			color_space = COLOR_SPACE_YCBCR601;
- 		break;
- 	case DRM_MODE_COLORIMETRY_BT709_YCC:
- 		if (dc_crtc_timing->flags.Y_ONLY)
- 			color_space = COLOR_SPACE_YCBCR709_LIMITED;
- 		else
- 			color_space = COLOR_SPACE_YCBCR709;
- 		break;
- 	case DRM_MODE_COLORIMETRY_OPRGB:
- 		color_space = COLOR_SPACE_ADOBERGB;
- 		break;
- 	case DRM_MODE_COLORIMETRY_BT2020_RGB:
- 	case DRM_MODE_COLORIMETRY_BT2020_YCC:
- 		if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
- 			color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
- 		else
- 			color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
- 		break;
- 	case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601
- 	default:
- 		if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
- 			color_space = COLOR_SPACE_SRGB;
- 			if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
- 				color_space = COLOR_SPACE_SRGB_LIMITED;
- 		/*
- 		 * 27030khz is the separation point between HDTV and SDTV
- 		 * according to HDMI spec, we use YCbCr709 and YCbCr601
- 		 * respectively
- 		 */
- 		} else if (dc_crtc_timing->pix_clk_100hz > 270300) {
- 			if (dc_crtc_timing->flags.Y_ONLY)
- 				color_space =
- 					COLOR_SPACE_YCBCR709_LIMITED;
- 			else
- 				color_space = COLOR_SPACE_YCBCR709;
- 		} else {
- 			if (dc_crtc_timing->flags.Y_ONLY)
- 				color_space =
- 					COLOR_SPACE_YCBCR601_LIMITED;
- 			else
- 				color_space = COLOR_SPACE_YCBCR601;
- 		}
- 		break;
- 	}
- 
- 	return color_space;
- }
- 
- static enum display_content_type
- get_output_content_type(const struct drm_connector_state *connector_state)
- {
- 	switch (connector_state->content_type) {
- 	default:
- 	case DRM_MODE_CONTENT_TYPE_NO_DATA:
- 		return DISPLAY_CONTENT_TYPE_NO_DATA;
- 	case DRM_MODE_CONTENT_TYPE_GRAPHICS:
- 		return DISPLAY_CONTENT_TYPE_GRAPHICS;
- 	case DRM_MODE_CONTENT_TYPE_PHOTO:
- 		return DISPLAY_CONTENT_TYPE_PHOTO;
- 	case DRM_MODE_CONTENT_TYPE_CINEMA:
- 		return DISPLAY_CONTENT_TYPE_CINEMA;
- 	case DRM_MODE_CONTENT_TYPE_GAME:
- 		return DISPLAY_CONTENT_TYPE_GAME;
- 	}
- }
- 
- static bool adjust_colour_depth_from_display_info(
- 	struct dc_crtc_timing *timing_out,
- 	const struct drm_display_info *info)
- {
- 	enum dc_color_depth depth = timing_out->display_color_depth;
- 	int normalized_clk;
- 
- 	do {
- 		normalized_clk = timing_out->pix_clk_100hz / 10;
- 		/* YCbCr 4:2:0 requires additional adjustment of 1/2 */
- 		if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- 			normalized_clk /= 2;
- 		/* Adjusting pix clock following on HDMI spec based on colour depth */
- 		switch (depth) {
- 		case COLOR_DEPTH_888:
- 			break;
- 		case COLOR_DEPTH_101010:
- 			normalized_clk = (normalized_clk * 30) / 24;
- 			break;
- 		case COLOR_DEPTH_121212:
- 			normalized_clk = (normalized_clk * 36) / 24;
- 			break;
- 		case COLOR_DEPTH_161616:
- 			normalized_clk = (normalized_clk * 48) / 24;
- 			break;
- 		default:
- 			/* The above depths are the only ones valid for HDMI. */
- 			return false;
- 		}
- 		if (normalized_clk <= info->max_tmds_clock) {
- 			timing_out->display_color_depth = depth;
- 			return true;
- 		}
- 	} while (--depth > COLOR_DEPTH_666);
- 	return false;
- }
- 
- static void fill_stream_properties_from_drm_display_mode(
- 	struct dc_stream_state *stream,
- 	const struct drm_display_mode *mode_in,
- 	const struct drm_connector *connector,
- 	const struct drm_connector_state *connector_state,
- 	const struct dc_stream_state *old_stream,
- 	int requested_bpc)
- {
- 	struct dc_crtc_timing *timing_out = &stream->timing;
- 	const struct drm_display_info *info = &connector->display_info;
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct hdmi_vendor_infoframe hv_frame;
- 	struct hdmi_avi_infoframe avi_frame;
- 	ssize_t err;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 	memset(&hv_frame, 0, sizeof(hv_frame));
- 	memset(&avi_frame, 0, sizeof(avi_frame));
- 
- 	timing_out->h_border_left = 0;
- 	timing_out->h_border_right = 0;
- 	timing_out->v_border_top = 0;
- 	timing_out->v_border_bottom = 0;
- 	/* TODO: un-hardcode */
- 	if (drm_mode_is_420_only(info, mode_in)
- 			&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 			    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 			&& aconnector
- 			&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420)
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 	else if (drm_mode_is_420_also(info, mode_in)
- 			&& aconnector
- 			&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420
- 			|| aconnector->force_yuv420_output))
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
- 			&& aconnector
- 			&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422
- 			|| aconnector->force_yuv422_output))
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
- 	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
- 			&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 			    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 			&& aconnector
- 			&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR444)
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
- 	else
- 		timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
- 
- 	timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
- 	timing_out->display_color_depth = convert_color_depth_from_display_info(
- 		connector,
- 		(timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420),
- 		requested_bpc);
- 	timing_out->scan_type = SCANNING_TYPE_NODATA;
- 	timing_out->hdmi_vic = 0;
- 
- 	if (old_stream) {
- 		timing_out->vic = old_stream->timing.vic;
- 		timing_out->flags.HSYNC_POSITIVE_POLARITY = old_stream->timing.flags.HSYNC_POSITIVE_POLARITY;
- 		timing_out->flags.VSYNC_POSITIVE_POLARITY = old_stream->timing.flags.VSYNC_POSITIVE_POLARITY;
- 	} else {
- 		timing_out->vic = drm_match_cea_mode(mode_in);
- 		if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
- 			timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
- 		if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
- 			timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
- 	}
- 
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 		stream->signal == SIGNAL_TYPE_HDMI_FRL) {
- 		err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
- 							       (struct drm_connector *)connector,
- 							       mode_in);
- 		if (err < 0)
- 			drm_warn_once(connector->dev, "Failed to setup avi infoframe on connector %s: %zd\n",
- 				      connector->name, err);
- 		timing_out->vic = avi_frame.video_code;
- 		err = drm_hdmi_vendor_infoframe_from_display_mode(&hv_frame,
- 								  (struct drm_connector *)connector,
- 								  mode_in);
- 		if (err < 0)
- 			drm_warn_once(connector->dev, "Failed to setup vendor infoframe on connector %s: %zd\n",
- 				      connector->name, err);
- 		timing_out->hdmi_vic = hv_frame.vic;
- 	}
- 
- 	if (aconnector && is_freesync_video_mode(mode_in, aconnector)) {
- 		timing_out->h_addressable = mode_in->hdisplay;
- 		timing_out->h_total = mode_in->htotal;
- 		timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start;
- 		timing_out->h_front_porch = mode_in->hsync_start - mode_in->hdisplay;
- 		timing_out->v_total = mode_in->vtotal;
- 		timing_out->v_addressable = mode_in->vdisplay;
- 		timing_out->v_front_porch = mode_in->vsync_start - mode_in->vdisplay;
- 		timing_out->v_sync_width = mode_in->vsync_end - mode_in->vsync_start;
- 		timing_out->pix_clk_100hz = mode_in->clock * 10;
- 	} else {
- 		timing_out->h_addressable = mode_in->crtc_hdisplay;
- 		timing_out->h_total = mode_in->crtc_htotal;
- 		timing_out->h_sync_width = mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
- 		timing_out->h_front_porch = mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
- 		timing_out->v_total = mode_in->crtc_vtotal;
- 		timing_out->v_addressable = mode_in->crtc_vdisplay;
- 		timing_out->v_front_porch = mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
- 		timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
- 		timing_out->pix_clk_100hz = mode_in->crtc_clock * 10;
- 	}
- 
- 	timing_out->aspect_ratio = get_aspect_ratio(mode_in);
- 
- 	stream->out_transfer_func.type = TF_TYPE_PREDEFINED;
- 	stream->out_transfer_func.tf = TRANSFER_FUNCTION_SRGB;
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
- 		if (!adjust_colour_depth_from_display_info(timing_out, info) &&
- 		    drm_mode_is_420_also(info, mode_in) &&
- 		    timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) {
- 			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 			adjust_colour_depth_from_display_info(timing_out, info);
- 		}
- 	}
- 
- 	stream->output_color_space = get_output_color_space(timing_out, connector_state);
- 	stream->content_type = get_output_content_type(connector_state);
- }
- 
- static void fill_audio_info(struct audio_info *audio_info,
- 			    const struct drm_connector *drm_connector,
- 			    const struct dc_sink *dc_sink)
- {
- 	int i = 0;
- 	int cea_revision = 0;
- 	const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
- 
- 	audio_info->manufacture_id = edid_caps->manufacturer_id;
- 	audio_info->product_id = edid_caps->product_id;
- 
- 	cea_revision = drm_connector->display_info.cea_rev;
- 
- 	strscpy(audio_info->display_name,
- 		edid_caps->display_name,
- 		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
- 
- 	if (cea_revision >= 3) {
- 		audio_info->mode_count = edid_caps->audio_mode_count;
- 
- 		for (i = 0; i < audio_info->mode_count; ++i) {
- 			audio_info->modes[i].format_code =
- 					(enum audio_format_code)
- 					(edid_caps->audio_modes[i].format_code);
- 			audio_info->modes[i].channel_count =
- 					edid_caps->audio_modes[i].channel_count;
- 			audio_info->modes[i].sample_rates.all =
- 					edid_caps->audio_modes[i].sample_rate;
- 			audio_info->modes[i].sample_size =
- 					edid_caps->audio_modes[i].sample_size;
- 		}
- 	}
- 
- 	audio_info->flags.all = edid_caps->speaker_flags;
- 
- 	/* TODO: We only check for the progressive mode, check for interlace mode too */
- 	if (drm_connector->latency_present[0]) {
- 		audio_info->video_latency = drm_connector->video_latency[0];
- 		audio_info->audio_latency = drm_connector->audio_latency[0];
- 	}
- 
- 	/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
- 
- }
- 
- static void
- copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode,
- 				      struct drm_display_mode *dst_mode)
- {
- 	dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay;
- 	dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay;
- 	dst_mode->crtc_clock = src_mode->crtc_clock;
- 	dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start;
- 	dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end;
- 	dst_mode->crtc_hsync_start =  src_mode->crtc_hsync_start;
- 	dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end;
- 	dst_mode->crtc_htotal = src_mode->crtc_htotal;
- 	dst_mode->crtc_hskew = src_mode->crtc_hskew;
- 	dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start;
- 	dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end;
- 	dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start;
- 	dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end;
- 	dst_mode->crtc_vtotal = src_mode->crtc_vtotal;
- }
- 
- static void
- decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
- 					const struct drm_display_mode *native_mode,
- 					bool scale_enabled)
- {
- 	if (scale_enabled || (
- 	    native_mode->clock == drm_mode->clock &&
- 	    native_mode->htotal == drm_mode->htotal &&
- 	    native_mode->vtotal == drm_mode->vtotal)) {
- 		if (native_mode->crtc_clock)
- 			copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
- 	} else {
- 		/* no scaling nor amdgpu inserted, no need to patch */
- 	}
- }
- 
- static struct dc_sink *
- create_fake_sink(struct drm_device *dev, struct dc_link *link)
- {
- 	struct dc_sink_init_data sink_init_data = { 0 };
- 	struct dc_sink *sink = NULL;
- 
- 	sink_init_data.link = link;
- 	sink_init_data.sink_signal = link->connector_signal;
- 
- 	sink = dc_sink_create(&sink_init_data);
- 	if (!sink) {
- 		drm_err(dev, "Failed to create sink!\n");
- 		return NULL;
- 	}
- 	sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
- 
- 	return sink;
- }
- 
- static void set_multisync_trigger_params(
- 		struct dc_stream_state *stream)
- {
- 	struct dc_stream_state *master = NULL;
- 
- 	if (stream->triggered_crtc_reset.enabled) {
- 		master = stream->triggered_crtc_reset.event_source;
- 		stream->triggered_crtc_reset.event =
- 			master->timing.flags.VSYNC_POSITIVE_POLARITY ?
- 			CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING;
- 		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL;
- 	}
- }
- 
- static void set_master_stream(struct dc_stream_state *stream_set[],
- 			      int stream_count)
- {
- 	int j, highest_rfr = 0, master_stream = 0;
- 
- 	for (j = 0;  j < stream_count; j++) {
- 		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
- 			int refresh_rate = 0;
- 
- 			refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/
- 				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
- 			if (refresh_rate > highest_rfr) {
- 				highest_rfr = refresh_rate;
- 				master_stream = j;
- 			}
- 		}
- 	}
- 	for (j = 0;  j < stream_count; j++) {
- 		if (stream_set[j])
- 			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
- 	}
- }
- 
- static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
- {
- 	int i = 0;
- 	struct dc_stream_state *stream;
- 
- 	if (context->stream_count < 2)
- 		return;
- 	for (i = 0; i < context->stream_count ; i++) {
- 		if (!context->streams[i])
- 			continue;
- 		/*
- 		 * TODO: add a function to read AMD VSDB bits and set
- 		 * crtc_sync_master.multi_sync_enabled flag
- 		 * For now it's set to false
- 		 */
- 	}
- 
- 	set_master_stream(context->streams, context->stream_count);
- 
- 	for (i = 0; i < context->stream_count ; i++) {
- 		stream = context->streams[i];
- 
- 		if (!stream)
- 			continue;
- 
- 		set_multisync_trigger_params(stream);
- 	}
- }
- 
- /**
-  * DOC: FreeSync Video
-  *
-  * When a userspace application wants to play a video, the content follows a
-  * standard format definition that usually specifies the FPS for that format.
-  * The below list illustrates some video format and the expected FPS,
-  * respectively:
-  *
-  * - TV/NTSC (23.976 FPS)
-  * - Cinema (24 FPS)
-  * - TV/PAL (25 FPS)
-  * - TV/NTSC (29.97 FPS)
-  * - TV/NTSC (30 FPS)
-  * - Cinema HFR (48 FPS)
-  * - TV/PAL (50 FPS)
-  * - Commonly used (60 FPS)
-  * - Multiples of 24 (48,72,96 FPS)
-  *
-  * The list of standards video format is not huge and can be added to the
-  * connector modeset list beforehand. With that, userspace can leverage
-  * FreeSync to extends the front porch in order to attain the target refresh
-  * rate. Such a switch will happen seamlessly, without screen blanking or
-  * reprogramming of the output in any other way. If the userspace requests a
-  * modesetting change compatible with FreeSync modes that only differ in the
-  * refresh rate, DC will skip the full update and avoid blink during the
-  * transition. For example, the video player can change the modesetting from
-  * 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without
-  * causing any display blink. This same concept can be applied to a mode
-  * setting change.
-  */
- static struct drm_display_mode *
- get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector,
- 		bool use_probed_modes)
- {
- 	struct drm_display_mode *m, *m_pref = NULL;
- 	u16 current_refresh, highest_refresh;
- 	struct list_head *list_head = use_probed_modes ?
- 		&aconnector->base.probed_modes :
- 		&aconnector->base.modes;
- 
- 	if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 		return NULL;
- 
- 	if (aconnector->freesync_vid_base.clock != 0)
- 		return &aconnector->freesync_vid_base;
- 
- 	/* Find the preferred mode */
- 	list_for_each_entry(m, list_head, head) {
- 		if (m->type & DRM_MODE_TYPE_PREFERRED) {
- 			m_pref = m;
- 			break;
- 		}
- 	}
- 
- 	if (!m_pref) {
- 		/* Probably an EDID with no preferred mode. Fallback to first entry */
- 		m_pref = list_first_entry_or_null(
- 				&aconnector->base.modes, struct drm_display_mode, head);
- 		if (!m_pref) {
- 			drm_dbg_driver(aconnector->base.dev, "No preferred mode found in EDID\n");
- 			return NULL;
- 		}
- 	}
- 
- 	highest_refresh = drm_mode_vrefresh(m_pref);
- 
- 	/*
- 	 * Find the mode with highest refresh rate with same resolution.
- 	 * For some monitors, preferred mode is not the mode with highest
- 	 * supported refresh rate.
- 	 */
- 	list_for_each_entry(m, list_head, head) {
- 		current_refresh  = drm_mode_vrefresh(m);
- 
- 		if (m->hdisplay == m_pref->hdisplay &&
- 		    m->vdisplay == m_pref->vdisplay &&
- 		    highest_refresh < current_refresh) {
- 			highest_refresh = current_refresh;
- 			m_pref = m;
- 		}
- 	}
- 
- 	drm_mode_copy(&aconnector->freesync_vid_base, m_pref);
- 	return m_pref;
- }
- 
- static bool is_freesync_video_mode(const struct drm_display_mode *mode,
- 		struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_display_mode *high_mode;
- 	int timing_diff;
- 
- 	high_mode = get_highest_refresh_rate_mode(aconnector, false);
- 	if (!high_mode || !mode)
- 		return false;
- 
- 	timing_diff = high_mode->vtotal - mode->vtotal;
- 
- 	if (high_mode->clock == 0 || high_mode->clock != mode->clock ||
- 	    high_mode->hdisplay != mode->hdisplay ||
- 	    high_mode->vdisplay != mode->vdisplay ||
- 	    high_mode->hsync_start != mode->hsync_start ||
- 	    high_mode->hsync_end != mode->hsync_end ||
- 	    high_mode->htotal != mode->htotal ||
- 	    high_mode->hskew != mode->hskew ||
- 	    high_mode->vscan != mode->vscan ||
- 	    high_mode->vsync_start - mode->vsync_start != timing_diff ||
- 	    high_mode->vsync_end - mode->vsync_end != timing_diff)
- 		return false;
- 	else
- 		return true;
- }
- 
- #if defined(CONFIG_DRM_AMD_DC_FP)
- static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
- 			    struct dc_sink *sink, struct dc_stream_state *stream,
- 			    struct dsc_dec_dpcd_caps *dsc_caps)
- {
- 	stream->timing.flags.DSC = 0;
- 	dsc_caps->is_dsc_supported = false;
- 
- 	if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 	    sink->sink_signal == SIGNAL_TYPE_EDP)) {
- 		if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE)
- 			dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
- 				aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
- 				aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- 				dsc_caps);
- 		else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
- 			if (aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT &&
- 					!aconnector->dsc_settings.dsc_force_disable_passthrough &&
- 					aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0 &&
- 					sink->edid_caps.frl_dsc_support &&
- 					sink->edid_caps.max_frl_rate > 0 &&
- 					sink->edid_caps.frl_dsc_max_frl_rate > 0)
- 				dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
- 			else
- 				dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
- 				      aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
- 				      aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- 				      dsc_caps);
- 		}
- 	} else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
- 		if (sink->edid_caps.frl_dsc_support &&
- 				sink->edid_caps.max_frl_rate > 0 &&
- 				sink->edid_caps.frl_dsc_max_frl_rate > 0)
- 			dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
- 	}
- }
- 
- static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
- 				    struct dc_sink *sink, struct dc_stream_state *stream,
- 				    struct dsc_dec_dpcd_caps *dsc_caps,
- 				    uint32_t max_dsc_target_bpp_limit_override)
- {
- 	const struct dc_link_settings *verified_link_cap = NULL;
- 	u32 link_bw_in_kbps;
- 	u32 edp_min_bpp_x16, edp_max_bpp_x16;
- 	struct dc *dc = sink->ctx->dc;
- 	struct dc_dsc_bw_range bw_range = {0};
- 	struct dc_dsc_config dsc_cfg = {0};
- 	struct dc_dsc_config_options dsc_options = {0};
- 
- 	dc_dsc_get_default_config_option(dc, &dsc_options);
- 	dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16;
- 
- 	verified_link_cap = dc_link_get_link_cap(stream->link);
- 	link_bw_in_kbps = dc_link_bandwidth_kbps(stream->link, verified_link_cap);
- 	edp_min_bpp_x16 = 8 * 16;
- 	edp_max_bpp_x16 = 8 * 16;
- 
- 	if (edp_max_bpp_x16 > dsc_caps->edp_max_bits_per_pixel)
- 		edp_max_bpp_x16 = dsc_caps->edp_max_bits_per_pixel;
- 
- 	if (edp_max_bpp_x16 < edp_min_bpp_x16)
- 		edp_min_bpp_x16 = edp_max_bpp_x16;
- 
- 	if (dc_dsc_compute_bandwidth_range(dc->res_pool->dscs[0],
- 				dc->debug.dsc_min_slice_height_override,
- 				edp_min_bpp_x16, edp_max_bpp_x16,
- 				dsc_caps,
- 				&stream->timing,
- 				dc_link_get_highest_encoding_format(aconnector->dc_link),
- 				&bw_range)) {
- 
- 		if (bw_range.max_kbps < link_bw_in_kbps) {
- 			if (dc_dsc_compute_config(dc->res_pool->dscs[0],
- 					dsc_caps,
- 					&dsc_options,
- 					0,
- 					&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link),
- 					&dsc_cfg)) {
- 				stream->timing.dsc_cfg = dsc_cfg;
- 				stream->timing.flags.DSC = 1;
- 				stream->timing.dsc_cfg.bits_per_pixel = edp_max_bpp_x16;
- 			}
- 			return;
- 		}
- 	}
- 
- 	if (dc_dsc_compute_config(dc->res_pool->dscs[0],
- 				dsc_caps,
- 				&dsc_options,
- 				link_bw_in_kbps,
- 				&stream->timing,
- 				dc_link_get_highest_encoding_format(aconnector->dc_link),
- 				&dsc_cfg)) {
- 		stream->timing.dsc_cfg = dsc_cfg;
- 		stream->timing.flags.DSC = 1;
- 	}
- }
- 
- static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
- 					struct dc_sink *sink, struct dc_stream_state *stream,
- 					struct dsc_dec_dpcd_caps *dsc_caps)
- {
- 	struct drm_connector *drm_connector = &aconnector->base;
- 	u32 link_bandwidth_kbps;
- 	struct dc *dc = sink->ctx->dc;
- 	const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL;
- 	u32 converter_bw_in_kbps;
- 	u32 sink_bw_in_kbps;
- 	u32 dsc_sink_bw_in_kbps;
- 	u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
- 	u32 dsc_max_supported_bw_in_kbps;
- 	u32 max_dsc_target_bpp_limit_override =
- 		drm_connector->display_info.max_dsc_bpp;
- 	struct dc_dsc_config_options dsc_options = {0};
- 
- 	dc_dsc_get_default_config_option(dc, &dsc_options);
- 	dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16;
- 
- 	link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
- 							dc_link_get_link_cap(aconnector->dc_link));
- 
- 	/* Set DSC policy according to dsc_clock_en */
- 	dc_dsc_policy_set_enable_dsc_when_not_needed(
- 		aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
- 
- 	if (sink->sink_signal == SIGNAL_TYPE_EDP &&
- 	    !aconnector->dc_link->panel_config.dsc.disable_dsc_edp &&
- 	    dc->caps.edp_dsc_support && aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE) {
- 
- 		apply_dsc_policy_for_edp(aconnector, sink, stream, dsc_caps, max_dsc_target_bpp_limit_override);
- 
- 	} else if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) {
- 		if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) {
- 			if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 						dsc_caps,
- 						&dsc_options,
- 						link_bandwidth_kbps,
- 						&stream->timing,
- 						dc_link_get_highest_encoding_format(aconnector->dc_link),
- 						&stream->timing.dsc_cfg)) {
- 				stream->timing.flags.DSC = 1;
- 				drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from SST RX\n",
- 							__func__, drm_connector->name);
- 			}
- 		} else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
- 			timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link));
- 			converter_bw_in_kbps = aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps;
- 			sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate);
- 			dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
- 
- 			if (dsc_caps->is_frl) {
- 				max_supported_bw_in_kbps = min(link_bandwidth_kbps, converter_bw_in_kbps);
- 				max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, sink_bw_in_kbps);
- 				dsc_max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps);
- 			} else {
- 				max_supported_bw_in_kbps = link_bandwidth_kbps;
- 				dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
- 			}
- 
- 			if (timing_bw_in_kbps > max_supported_bw_in_kbps &&
- 					max_supported_bw_in_kbps > 0 &&
- 					dsc_max_supported_bw_in_kbps > 0)
- 				if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 						dsc_caps,
- 						&dsc_options,
- 						dsc_max_supported_bw_in_kbps,
- 						&stream->timing,
- 						dc_link_get_highest_encoding_format(aconnector->dc_link),
- 						&stream->timing.dsc_cfg)) {
- 					stream->timing.flags.DSC = 1;
- 					drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from %s\n",
- 							__func__, drm_connector->name,
- 							(dsc_caps->is_frl == 1) ? "HDMI FRL RX" : "DP-HDMI PCON");
- 				}
- 		}
- 	}
- 	else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
- 		struct dc_dsc_policy dsc_policy = {0};
- 
- 		frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link);
- 		if (frl_verified_link_cap->frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE &&
- 			aconnector->dc_link->frl_flags.force_frl_dsc) {
- 			dc_dsc_policy_set_enable_dsc_when_not_needed(true);
- 			dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
- 		}
- 
- 		timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL);
- 		link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link, frl_verified_link_cap->frl_link_rate);
- 		dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
- 
- 		if ((timing_bw_in_kbps > link_bandwidth_kbps && dsc_sink_bw_in_kbps > 0) ||
- 		    (dsc_policy.enable_dsc_when_not_needed || dsc_options.force_dsc_when_not_needed)) {
- 			if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 					dsc_caps,
- 					&dsc_options,
- 					dsc_sink_bw_in_kbps,
- 					&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link),
- 					&stream->timing.dsc_cfg)) {
- 				stream->timing.flags.DSC = 1;
- 				drm_dbg_driver(drm_connector->dev, "%s: HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n",
- 						__func__, drm_connector->name);
- 			}
- 		}
- 	}
- 
- 	/* Overwrite the stream flag if DSC is enabled through debugfs */
- 	if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE)
- 		stream->timing.flags.DSC = 1;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h)
- 		stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v)
- 		stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel)
- 		stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel;
- }
- #endif
- 
- static struct dc_stream_state *
- create_stream_for_sink(struct drm_connector *connector,
- 		       const struct drm_display_mode *drm_mode,
- 		       const struct dm_connector_state *dm_state,
- 		       const struct dc_stream_state *old_stream,
- 		       int requested_bpc)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct drm_display_mode *preferred_mode = NULL;
- 	const struct drm_connector_state *con_state = &dm_state->base;
- 	struct dc_stream_state *stream = NULL;
- 	struct drm_display_mode mode;
- 	struct drm_display_mode saved_mode;
- 	struct drm_display_mode *freesync_mode = NULL;
- 	bool native_mode_found = false;
- 	bool recalculate_timing = false;
- 	bool scale = dm_state->scaling != RMX_OFF;
- 	int mode_refresh;
- 	int preferred_refresh = 0;
- 	enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
- #if defined(CONFIG_DRM_AMD_DC_FP)
- 	struct dsc_dec_dpcd_caps dsc_caps = {0};
- #endif
- 	struct dc_link *link = NULL;
- 	struct dc_sink *sink = NULL;
- 
- 	drm_mode_init(&mode, drm_mode);
- 	memset(&saved_mode, 0, sizeof(saved_mode));
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) {
- 		aconnector = NULL;
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		link = aconnector->dc_link;
- 	} else {
- 		struct drm_writeback_connector *wbcon = NULL;
- 		struct amdgpu_dm_wb_connector *dm_wbcon = NULL;
- 
- 		wbcon = drm_connector_to_writeback(connector);
- 		dm_wbcon = to_amdgpu_dm_wb_connector(wbcon);
- 		link = dm_wbcon->link;
- 	}
- 
- 	if (!aconnector || !aconnector->dc_sink) {
- 		sink = create_fake_sink(dev, link);
- 		if (!sink)
- 			return stream;
- 
- 	} else {
- 		sink = aconnector->dc_sink;
- 		dc_sink_retain(sink);
- 	}
- 
- 	stream = dc_create_stream_for_sink(sink);
- 
- 	if (stream == NULL) {
- 		drm_err(dev, "Failed to create stream for sink!\n");
- 		goto finish;
- 	}
- 
- 	/* We leave this NULL for writeback connectors */
- 	stream->dm_stream_context = aconnector;
- 
- 	stream->timing.flags.LTE_340MCSC_SCRAMBLE =
- 		connector->display_info.hdmi.scdc.scrambling.low_rates;
- 
- 	list_for_each_entry(preferred_mode, &connector->modes, head) {
- 		/* Search for preferred mode */
- 		if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
- 			native_mode_found = true;
- 			break;
- 		}
- 	}
- 	if (!native_mode_found)
- 		preferred_mode = list_first_entry_or_null(
- 				&connector->modes,
- 				struct drm_display_mode,
- 				head);
- 
- 	mode_refresh = drm_mode_vrefresh(&mode);
- 
- 	if (preferred_mode == NULL) {
- 		/*
- 		 * This may not be an error, the use case is when we have no
- 		 * usermode calls to reset and set mode upon hotplug. In this
- 		 * case, we call set mode ourselves to restore the previous mode
- 		 * and the modelist may not be filled in time.
- 		 */
- 		drm_dbg_driver(dev, "No preferred mode found\n");
- 	} else if (aconnector) {
- 		recalculate_timing = amdgpu_freesync_vid_mode &&
- 				 is_freesync_video_mode(&mode, aconnector);
- 		if (recalculate_timing) {
- 			freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
- 			drm_mode_copy(&saved_mode, &mode);
- 			saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio;
- 			drm_mode_copy(&mode, freesync_mode);
- 			mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio;
- 		} else {
- 			decide_crtc_timing_for_drm_display_mode(
- 					&mode, preferred_mode, scale);
- 
- 			preferred_refresh = drm_mode_vrefresh(preferred_mode);
- 		}
- 	}
- 
- 	if (recalculate_timing)
- 		drm_mode_set_crtcinfo(&saved_mode, 0);
- 
- 	/*
- 	 * If scaling is enabled and refresh rate didn't change
- 	 * we copy the vic and polarities of the old timings
- 	 */
- 	if (!scale || mode_refresh != preferred_refresh)
- 		fill_stream_properties_from_drm_display_mode(
- 			stream, &mode, connector, con_state, NULL,
- 			requested_bpc);
- 	else
- 		fill_stream_properties_from_drm_display_mode(
- 			stream, &mode, connector, con_state, old_stream,
- 			requested_bpc);
- 
- 	/* The rest isn't needed for writeback connectors */
- 	if (!aconnector)
- 		goto finish;
- 
- 	if (aconnector->timing_changed) {
- 		drm_dbg(aconnector->base.dev,
- 			"overriding timing for automated test, bpc %d, changing to %d\n",
- 			stream->timing.display_color_depth,
- 			aconnector->timing_requested->display_color_depth);
- 		stream->timing = *aconnector->timing_requested;
- 	}
- 
- #if defined(CONFIG_DRM_AMD_DC_FP)
- 	/* SST DSC determination policy */
- 	update_dsc_caps(aconnector, sink, stream, &dsc_caps);
- 	if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported)
- 		apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps);
- #endif
- 
- 	update_stream_scaling_settings(dev, &mode, dm_state, stream);
- 
- 	fill_audio_info(
- 		&stream->audio_info,
- 		connector,
- 		sink);
- 
- 	update_stream_signal(stream, sink);
- 
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 	    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 		mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
- 
- 	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 	    stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
- 	    stream->signal == SIGNAL_TYPE_EDP) {
- 		const struct dc_edid_caps *edid_caps;
- 		unsigned int disable_colorimetry = 0;
- 
- 		if (aconnector->dc_sink) {
- 			edid_caps = &aconnector->dc_sink->edid_caps;
- 			disable_colorimetry = edid_caps->panel_patch.disable_colorimetry;
- 		}
- 
- 		//
- 		// should decide stream support vsc sdp colorimetry capability
- 		// before building vsc info packet
- 		//
- 		stream->use_vsc_sdp_for_colorimetry = stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 &&
- 						      stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED &&
- 						      !disable_colorimetry;
- 
- 		if (stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22)
- 			tf = TRANSFER_FUNC_GAMMA_22;
- 		mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf);
- 		aconnector->sr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY;
- 
- 	}
- finish:
- 	dc_sink_release(sink);
- 
- 	return stream;
- }
- 
- /**
-  * amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display
-  * @aconnector: DM connector to poll (owns @base drm_connector and @dc_link)
-  * @force: if true, force polling even when DAC load detection was used
-  *
-  * Used for connectors that don't support HPD (hotplug detection) to
-  * periodically check whether the connector is connected to a display.
-  *
-  * When connection was determined via DAC load detection, we avoid
-  * re-running it on normal polls to prevent visible glitches, unless
-  * @force is set.
-  *
-  * Return: The probed connector status (connected/disconnected/unknown).
-  */
- static enum drm_connector_status
- amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dc_link *link = aconnector->dc_link;
- 	enum dc_connection_type conn_type = dc_connection_none;
- 	enum drm_connector_status status = connector_status_disconnected;
- 
- 	/* When we determined the connection using DAC load detection,
- 	 * do NOT poll the connector do detect disconnect because
- 	 * that would run DAC load detection again which can cause
- 	 * visible visual glitches.
- 	 *
- 	 * Only allow to poll such a connector again when forcing.
- 	 */
- 	if (!force && link->local_sink && link->type == dc_connection_analog_load)
- 		return connector->status;
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 
- 	if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) &&
- 	    conn_type != dc_connection_none) {
- 		mutex_lock(&adev->dm.dc_lock);
- 
- 		/* Only call full link detection when a sink isn't created yet,
- 		 * ie. just when the display is plugged in, otherwise we risk flickering.
- 		 */
- 		if (link->local_sink ||
- 			dc_link_detect(link, DETECT_REASON_HPD))
- 			status = connector_status_connected;
- 
- 		mutex_unlock(&adev->dm.dc_lock);
- 	}
- 
- 	if (connector->status != status) {
- 		if (status == connector_status_disconnected) {
- 			if (link->local_sink)
- 				dc_sink_release(link->local_sink);
- 
- 			link->local_sink = NULL;
- 			link->dpcd_sink_count = 0;
- 			link->type = dc_connection_none;
- 		}
- 
- 		amdgpu_dm_update_connector_after_detect(aconnector);
- 	}
- 
- 	mutex_unlock(&aconnector->hpd_lock);
- 	return status;
- }
- 
- /**
-  * amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
-  *
-  * A connector is considered connected when it has a sink that is not NULL.
-  * For connectors that support HPD (hotplug detection), the connection is
-  * handled in the HPD interrupt.
-  * For connectors that may not support HPD, such as analog connectors,
-  * DRM will call this function repeatedly to poll them.
-  *
-  * Notes:
-  * 1. This interface is NOT called in context of HPD irq.
-  * 2. This interface *is called* in context of user-mode ioctl. Which
-  *    makes it a bad place for *any* MST-related activity.
-  *
-  * @connector: The DRM connector we are checking. We convert it to
-  *             amdgpu_dm_connector so we can read the DC link and state.
-  * @force:     If true, do a full detect again. This is used even when
-  *             a lighter check would normally be used to avoid flicker.
-  *
-  * Return: The connector status (connected, disconnected, or unknown).
-  *
-  */
- static enum drm_connector_status
- amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 	update_subconnector_property(aconnector);
- 
- 	if (aconnector->base.force == DRM_FORCE_ON ||
- 		aconnector->base.force == DRM_FORCE_ON_DIGITAL)
- 		return connector_status_connected;
- 	else if (aconnector->base.force == DRM_FORCE_OFF)
- 		return connector_status_disconnected;
- 
- 	/* Poll analog connectors and only when either
- 	 * disconnected or connected to an analog display.
- 	 */
- 	if (drm_kms_helper_is_poll_worker() &&
- 		dc_connector_supports_analog(aconnector->dc_link->link_id.id) &&
- 		(!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog))
- 		return amdgpu_dm_connector_poll(aconnector, force);
- 
- 	return (aconnector->dc_sink ? connector_status_connected :
- 			connector_status_disconnected);
- }
- 
- int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
- 					    struct drm_connector_state *connector_state,
- 					    struct drm_property *property,
- 					    uint64_t val)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_old_state =
- 		to_dm_connector_state(connector->state);
- 	struct dm_connector_state *dm_new_state =
- 		to_dm_connector_state(connector_state);
- 
- 	int ret = -EINVAL;
- 
- 	if (property == dev->mode_config.scaling_mode_property) {
- 		enum amdgpu_rmx_type rmx_type;
- 
- 		switch (val) {
- 		case DRM_MODE_SCALE_CENTER:
- 			rmx_type = RMX_CENTER;
- 			break;
- 		case DRM_MODE_SCALE_ASPECT:
- 			rmx_type = RMX_ASPECT;
- 			break;
- 		case DRM_MODE_SCALE_FULLSCREEN:
- 			rmx_type = RMX_FULL;
- 			break;
- 		case DRM_MODE_SCALE_NONE:
- 		default:
- 			rmx_type = RMX_OFF;
- 			break;
- 		}
- 
- 		if (dm_old_state->scaling == rmx_type)
- 			return 0;
- 
- 		dm_new_state->scaling = rmx_type;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_hborder_property) {
- 		dm_new_state->underscan_hborder = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_vborder_property) {
- 		dm_new_state->underscan_vborder = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_property) {
- 		dm_new_state->underscan_enable = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.abm_level_property) {
- 		switch (val) {
- 		case ABM_SYSFS_CONTROL:
- 			dm_new_state->abm_sysfs_forbidden = false;
- 			break;
- 		case ABM_LEVEL_OFF:
- 			dm_new_state->abm_sysfs_forbidden = true;
- 			dm_new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
- 			break;
- 		default:
- 			dm_new_state->abm_sysfs_forbidden = true;
- 			dm_new_state->abm_level = val;
- 		}
- 		ret = 0;
- 	}
- 
- 	return ret;
- }
- 
- int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
- 					    const struct drm_connector_state *state,
- 					    struct drm_property *property,
- 					    uint64_t *val)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_state =
- 		to_dm_connector_state(state);
- 	int ret = -EINVAL;
- 
- 	if (property == dev->mode_config.scaling_mode_property) {
- 		switch (dm_state->scaling) {
- 		case RMX_CENTER:
- 			*val = DRM_MODE_SCALE_CENTER;
- 			break;
- 		case RMX_ASPECT:
- 			*val = DRM_MODE_SCALE_ASPECT;
- 			break;
- 		case RMX_FULL:
- 			*val = DRM_MODE_SCALE_FULLSCREEN;
- 			break;
- 		case RMX_OFF:
- 		default:
- 			*val = DRM_MODE_SCALE_NONE;
- 			break;
- 		}
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_hborder_property) {
- 		*val = dm_state->underscan_hborder;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_vborder_property) {
- 		*val = dm_state->underscan_vborder;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_property) {
- 		*val = dm_state->underscan_enable;
- 		ret = 0;
- 	} else if (property == adev->mode_info.abm_level_property) {
- 		if (!dm_state->abm_sysfs_forbidden)
- 			*val = ABM_SYSFS_CONTROL;
- 		else
- 			*val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
- 				dm_state->abm_level : 0;
- 		ret = 0;
- 	}
- 
- 	return ret;
- }
- 
- /**
-  * DOC: panel power savings
-  *
-  * The display manager allows you to set your desired **panel power savings**
-  * level (between 0-4, with 0 representing off), e.g. using the following::
-  *
-  *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
-  *
-  * Modifying this value can have implications on color accuracy, so tread
-  * carefully.
-  */
- 
- static ssize_t panel_power_savings_show(struct device *device,
- 					struct device_attribute *attr,
- 					char *buf)
- {
- 	struct drm_connector *connector = dev_get_drvdata(device);
- 	struct drm_device *dev = connector->dev;
- 	u8 val;
- 
- 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- 	val = to_dm_connector_state(connector->state)->abm_level ==
- 		ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
- 		to_dm_connector_state(connector->state)->abm_level;
- 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
- 
- 	return sysfs_emit(buf, "%u\n", val);
- }
- 
- static ssize_t panel_power_savings_store(struct device *device,
- 					 struct device_attribute *attr,
- 					 const char *buf, size_t count)
- {
- 	struct drm_connector *connector = dev_get_drvdata(device);
- 	struct drm_device *dev = connector->dev;
- 	long val;
- 	int ret;
- 
- 	ret = kstrtol(buf, 0, &val);
- 
- 	if (ret)
- 		return ret;
- 
- 	if (val < 0 || val > 4)
- 		return -EINVAL;
- 
- 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- 	if (to_dm_connector_state(connector->state)->abm_sysfs_forbidden)
- 		ret = -EBUSY;
- 	else
- 		to_dm_connector_state(connector->state)->abm_level = val ?:
- 			ABM_LEVEL_IMMEDIATE_DISABLE;
- 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
- 
- 	if (ret)
- 		return ret;
- 
- 	drm_kms_helper_hotplug_event(dev);
- 
- 	return count;
- }
- 
- static DEVICE_ATTR_RW(panel_power_savings);
- 
- static struct attribute *amdgpu_attrs[] = {
- 	&dev_attr_panel_power_savings.attr,
- 	NULL
- };
- 
- static const struct attribute_group amdgpu_group = {
- 	.name = "amdgpu",
- 	.attrs = amdgpu_attrs
- };
- 
- static bool
- amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector)
- {
- 	if (amdgpu_dm_abm_level >= 0)
- 		return false;
- 
- 	if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
- 		return false;
- 
- 	/* check for OLED panels */
- 	if (amdgpu_dm_connector->bl_idx >= 0) {
- 		struct drm_device *drm = amdgpu_dm_connector->base.dev;
- 		struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
- 		struct amdgpu_dm_backlight_caps *caps;
- 
- 		caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx];
- 		if (caps->aux_support)
- 			return false;
- 	}
- 
- 	return true;
- }
- 
- static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
- 
- 	if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector))
- 		sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group);
- 
- 	cec_notifier_conn_unregister(amdgpu_dm_connector->notifier);
- 	drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
- }
- 
- static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct amdgpu_display_manager *dm = &adev->dm;
- 
- 	/*
- 	 * Call only if mst_mgr was initialized before since it's not done
- 	 * for all connector types.
- 	 */
- 	if (aconnector->mst_mgr.dev)
- 		drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
- 
- 	/* Cancel and flush any pending HDMI HPD debounce work */
- 	if (aconnector->hdmi_hpd_debounce_delay_ms) {
- 		cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
- 		if (aconnector->hdmi_prev_sink) {
- 			dc_sink_release(aconnector->hdmi_prev_sink);
- 			aconnector->hdmi_prev_sink = NULL;
- 		}
- 	}
- 
- 	if (aconnector->bl_idx != -1) {
- 		backlight_device_unregister(dm->backlight_dev[aconnector->bl_idx]);
- 		dm->backlight_dev[aconnector->bl_idx] = NULL;
- 	}
- 
- 	if (aconnector->dc_em_sink)
- 		dc_sink_release(aconnector->dc_em_sink);
- 	aconnector->dc_em_sink = NULL;
- 	if (aconnector->dc_sink)
- 		dc_sink_release(aconnector->dc_sink);
- 	aconnector->dc_sink = NULL;
- 
- 	drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux);
- 	drm_connector_unregister(connector);
- 	drm_connector_cleanup(connector);
- 	kfree(aconnector->dm_dp_aux.aux.name);
- 
- 	kfree(connector);
- }
- 
- void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
- {
- 	struct dm_connector_state *state =
- 		to_dm_connector_state(connector->state);
- 
- 	if (connector->state)
- 		__drm_atomic_helper_connector_destroy_state(connector->state);
- 
- 	kfree(state);
- 
- 	state = kzalloc_obj(*state);
- 
- 	if (state) {
- 		state->scaling = RMX_OFF;
- 		state->underscan_enable = false;
- 		state->underscan_hborder = 0;
- 		state->underscan_vborder = 0;
- 		state->base.max_requested_bpc = 8;
- 		state->vcpi_slots = 0;
- 		state->pbn = 0;
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
- 			if (amdgpu_dm_abm_level <= 0)
- 				state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
- 			else
- 				state->abm_level = amdgpu_dm_abm_level;
- 		}
- 
- 		__drm_atomic_helper_connector_reset(connector, &state->base);
- 	}
- }
- 
- struct drm_connector_state *
- amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
- {
- 	struct dm_connector_state *state =
- 		to_dm_connector_state(connector->state);
- 
- 	struct dm_connector_state *new_state =
- 			kmemdup(state, sizeof(*state), GFP_KERNEL);
- 
- 	if (!new_state)
- 		return NULL;
- 
- 	__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
- 
- 	new_state->freesync_capable = state->freesync_capable;
- 	new_state->abm_level = state->abm_level;
- 	new_state->scaling = state->scaling;
- 	new_state->underscan_enable = state->underscan_enable;
- 	new_state->underscan_hborder = state->underscan_hborder;
- 	new_state->underscan_vborder = state->underscan_vborder;
- 	new_state->vcpi_slots = state->vcpi_slots;
- 	new_state->pbn = state->pbn;
- 	return &new_state->base;
- }
- 
- static int
- amdgpu_dm_connector_late_register(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 		to_amdgpu_dm_connector(connector);
- 	int r;
- 
- 	if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) {
- 		r = sysfs_create_group(&connector->kdev->kobj,
- 				       &amdgpu_group);
- 		if (r)
- 			return r;
- 	}
- 
- 	amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
- 
- 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
- 	    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
- 		amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev;
- 		r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux);
- 		if (r)
- 			return r;
- 	}
- 
- #if defined(CONFIG_DEBUG_FS)
- 	connector_debugfs_init(amdgpu_dm_connector);
- #endif
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
- 	const struct drm_edid *drm_edid;
- 	struct i2c_adapter *ddc;
- 	struct drm_device *dev = connector->dev;
- 
- 	if (dc_link && dc_link->aux_mode)
- 		ddc = &aconnector->dm_dp_aux.aux.ddc;
- 	else
- 		ddc = &aconnector->i2c->base;
- 
- 	drm_edid = drm_edid_read_ddc(connector, ddc);
- 	drm_edid_connector_update(connector, drm_edid);
- 	if (!drm_edid) {
- 		drm_err(dev, "No EDID found on connector: %s.\n", connector->name);
- 		return;
- 	}
- 
- 	aconnector->drm_edid = drm_edid;
- 	/* Update emulated (virtual) sink's EDID */
- 	if (dc_em_sink && dc_link) {
- 		// FIXME: Get rid of drm_edid_raw()
- 		const struct edid *edid = drm_edid_raw(drm_edid);
- 
- 		memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
- 		memmove(dc_em_sink->dc_edid.raw_edid, edid,
- 			(edid->extensions + 1) * EDID_LENGTH);
- 		dm_helpers_parse_edid_caps(
- 			dc_link,
- 			&dc_em_sink->dc_edid,
- 			&dc_em_sink->edid_caps);
- 	}
- }
- 
- static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
- 	.reset = amdgpu_dm_connector_funcs_reset,
- 	.detect = amdgpu_dm_connector_detect,
- 	.fill_modes = drm_helper_probe_single_connector_modes,
- 	.destroy = amdgpu_dm_connector_destroy,
- 	.atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
- 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- 	.atomic_set_property = amdgpu_dm_connector_atomic_set_property,
- 	.atomic_get_property = amdgpu_dm_connector_atomic_get_property,
- 	.late_register = amdgpu_dm_connector_late_register,
- 	.early_unregister = amdgpu_dm_connector_unregister,
- 	.force = amdgpu_dm_connector_funcs_force
- };
- 
- static int get_modes(struct drm_connector *connector)
- {
- 	return amdgpu_dm_connector_get_modes(connector);
- }
- 
- static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	struct dc_sink_init_data init_params = {
- 			.link = aconnector->dc_link,
- 			.sink_signal = SIGNAL_TYPE_VIRTUAL
- 	};
- 	const struct drm_edid *drm_edid;
- 	const struct edid *edid;
- 	struct i2c_adapter *ddc;
- 
- 	if (dc_link && dc_link->aux_mode)
- 		ddc = &aconnector->dm_dp_aux.aux.ddc;
- 	else
- 		ddc = &aconnector->i2c->base;
- 
- 	drm_edid = drm_edid_read_ddc(connector, ddc);
- 	drm_edid_connector_update(connector, drm_edid);
- 	if (!drm_edid) {
- 		drm_err(connector->dev, "No EDID found on connector: %s.\n", connector->name);
- 		return;
- 	}
- 
- 	if (connector->display_info.is_hdmi)
- 		init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
- 
- 	aconnector->drm_edid = drm_edid;
- 
- 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
- 	aconnector->dc_em_sink = dc_link_add_remote_sink(
- 		aconnector->dc_link,
- 		(uint8_t *)edid,
- 		(edid->extensions + 1) * EDID_LENGTH,
- 		&init_params);
- 
- 	if (aconnector->base.force == DRM_FORCE_ON) {
- 		aconnector->dc_sink = aconnector->dc_link->local_sink ?
- 		aconnector->dc_link->local_sink :
- 		aconnector->dc_em_sink;
- 		if (aconnector->dc_sink)
- 			dc_sink_retain(aconnector->dc_sink);
- 	}
- }
- 
- static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
- {
- 	struct dc_link *link = (struct dc_link *)aconnector->dc_link;
- 
- 	/*
- 	 * In case of headless boot with force on for DP managed connector
- 	 * Those settings have to be != 0 to get initial modeset
- 	 */
- 	if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) {
- 		link->verified_link_cap.lane_count = LANE_COUNT_FOUR;
- 		link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
- 	}
- 
- 	create_eml_sink(aconnector);
- }
- 
- static enum dc_status dm_validate_stream_and_context(struct dc *dc,
- 						struct dc_stream_state *stream)
- {
- 	enum dc_status dc_result = DC_ERROR_UNEXPECTED;
- 	struct dc_plane_state *dc_plane_state = NULL;
- 	struct dc_state *dc_state = NULL;
- 
- 	if (!stream)
- 		goto cleanup;
- 
- 	dc_plane_state = dc_create_plane_state(dc);
- 	if (!dc_plane_state)
- 		goto cleanup;
- 
- 	dc_state = dc_state_create(dc, NULL);
- 	if (!dc_state)
- 		goto cleanup;
- 
- 	/* populate stream to plane */
- 	dc_plane_state->src_rect.height  = stream->src.height;
- 	dc_plane_state->src_rect.width   = stream->src.width;
- 	dc_plane_state->dst_rect.height  = stream->src.height;
- 	dc_plane_state->dst_rect.width   = stream->src.width;
- 	dc_plane_state->clip_rect.height = stream->src.height;
- 	dc_plane_state->clip_rect.width  = stream->src.width;
- 	dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256;
- 	dc_plane_state->plane_size.surface_size.height = stream->src.height;
- 	dc_plane_state->plane_size.surface_size.width  = stream->src.width;
- 	dc_plane_state->plane_size.chroma_size.height  = stream->src.height;
- 	dc_plane_state->plane_size.chroma_size.width   = stream->src.width;
- 	dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
- 	dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
- 	dc_plane_state->rotation = ROTATION_ANGLE_0;
- 	dc_plane_state->is_tiling_rotated = false;
- 	dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL;
- 
- 	dc_result = dc_validate_stream(dc, stream);
- 	if (dc_result == DC_OK)
- 		dc_result = dc_validate_plane(dc, dc_plane_state);
- 
- 	if (dc_result == DC_OK)
- 		dc_result = dc_state_add_stream(dc, dc_state, stream);
- 
- 	if (dc_result == DC_OK && !dc_state_add_plane(
- 						dc,
- 						stream,
- 						dc_plane_state,
- 						dc_state))
- 		dc_result = DC_FAIL_ATTACH_SURFACES;
- 
- 	if (dc_result == DC_OK)
- 		dc_result = dc_validate_global_state(dc, dc_state, DC_VALIDATE_MODE_ONLY);
- 
- cleanup:
- 	if (dc_state)
- 		dc_state_release(dc_state);
- 
- 	if (dc_plane_state)
- 		dc_plane_state_release(dc_plane_state);
- 
- 	return dc_result;
- }
- 
- struct dc_stream_state *
- create_validate_stream_for_sink(struct drm_connector *connector,
- 				const struct drm_display_mode *drm_mode,
- 				const struct dm_connector_state *dm_state,
- 				const struct dc_stream_state *old_stream)
- {
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct dc_stream_state *stream;
- 	const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL;
- 	int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
- 	enum dc_status dc_result = DC_OK;
- 	uint8_t bpc_limit = 6;
- 
- 	if (!dm_state)
- 		return NULL;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if (aconnector &&
- 	    (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 	     aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL ||
- 	     aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
- 		bpc_limit = 8;
- 
- 	do {
- 		drm_dbg_kms(connector->dev, "Trying with %d bpc\n", requested_bpc);
- 		stream = create_stream_for_sink(connector, drm_mode,
- 						dm_state, old_stream,
- 						requested_bpc);
- 		if (stream == NULL) {
- 			drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n");
- 			break;
- 		}
- 
- 		dc_result = dc_validate_stream(adev->dm.dc, stream);
- 
- 		if (!aconnector) /* writeback connector */
- 			return stream;
- 
- 		if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- 			dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
- 
- 		if (dc_result == DC_OK)
- 			dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
- 
- 		if (dc_result != DC_OK) {
- 			drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
- 				      drm_mode->hdisplay,
- 				      drm_mode->vdisplay,
- 				      drm_mode->clock,
- 				      dc_pixel_encoding_to_str(stream->timing.pixel_encoding),
- 				      dc_color_depth_to_str(stream->timing.display_color_depth),
- 				      dc_status_to_str(dc_result));
- 
- 			dc_stream_release(stream);
- 			stream = NULL;
- 			requested_bpc -= 2; /* lower bpc to retry validation */
- 		}
- 
- 	} while (stream == NULL && requested_bpc >= bpc_limit);
- 
- 	switch (dc_result) {
- 	/*
- 	 * If we failed to validate DP bandwidth stream with the requested RGB color depth,
- 	 * we try to fallback and configure in order:
- 	 * YUV422 (8bpc, 6bpc)
- 	 * YUV420 (8bpc, 6bpc)
- 	 */
- 	case DC_FAIL_ENC_VALIDATE:
- 	case DC_EXCEED_DONGLE_CAP:
- 	case DC_NO_DP_LINK_BANDWIDTH:
- 		/* recursively entered twice and already tried both YUV422 and YUV420 */
- 		if (aconnector->force_yuv422_output && aconnector->force_yuv420_output)
- 			break;
- 		/* first failure; try YUV422 */
- 		if (!aconnector->force_yuv422_output) {
- 			drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV422\n",
- 				    __func__, __LINE__, dc_result);
- 			aconnector->force_yuv422_output = true;
- 		/* recursively entered and YUV422 failed, try YUV420 */
- 		} else if (!aconnector->force_yuv420_output) {
- 			drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV420\n",
- 				    __func__, __LINE__, dc_result);
- 			aconnector->force_yuv420_output = true;
- 		}
- 		stream = create_validate_stream_for_sink(connector, drm_mode,
- 							 dm_state, old_stream);
- 		aconnector->force_yuv422_output = false;
- 		aconnector->force_yuv420_output = false;
- 		break;
- 	case DC_OK:
- 		break;
- 	default:
- 		drm_dbg_kms(connector->dev, "%s:%d Unhandled validation failure %d\n",
- 			    __func__, __LINE__, dc_result);
- 		break;
- 	}
- 
- 	return stream;
- }
- 
- enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
- 				   const struct drm_display_mode *mode)
- {
- 	int result = MODE_ERROR;
- 	struct dc_sink *dc_sink;
- 	struct drm_display_mode *test_mode;
- 	/* TODO: Unhardcode stream count */
- 	struct dc_stream_state *stream;
- 	/* we always have an amdgpu_dm_connector here since we got
- 	 * here via the amdgpu_dm_connector_helper_funcs
- 	 */
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
- 			(mode->flags & DRM_MODE_FLAG_DBLSCAN))
- 		return result;
- 
- 	/*
- 	 * Only run this the first time mode_valid is called to initilialize
- 	 * EDID mgmt
- 	 */
- 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED &&
- 		!aconnector->dc_em_sink)
- 		handle_edid_mgmt(aconnector);
- 
- 	dc_sink = to_amdgpu_dm_connector(connector)->dc_sink;
- 
- 	if (dc_sink == NULL && aconnector->base.force != DRM_FORCE_ON_DIGITAL &&
- 				aconnector->base.force != DRM_FORCE_ON) {
- 		drm_err(connector->dev, "dc_sink is NULL!\n");
- 		goto fail;
- 	}
- 
- 	test_mode = drm_mode_duplicate(connector->dev, mode);
- 	if (!test_mode)
- 		goto fail;
- 
- 	drm_mode_set_crtcinfo(test_mode, 0);
- 
- 	stream = create_validate_stream_for_sink(connector, test_mode,
- 						 to_dm_connector_state(connector->state),
- 						 NULL);
- 	drm_mode_destroy(connector->dev, test_mode);
- 	if (stream) {
- 		dc_stream_release(stream);
- 		result = MODE_OK;
- 	}
- 
- fail:
- 	/* TODO: error handling*/
- 	return result;
- }
- 
- static int fill_hdr_info_packet(const struct drm_connector_state *state,
- 				struct dc_info_packet *out)
- {
- 	struct hdmi_drm_infoframe frame;
- 	unsigned char buf[30]; /* 26 + 4 */
- 	ssize_t len;
- 	int ret, i;
- 
- 	memset(out, 0, sizeof(*out));
- 
- 	if (!state->hdr_output_metadata)
- 		return 0;
- 
- 	ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, state);
- 	if (ret)
- 		return ret;
- 
- 	len = hdmi_drm_infoframe_pack_only(&frame, buf, sizeof(buf));
- 	if (len < 0)
- 		return (int)len;
- 
- 	/* Static metadata is a fixed 26 bytes + 4 byte header. */
- 	if (len != 30)
- 		return -EINVAL;
- 
- 	/* Prepare the infopacket for DC. */
- 	switch (state->connector->connector_type) {
- 	case DRM_MODE_CONNECTOR_HDMIA:
- 		out->hb0 = 0x87; /* type */
- 		out->hb1 = 0x01; /* version */
- 		out->hb2 = 0x1A; /* length */
- 		out->sb[0] = buf[3]; /* checksum */
- 		i = 1;
- 		break;
- 
- 	case DRM_MODE_CONNECTOR_DisplayPort:
- 	case DRM_MODE_CONNECTOR_eDP:
- 		out->hb0 = 0x00; /* sdp id, zero */
- 		out->hb1 = 0x87; /* type */
- 		out->hb2 = 0x1D; /* payload len - 1 */
- 		out->hb3 = (0x13 << 2); /* sdp version */
- 		out->sb[0] = 0x01; /* version */
- 		out->sb[1] = 0x1A; /* length */
- 		i = 2;
- 		break;
- 
- 	default:
- 		return -EINVAL;
- 	}
- 
- 	memcpy(&out->sb[i], &buf[4], 26);
- 	out->valid = true;
- 
- 	print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb,
- 		       sizeof(out->sb), false);
- 
- 	return 0;
- }
- 
- static int
- amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
- 				 struct drm_atomic_commit *state)
- {
- 	struct drm_connector_state *new_con_state =
- 		drm_atomic_get_new_connector_state(state, conn);
- 	struct drm_connector_state *old_con_state =
- 		drm_atomic_get_old_connector_state(state, conn);
- 	struct drm_crtc *crtc = new_con_state->crtc;
- 	struct drm_crtc_state *new_crtc_state;
- 	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
- 	int ret;
- 
- 	if (WARN_ON(unlikely(!old_con_state || !new_con_state)))
- 		return -EINVAL;
- 
- 	trace_amdgpu_dm_connector_atomic_check(new_con_state);
- 
- 	if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
- 		ret = drm_dp_mst_root_conn_atomic_check(new_con_state, &aconn->mst_mgr);
- 		if (ret < 0)
- 			return ret;
- 	}
- 
- 	if (!crtc)
- 		return 0;
- 
- 	if (new_con_state->privacy_screen_sw_state != old_con_state->privacy_screen_sw_state) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (new_con_state->colorspace != old_con_state->colorspace) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (new_con_state->content_type != old_con_state->content_type) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) {
- 		struct dc_info_packet hdr_infopacket;
- 
- 		ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket);
- 		if (ret)
- 			return ret;
- 
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		/*
- 		 * DC considers the stream backends changed if the
- 		 * static metadata changes. Forcing the modeset also
- 		 * gives a simple way for userspace to switch from
- 		 * 8bpc to 10bpc when setting the metadata to enter
- 		 * or exit HDR.
- 		 *
- 		 * Changing the static metadata after it's been
- 		 * set is permissible, however. So only force a
- 		 * modeset if we're entering or exiting HDR.
- 		 */
- 		new_crtc_state->mode_changed = new_crtc_state->mode_changed ||
- 			!old_con_state->hdr_output_metadata ||
- 			!new_con_state->hdr_output_metadata;
- 	}
- 
- 	return 0;
- }
- 
- static const struct drm_connector_helper_funcs
- amdgpu_dm_connector_helper_funcs = {
- 	/*
- 	 * If hotplugging a second bigger display in FB Con mode, bigger resolution
- 	 * modes will be filtered by drm_mode_validate_size(), and those modes
- 	 * are missing after user start lightdm. So we need to renew modes list.
- 	 * in get_modes call back, not just return the modes count
- 	 */
- 	.get_modes = get_modes,
- 	.mode_valid = amdgpu_dm_connector_mode_valid,
- 	.atomic_check = amdgpu_dm_connector_atomic_check,
- };
- 
- static void dm_encoder_helper_disable(struct drm_encoder *encoder)
- {
- 
- }
- 
- int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth)
- {
- 	switch (display_color_depth) {
- 	case COLOR_DEPTH_666:
- 		return 6;
- 	case COLOR_DEPTH_888:
- 		return 8;
- 	case COLOR_DEPTH_101010:
- 		return 10;
- 	case COLOR_DEPTH_121212:
- 		return 12;
- 	case COLOR_DEPTH_141414:
- 		return 14;
- 	case COLOR_DEPTH_161616:
- 		return 16;
- 	default:
- 		break;
- 	}
- 	return 0;
- }
- 
- static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
- 					  struct drm_crtc_state *crtc_state,
- 					  struct drm_connector_state *conn_state)
- {
- 	struct drm_atomic_commit *state = crtc_state->state;
- 	struct drm_connector *connector = conn_state->connector;
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state);
- 	const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
- 	struct drm_dp_mst_topology_mgr *mst_mgr;
- 	struct drm_dp_mst_port *mst_port;
- 	struct drm_dp_mst_topology_state *mst_state;
- 	enum dc_color_depth color_depth;
- 	int clock, bpp = 0;
- 	bool is_y420 = false;
- 
- 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
- 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
- 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 		struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 		enum drm_mode_status result;
- 
- 		result = drm_crtc_helper_mode_valid_fixed(encoder->crtc, adjusted_mode, native_mode);
- 		if (result != MODE_OK && dm_new_connector_state->scaling == RMX_OFF) {
- 			drm_dbg_driver(encoder->dev,
- 				       "mode %dx%d@%dHz is not native, enabling scaling\n",
- 				       adjusted_mode->hdisplay, adjusted_mode->vdisplay,
- 				       drm_mode_vrefresh(adjusted_mode));
- 			dm_new_connector_state->scaling = RMX_ASPECT;
- 		}
- 		return 0;
- 	}
- 
- 	if (!aconnector->mst_output_port)
- 		return 0;
- 
- 	mst_port = aconnector->mst_output_port;
- 	mst_mgr = &aconnector->mst_root->mst_mgr;
- 
- 	if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
- 		return 0;
- 
- 	mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr);
- 	if (IS_ERR(mst_state))
- 		return PTR_ERR(mst_state);
- 
- 	mst_state->pbn_div.full = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link);
- 
- 	if (!state->duplicated) {
- 		int max_bpc = conn_state->max_requested_bpc;
- 
- 		is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
- 			  aconnector->force_yuv420_output;
- 		color_depth = convert_color_depth_from_display_info(connector,
- 								    is_y420,
- 								    max_bpc);
- 		bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
- 		clock = adjusted_mode->clock;
- 		dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4);
- 	}
- 
- 	dm_new_connector_state->vcpi_slots =
- 		drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port,
- 					      dm_new_connector_state->pbn);
- 	if (dm_new_connector_state->vcpi_slots < 0) {
- 		drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
- 		return dm_new_connector_state->vcpi_slots;
- 	}
- 	return 0;
- }
- 
- const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
- 	.disable = dm_encoder_helper_disable,
- 	.atomic_check = dm_encoder_helper_atomic_check
- };
- 
  static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state,
  					    struct dc_state *dc_state,
  					    struct dsc_mst_fairness_vars *vars)
@@@ -8914,753 -3326,6 +3331,6 @@@
  	return 0;
  }
  
- static int to_drm_connector_type(enum signal_type st, uint32_t connector_id)
- {
- 	switch (st) {
- 	case SIGNAL_TYPE_HDMI_TYPE_A:
- 		return DRM_MODE_CONNECTOR_HDMIA;
- 	case SIGNAL_TYPE_EDP:
- 		return DRM_MODE_CONNECTOR_eDP;
- 	case SIGNAL_TYPE_LVDS:
- 		return DRM_MODE_CONNECTOR_LVDS;
- 	case SIGNAL_TYPE_RGB:
- 		return DRM_MODE_CONNECTOR_VGA;
- 	case SIGNAL_TYPE_DISPLAY_PORT:
- 	case SIGNAL_TYPE_DISPLAY_PORT_MST:
- 		/* External DP bridges have a different connector type. */
- 		if (connector_id == CONNECTOR_ID_VGA)
- 			return DRM_MODE_CONNECTOR_VGA;
- 		else if (connector_id == CONNECTOR_ID_LVDS)
- 			return DRM_MODE_CONNECTOR_LVDS;
- 
- 		return DRM_MODE_CONNECTOR_DisplayPort;
- 	case SIGNAL_TYPE_DVI_DUAL_LINK:
- 	case SIGNAL_TYPE_DVI_SINGLE_LINK:
- 		if (connector_id == CONNECTOR_ID_SINGLE_LINK_DVII ||
- 			connector_id == CONNECTOR_ID_DUAL_LINK_DVII)
- 			return DRM_MODE_CONNECTOR_DVII;
- 
- 		return DRM_MODE_CONNECTOR_DVID;
- 	case SIGNAL_TYPE_VIRTUAL:
- 		return DRM_MODE_CONNECTOR_VIRTUAL;
- 
- 	default:
- 		return DRM_MODE_CONNECTOR_Unknown;
- 	}
- }
- 
- static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 
- 	/* There is only one encoder per connector */
- 	drm_connector_for_each_possible_encoder(connector, encoder)
- 		return encoder;
- 
- 	return NULL;
- }
- 
- static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 	struct amdgpu_encoder *amdgpu_encoder;
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 
- 	if (encoder == NULL)
- 		return;
- 
- 	amdgpu_encoder = to_amdgpu_encoder(encoder);
- 
- 	amdgpu_encoder->native_mode.clock = 0;
- 
- 	if (!list_empty(&connector->probed_modes)) {
- 		struct drm_display_mode *preferred_mode = NULL;
- 
- 		list_for_each_entry(preferred_mode,
- 				    &connector->probed_modes,
- 				    head) {
- 			if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED)
- 				amdgpu_encoder->native_mode = *preferred_mode;
- 
- 			break;
- 		}
- 
- 	}
- }
- 
- static struct drm_display_mode *
- amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
- 			     const char *name,
- 			     int hdisplay, int vdisplay)
- {
- 	struct drm_device *dev = encoder->dev;
- 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 	struct drm_display_mode *mode = NULL;
- 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 
- 	mode = drm_mode_duplicate(dev, native_mode);
- 
- 	if (mode == NULL)
- 		return NULL;
- 
- 	mode->hdisplay = hdisplay;
- 	mode->vdisplay = vdisplay;
- 	mode->type &= ~DRM_MODE_TYPE_PREFERRED;
- 	strscpy(mode->name, name, DRM_DISPLAY_MODE_LEN);
- 
- 	return mode;
- 
- }
- 
- static const struct amdgpu_dm_mode_size {
- 	char name[DRM_DISPLAY_MODE_LEN];
- 	int w;
- 	int h;
- } common_modes[] = {
- 	{  "640x480",  640,  480},
- 	{  "800x600",  800,  600},
- 	{ "1024x768", 1024,  768},
- 	{ "1280x720", 1280,  720},
- 	{ "1280x800", 1280,  800},
- 	{"1280x1024", 1280, 1024},
- 	{ "1440x900", 1440,  900},
- 	{"1680x1050", 1680, 1050},
- 	{"1600x1200", 1600, 1200},
- 	{"1920x1080", 1920, 1080},
- 	{"1920x1200", 1920, 1200}
- };
- 
- static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
- 						 struct drm_connector *connector)
- {
- 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 	struct drm_display_mode *mode = NULL;
- 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 				to_amdgpu_dm_connector(connector);
- 	int i;
- 	int n;
- 
- 	if ((connector->connector_type != DRM_MODE_CONNECTOR_eDP) &&
- 	    (connector->connector_type != DRM_MODE_CONNECTOR_LVDS))
- 		return;
- 
- 	n = ARRAY_SIZE(common_modes);
- 
- 	for (i = 0; i < n; i++) {
- 		struct drm_display_mode *curmode = NULL;
- 		bool mode_existed = false;
- 
- 		if (common_modes[i].w > native_mode->hdisplay ||
- 		    common_modes[i].h > native_mode->vdisplay ||
- 		   (common_modes[i].w == native_mode->hdisplay &&
- 		    common_modes[i].h == native_mode->vdisplay))
- 			continue;
- 
- 		list_for_each_entry(curmode, &connector->probed_modes, head) {
- 			if (common_modes[i].w == curmode->hdisplay &&
- 			    common_modes[i].h == curmode->vdisplay) {
- 				mode_existed = true;
- 				break;
- 			}
- 		}
- 
- 		if (mode_existed)
- 			continue;
- 
- 		mode = amdgpu_dm_create_common_mode(encoder,
- 				common_modes[i].name, common_modes[i].w,
- 				common_modes[i].h);
- 		if (!mode)
- 			continue;
- 
- 		drm_mode_probed_add(connector, mode);
- 		amdgpu_dm_connector->num_modes++;
- 	}
- }
- 
- static void amdgpu_set_panel_orientation(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 	struct amdgpu_encoder *amdgpu_encoder;
- 	const struct drm_display_mode *native_mode;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
- 	    connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
- 		return;
- 
- 	mutex_lock(&connector->dev->mode_config.mutex);
- 	amdgpu_dm_connector_get_modes(connector);
- 	mutex_unlock(&connector->dev->mode_config.mutex);
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 	if (!encoder)
- 		return;
- 
- 	amdgpu_encoder = to_amdgpu_encoder(encoder);
- 
- 	native_mode = &amdgpu_encoder->native_mode;
- 	if (native_mode->hdisplay == 0 || native_mode->vdisplay == 0)
- 		return;
- 
- 	drm_connector_set_panel_orientation_with_quirk(connector,
- 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
- 						       native_mode->hdisplay,
- 						       native_mode->vdisplay);
- }
- 
- static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
- 					      const struct drm_edid *drm_edid)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 
- 	if (drm_edid) {
- 		/* empty probed_modes */
- 		INIT_LIST_HEAD(&connector->probed_modes);
- 		amdgpu_dm_connector->num_modes =
- 				drm_edid_connector_add_modes(connector);
- 
- 		/* sorting the probed modes before calling function
- 		 * amdgpu_dm_get_native_mode() since EDID can have
- 		 * more than one preferred mode. The modes that are
- 		 * later in the probed mode list could be of higher
- 		 * and preferred resolution. For example, 3840x2160
- 		 * resolution in base EDID preferred timing and 4096x2160
- 		 * preferred resolution in DID extension block later.
- 		 */
- 		drm_mode_sort(&connector->probed_modes);
- 		amdgpu_dm_get_native_mode(connector);
- 
- 		/* Freesync capabilities are reset by calling
- 		 * drm_edid_connector_add_modes() and need to be
- 		 * restored here.
- 		 */
- 		amdgpu_dm_update_freesync_caps(connector, drm_edid, false);
- 	} else {
- 		amdgpu_dm_connector->num_modes = 0;
- 	}
- }
- 
- static bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector,
- 			      struct drm_display_mode *mode)
- {
- 	struct drm_display_mode *m;
- 
- 	list_for_each_entry(m, &aconnector->base.probed_modes, head) {
- 		if (drm_mode_equal(m, mode))
- 			return true;
- 	}
- 
- 	return false;
- }
- 
- static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
- {
- 	const struct drm_display_mode *m;
- 	struct drm_display_mode *new_mode;
- 	uint i;
- 	u32 new_modes_count = 0;
- 
- 	/* Standard FPS values
- 	 *
- 	 * 23.976       - TV/NTSC
- 	 * 24           - Cinema
- 	 * 25           - TV/PAL
- 	 * 29.97        - TV/NTSC
- 	 * 30           - TV/NTSC
- 	 * 48           - Cinema HFR
- 	 * 50           - TV/PAL
- 	 * 60           - Commonly used
- 	 * 48,72,96,120 - Multiples of 24
- 	 */
- 	static const u32 common_rates[] = {
- 		23976, 24000, 25000, 29970, 30000,
- 		48000, 50000, 60000, 72000, 96000, 120000
- 	};
- 
- 	/*
- 	 * Find mode with highest refresh rate with the same resolution
- 	 * as the preferred mode. Some monitors report a preferred mode
- 	 * with lower resolution than the highest refresh rate supported.
- 	 */
- 
- 	m = get_highest_refresh_rate_mode(aconnector, true);
- 	if (!m)
- 		return 0;
- 
- 	for (i = 0; i < ARRAY_SIZE(common_rates); i++) {
- 		u64 target_vtotal, target_vtotal_diff;
- 		u64 num, den;
- 
- 		if (drm_mode_vrefresh(m) * 1000 < common_rates[i])
- 			continue;
- 
- 		if (common_rates[i] < aconnector->min_vfreq * 1000 ||
- 		    common_rates[i] > aconnector->max_vfreq * 1000)
- 			continue;
- 
- 		num = (unsigned long long)m->clock * 1000 * 1000;
- 		den = common_rates[i] * (unsigned long long)m->htotal;
- 		target_vtotal = div_u64(num, den);
- 		target_vtotal_diff = target_vtotal - m->vtotal;
- 
- 		/* Check for illegal modes */
- 		if (m->vsync_start + target_vtotal_diff < m->vdisplay ||
- 		    m->vsync_end + target_vtotal_diff < m->vsync_start ||
- 		    m->vtotal + target_vtotal_diff < m->vsync_end)
- 			continue;
- 
- 		new_mode = drm_mode_duplicate(aconnector->base.dev, m);
- 		if (!new_mode)
- 			goto out;
- 
- 		new_mode->vtotal += (u16)target_vtotal_diff;
- 		new_mode->vsync_start += (u16)target_vtotal_diff;
- 		new_mode->vsync_end += (u16)target_vtotal_diff;
- 		new_mode->type &= ~DRM_MODE_TYPE_PREFERRED;
- 		new_mode->type |= DRM_MODE_TYPE_DRIVER;
- 
- 		if (!is_duplicate_mode(aconnector, new_mode)) {
- 			drm_mode_probed_add(&aconnector->base, new_mode);
- 			new_modes_count += 1;
- 		} else
- 			drm_mode_destroy(aconnector->base.dev, new_mode);
- 	}
-  out:
- 	return new_modes_count;
- }
- 
- static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
- 						   const struct drm_edid *drm_edid)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 		to_amdgpu_dm_connector(connector);
- 
- 	if (!(amdgpu_freesync_vid_mode && drm_edid))
- 		return;
- 
- 	if (!amdgpu_dm_connector->dc_sink || !amdgpu_dm_connector->dc_link)
- 		return;
- 
- 	if (!dc_supports_vrr(amdgpu_dm_connector->dc_sink->ctx->dce_version))
- 		return;
- 
- 	if (dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id) &&
- 	    amdgpu_dm_connector->dc_sink->edid_caps.analog)
- 		return;
- 
- 	if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 		amdgpu_dm_connector->num_modes +=
- 			add_fs_modes(amdgpu_dm_connector);
- }
- 
- static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 	struct dc_link *dc_link = amdgpu_dm_connector->dc_link;
- 	struct drm_encoder *encoder;
- 	const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid;
- 	struct dc_link_settings *verified_link_cap = &dc_link->verified_link_cap;
- 	const struct dc *dc = dc_link->dc;
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 
- 	if (!drm_edid) {
- 		amdgpu_dm_connector->num_modes =
- 				drm_add_modes_noedid(connector, 640, 480);
- 		if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING)
- 			amdgpu_dm_connector->num_modes +=
- 				drm_add_modes_noedid(connector, 1920, 1080);
- 
- 		if (amdgpu_dm_connector->dc_sink &&
- 		    amdgpu_dm_connector->dc_sink->edid_caps.analog &&
- 		    dc_connector_supports_analog(dc_link->link_id.id)) {
- 			/* Analog monitor connected by DAC load detection.
- 			 * Add common modes. It will be up to the user to select one that works.
- 			 */
- 			for (int i = 0; i < ARRAY_SIZE(common_modes); i++)
- 				amdgpu_dm_connector->num_modes += drm_add_modes_noedid(
- 					connector, common_modes[i].w, common_modes[i].h);
- 		}
- 	} else {
- 		amdgpu_dm_connector_ddc_get_modes(connector, drm_edid);
- 		if (encoder)
- 			amdgpu_dm_connector_add_common_modes(encoder, connector);
- 		amdgpu_dm_connector_add_freesync_modes(connector, drm_edid);
- 	}
- 	amdgpu_dm_fbc_init(connector);
- 
- 	return amdgpu_dm_connector->num_modes;
- }
- 
- static const u32 supported_colorspaces =
- 	BIT(DRM_MODE_COLORIMETRY_BT709_YCC) |
- 	BIT(DRM_MODE_COLORIMETRY_OPRGB) |
- 	BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) |
- 	BIT(DRM_MODE_COLORIMETRY_BT2020_YCC);
- 
- void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
- 				     struct amdgpu_dm_connector *aconnector,
- 				     int connector_type,
- 				     struct dc_link *link,
- 				     int link_index)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dm->ddev);
- 
- 	/*
- 	 * Some of the properties below require access to state, like bpc.
- 	 * Allocate some default initial connector state with our reset helper.
- 	 */
- 	if (aconnector->base.funcs->reset)
- 		aconnector->base.funcs->reset(&aconnector->base);
- 
- 	aconnector->connector_id = link_index;
- 	aconnector->bl_idx = -1;
- 	aconnector->dc_link = link;
- 	aconnector->base.interlace_allowed = false;
- 	aconnector->base.doublescan_allowed = false;
- 	aconnector->base.stereo_allowed = false;
- 	aconnector->base.dpms = DRM_MODE_DPMS_OFF;
- 	aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
- 	aconnector->audio_inst = -1;
- 	aconnector->pack_sdp_v1_3 = false;
- 	aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE;
- 	memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info));
- 	mutex_init(&aconnector->hpd_lock);
- 	mutex_init(&aconnector->handle_mst_msg_ready);
- 
- 	/*
- 	 * If HDMI HPD debounce delay is set, use the minimum between selected
- 	 * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS
- 	 */
- 	if (amdgpu_hdmi_hpd_debounce_delay_ms) {
- 		aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms,
- 							     AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS);
- 		INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work);
- 		aconnector->hdmi_prev_sink = NULL;
- 	} else {
- 		aconnector->hdmi_hpd_debounce_delay_ms = 0;
- 	}
- 
- 	/*
- 	 * configure support HPD hot plug connector_>polled default value is 0
- 	 * which means HPD hot plug not supported
- 	 */
- 	switch (connector_type) {
- 	case DRM_MODE_CONNECTOR_HDMIA:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		aconnector->base.ycbcr_420_allowed =
- 			link->link_enc->features.hdmi_ycbcr420_supported ? true : false;
- 		break;
- 	case DRM_MODE_CONNECTOR_DisplayPort:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		link->link_enc = link_enc_cfg_get_link_enc(link);
- 		ASSERT(link->link_enc);
- 		if (link->link_enc)
- 			aconnector->base.ycbcr_420_allowed =
- 			link->link_enc->features.dp_ycbcr420_supported ? true : false;
- 		break;
- 	case DRM_MODE_CONNECTOR_DVID:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		break;
- 	case DRM_MODE_CONNECTOR_DVII:
- 	case DRM_MODE_CONNECTOR_VGA:
- 		aconnector->base.polled =
- 			DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	drm_object_attach_property(&aconnector->base.base,
- 				dm->ddev->mode_config.scaling_mode_property,
- 				DRM_MODE_SCALE_NONE);
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA
- 		|| (connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root))
- 		drm_connector_attach_broadcast_rgb_property(&aconnector->base);
- 
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_property,
- 				UNDERSCAN_OFF);
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_hborder_property,
- 				0);
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_vborder_property,
- 				0);
- 
- 	if (!aconnector->mst_root)
- 		drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
- 
- 	aconnector->base.state->max_bpc = 16;
- 	aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc;
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
- 		/* Content Type is currently only implemented for HDMI. */
- 		drm_connector_attach_content_type_property(&aconnector->base);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
- 		if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces))
- 			drm_connector_attach_colorspace_property(&aconnector->base);
- 	} else if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root) ||
- 		   connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces))
- 			drm_connector_attach_colorspace_property(&aconnector->base);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- 	    connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
- 	    connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
- 
- 		if (!aconnector->mst_root)
- 			drm_connector_attach_vrr_capable_property(&aconnector->base);
- 
- 		if (adev->dm.hdcp_workqueue)
- 			drm_connector_attach_content_protection_property(&aconnector->base, true);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		struct drm_privacy_screen *privacy_screen;
- 
- 		drm_connector_attach_panel_type_property(&aconnector->base);
- 
- 		privacy_screen = drm_privacy_screen_get(adev_to_drm(adev)->dev, NULL);
- 		if (!IS_ERR(privacy_screen)) {
- 			drm_connector_attach_privacy_screen_provider(&aconnector->base,
- 								     privacy_screen);
- 		} else if (PTR_ERR(privacy_screen) != -ENODEV) {
- 			drm_warn(adev_to_drm(adev), "Error getting privacy-screen\n");
- 		}
- 	}
- }
- 
- static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
- 			      struct i2c_msg *msgs, int num)
- {
- 	struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
- 	struct ddc_service *ddc_service = i2c->ddc_service;
- 	struct i2c_command cmd;
- 	int i;
- 	int result = -EIO;
- 
- 	if (!ddc_service->ddc_pin)
- 		return result;
- 
- 	cmd.payloads = kzalloc_objs(struct i2c_payload, num);
- 
- 	if (!cmd.payloads)
- 		return result;
- 
- 	cmd.number_of_payloads = num;
- 	cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
- 	cmd.speed = 100;
- 
- 	for (i = 0; i < num; i++) {
- 		cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD);
- 		cmd.payloads[i].address = msgs[i].addr;
- 		cmd.payloads[i].length = msgs[i].len;
- 		cmd.payloads[i].data = msgs[i].buf;
- 	}
- 
- 	if (i2c->oem) {
- 		if (dc_submit_i2c_oem(
- 			    ddc_service->ctx->dc,
- 			    &cmd))
- 			result = num;
- 	} else {
- 		if (dc_submit_i2c(
- 			    ddc_service->ctx->dc,
- 			    ddc_service->link->link_index,
- 			    &cmd))
- 			result = num;
- 	}
- 
- 	kfree(cmd.payloads);
- 	return result;
- }
- 
- static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
- {
- 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
- }
- 
- static const struct i2c_algorithm amdgpu_dm_i2c_algo = {
- 	.master_xfer = amdgpu_dm_i2c_xfer,
- 	.functionality = amdgpu_dm_i2c_func,
- };
- 
- static struct amdgpu_i2c_adapter *
- create_i2c(struct ddc_service *ddc_service, bool oem)
- {
- 	struct amdgpu_device *adev = ddc_service->ctx->driver_context;
- 	struct amdgpu_i2c_adapter *i2c;
- 
- 	i2c = kzalloc_obj(struct amdgpu_i2c_adapter);
- 	if (!i2c)
- 		return NULL;
- 	i2c->base.owner = THIS_MODULE;
- 	i2c->base.dev.parent = &adev->pdev->dev;
- 	i2c->base.algo = &amdgpu_dm_i2c_algo;
- 	if (oem)
- 		snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c OEM bus");
- 	else
- 		snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d",
- 			 ddc_service->link->link_index);
- 	i2c_set_adapdata(&i2c->base, i2c);
- 	i2c->ddc_service = ddc_service;
- 	i2c->oem = oem;
- 
- 	return i2c;
- }
- 
- int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
- {
- 	struct cec_connector_info conn_info;
- 	struct drm_device *ddev = aconnector->base.dev;
- 	struct device *hdmi_dev = ddev->dev;
- 
- 	if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) {
- 		drm_info(ddev, "HDMI-CEC feature masked\n");
- 		return -EINVAL;
- 	}
- 
- 	cec_fill_conn_info_from_drm(&conn_info, &aconnector->base);
- 	aconnector->notifier =
- 		cec_notifier_conn_register(hdmi_dev, NULL, &conn_info);
- 	if (!aconnector->notifier) {
- 		drm_err(ddev, "Failed to create cec notifier\n");
- 		return -ENOMEM;
- 	}
- 
- 	return 0;
- }
- 
- /*
-  * Note: this function assumes that dc_link_detect() was called for the
-  * dc_link which will be represented by this aconnector.
-  */
- static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
- 				    struct amdgpu_dm_connector *aconnector,
- 				    u32 link_index,
- 				    struct amdgpu_encoder *aencoder)
- {
- 	int res = 0;
- 	int connector_type;
- 	struct dc *dc = dm->dc;
- 	struct dc_link *link = dc_get_link_at_index(dc, link_index);
- 	struct amdgpu_i2c_adapter *i2c;
- 
- 	/* Not needed for writeback connector */
- 	link->priv = aconnector;
- 
- 
- 	i2c = create_i2c(link->ddc, false);
- 	if (!i2c) {
- 		drm_err(adev_to_drm(dm->adev), "Failed to create i2c adapter data\n");
- 		return -ENOMEM;
- 	}
- 
- 	aconnector->i2c = i2c;
- 	res = devm_i2c_add_adapter(dm->adev->dev, &i2c->base);
- 
- 	if (res) {
- 		drm_err(adev_to_drm(dm->adev), "Failed to register hw i2c %d\n", link->link_index);
- 		goto out_free;
- 	}
- 
- 	connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id);
- 
- 	res = drm_connector_init_with_ddc(
- 			dm->ddev,
- 			&aconnector->base,
- 			&amdgpu_dm_connector_funcs,
- 			connector_type,
- 			&i2c->base);
- 
- 	if (res) {
- 		drm_err(adev_to_drm(dm->adev), "connector_init failed\n");
- 		aconnector->connector_id = -1;
- 		goto out_free;
- 	}
- 
- 	drm_connector_helper_add(
- 			&aconnector->base,
- 			&amdgpu_dm_connector_helper_funcs);
- 
- 	amdgpu_dm_connector_init_helper(
- 		dm,
- 		aconnector,
- 		connector_type,
- 		link,
- 		link_index);
- 
- 	drm_connector_attach_encoder(
- 		&aconnector->base, &aencoder->base);
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- 	    connector_type == DRM_MODE_CONNECTOR_HDMIB)
- 		amdgpu_dm_initialize_hdmi_connector(aconnector);
- 
- 	if (dc_is_dp_signal(link->connector_signal))
- 		amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index);
- 
- out_free:
- 	if (res) {
- 		kfree(i2c);
- 		aconnector->i2c = NULL;
- 	}
- 	return res;
- }
- 
- int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev)
- {
- 	switch (adev->mode_info.num_crtc) {
- 	case 1:
- 		return 0x1;
- 	case 2:
- 		return 0x3;
- 	case 3:
- 		return 0x7;
- 	case 4:
- 		return 0xf;
- 	case 5:
- 		return 0x1f;
- 	case 6:
- 	default:
- 		return 0x3f;
- 	}
- }
- 
- static int amdgpu_dm_encoder_init(struct drm_device *dev,
- 				  struct amdgpu_encoder *aencoder,
- 				  uint32_t link_index)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 
- 	int res = drm_encoder_init(dev,
- 				   &aencoder->base,
- 				   &amdgpu_dm_encoder_funcs,
- 				   DRM_MODE_ENCODER_TMDS,
- 				   NULL);
- 
- 	aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev);
- 
- 	if (!res)
- 		aencoder->encoder_id = link_index;
- 	else
- 		aencoder->encoder_id = -1;
- 
- 	drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs);
- 
- 	return res;
- }
- 
  static void manage_dm_interrupts(struct amdgpu_device *adev,
  				 struct amdgpu_crtc *acrtc,
  				 struct dm_crtc_state *acrtc_state)
@@@ -9760,7 -3425,7 +3430,7 @@@ static void dm_update_pflip_irq_state(s
  	amdgpu_irq_update(adev, &adev->pageflip_irq, irq_type);
  }
  
- static bool
+ STATIC_IFN_KUNIT bool
  is_scaling_state_different(const struct dm_connector_state *dm_state,
  			   const struct dm_connector_state *old_dm_state)
  {
@@@ -9777,13 -3442,15 +3447,15 @@@
  		return true;
  	return false;
  }
+ EXPORT_IF_KUNIT(is_scaling_state_different);
  
- static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
- 					    struct drm_crtc_state *old_crtc_state,
- 					    struct drm_connector_state *new_conn_state,
- 					    struct drm_connector_state *old_conn_state,
- 					    const struct drm_connector *connector,
- 					    struct hdcp_workqueue *hdcp_w)
+ STATIC_IFN_KUNIT bool
+ is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+ 				struct drm_crtc_state *old_crtc_state,
+ 				struct drm_connector_state *new_conn_state,
+ 				struct drm_connector_state *old_conn_state,
+ 				const struct drm_connector *connector,
+ 				struct hdcp_workqueue *hdcp_w)
  {
  	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
  	struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
@@@ -9897,6 -3564,7 +3569,7 @@@
  	pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
  	return false;
  }
+ EXPORT_IF_KUNIT(is_content_protection_different);
  
  static void remove_stream(struct amdgpu_device *adev,
  			  struct amdgpu_crtc *acrtc,
@@@ -9908,213 -3576,6 +3581,6 @@@
  	acrtc->enabled = false;
  }
  
- static void update_freesync_state_on_stream(
- 	struct amdgpu_display_manager *dm,
- 	struct dm_crtc_state *new_crtc_state,
- 	struct dc_stream_state *new_stream,
- 	struct dc_plane_state *surface,
- 	u32 flip_timestamp_in_us)
- {
- 	struct mod_vrr_params vrr_params;
- 	struct dc_info_packet vrr_infopacket = {0};
- 	struct amdgpu_device *adev = dm->adev;
- 	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
- 	unsigned long flags;
- 	bool pack_sdp_v1_3 = false;
- 	struct amdgpu_dm_connector *aconn;
- 	enum vrr_packet_type packet_type = PACKET_TYPE_VRR;
- 
- 	if (!new_stream)
- 		return;
- 
- 	/*
- 	 * TODO: Determine why min/max totals and vrefresh can be 0 here.
- 	 * For now it's sufficient to just guard against these conditions.
- 	 */
- 
- 	if (!new_stream->timing.h_total || !new_stream->timing.v_total)
- 		return;
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 	vrr_params = acrtc->dm_irq_params.vrr_params;
- 
- 	if (surface) {
- 		mod_freesync_handle_preflip(
- 			dm->freesync_module,
- 			surface,
- 			new_stream,
- 			flip_timestamp_in_us,
- 			&vrr_params);
- 
- 		if (adev->family < AMDGPU_FAMILY_AI &&
- 		    amdgpu_dm_crtc_vrr_active(new_crtc_state)) {
- 			mod_freesync_handle_v_update(dm->freesync_module,
- 						     new_stream, &vrr_params);
- 
- 			/* Need to call this before the frame ends. */
- 			dc_stream_adjust_vmin_vmax(dm->dc,
- 						   new_crtc_state->stream,
- 						   &vrr_params.adjust);
- 		}
- 	}
- 
- 	aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
- 
- 	if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) {
- 		pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
- 
- 		if (aconn->vsdb_info.amd_vsdb_version == 1)
- 			packet_type = PACKET_TYPE_FS_V1;
- 		else if (aconn->vsdb_info.amd_vsdb_version == 2)
- 			packet_type = PACKET_TYPE_FS_V2;
- 		else if (aconn->vsdb_info.amd_vsdb_version == 3)
- 			packet_type = PACKET_TYPE_FS_V3;
- 
- 		mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL,
- 					&new_stream->adaptive_sync_infopacket);
- 	}
- 
- 	mod_freesync_build_vrr_infopacket(
- 		dm->freesync_module,
- 		new_stream,
- 		&vrr_params,
- 		packet_type,
- 		TRANSFER_FUNC_UNKNOWN,
- 		&vrr_infopacket,
- 		pack_sdp_v1_3);
- 
- 	new_crtc_state->freesync_vrr_info_changed |=
- 		(memcmp(&new_crtc_state->vrr_infopacket,
- 			&vrr_infopacket,
- 			sizeof(vrr_infopacket)) != 0);
- 
- 	acrtc->dm_irq_params.vrr_params = vrr_params;
- 	new_crtc_state->vrr_infopacket = vrr_infopacket;
- 
- 	new_stream->vrr_infopacket = vrr_infopacket;
- 	new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
- 
- 	if (new_crtc_state->freesync_vrr_info_changed)
- 		drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
- 			      new_crtc_state->base.crtc->base.id,
- 			      (int)new_crtc_state->base.vrr_enabled,
- 			      (int)vrr_params.state);
- 
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- }
- 
- static void update_stream_irq_parameters(
- 	struct amdgpu_display_manager *dm,
- 	struct dm_crtc_state *new_crtc_state)
- {
- 	struct dc_stream_state *new_stream = new_crtc_state->stream;
- 	struct mod_vrr_params vrr_params;
- 	struct mod_freesync_config config = new_crtc_state->freesync_config;
- 	struct amdgpu_device *adev = dm->adev;
- 	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
- 	unsigned long flags;
- 
- 	if (!new_stream)
- 		return;
- 
- 	/*
- 	 * TODO: Determine why min/max totals and vrefresh can be 0 here.
- 	 * For now it's sufficient to just guard against these conditions.
- 	 */
- 	if (!new_stream->timing.h_total || !new_stream->timing.v_total)
- 		return;
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 	vrr_params = acrtc->dm_irq_params.vrr_params;
- 
- 	if (new_crtc_state->vrr_supported &&
- 	    config.min_refresh_in_uhz &&
- 	    config.max_refresh_in_uhz) {
- 		/*
- 		 * if freesync compatible mode was set, config.state will be set
- 		 * in atomic check
- 		 */
- 		if (config.state == VRR_STATE_ACTIVE_FIXED && config.fixed_refresh_in_uhz &&
- 		    (!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) ||
- 		     new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)) {
- 			vrr_params.max_refresh_in_uhz = config.max_refresh_in_uhz;
- 			vrr_params.min_refresh_in_uhz = config.min_refresh_in_uhz;
- 			vrr_params.fixed_refresh_in_uhz = config.fixed_refresh_in_uhz;
- 			vrr_params.state = VRR_STATE_ACTIVE_FIXED;
- 		} else {
- 			config.state = new_crtc_state->base.vrr_enabled ?
- 						     VRR_STATE_ACTIVE_VARIABLE :
- 						     VRR_STATE_INACTIVE;
- 		}
- 	} else {
- 		config.state = VRR_STATE_UNSUPPORTED;
- 	}
- 
- 	mod_freesync_build_vrr_params(dm->freesync_module,
- 				      new_stream,
- 				      &config, &vrr_params);
- 
- 	new_crtc_state->freesync_config = config;
- 	/* Copy state for access from DM IRQ handler */
- 	acrtc->dm_irq_params.freesync_config = config;
- 	acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes;
- 	acrtc->dm_irq_params.vrr_params = vrr_params;
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- }
- 
- static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
- 					    struct dm_crtc_state *old_state,
- 					    struct dm_crtc_state *new_state)
- {
- 	struct amdgpu_device *adev = drm_to_adev(new_state->base.crtc->dev);
- 	bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
- 	bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state);
- 
- 	/* Only DCE gates vupdate on VRR, keep it enabled for DCN */
- 	bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0;
- 
- 	if (!old_vrr_active && new_vrr_active) {
- 		/* Transition VRR inactive -> active:
- 		 * While VRR is active, we must not disable vblank irq, as a
- 		 * reenable after disable would compute bogus vblank/pflip
- 		 * timestamps if it likely happened inside display front-porch.
- 		 *
- 		 * We also need vupdate irq for the actual core vblank handling
- 		 * at end of vblank.
- 		 */
- 		if (vrr_gates_vupdate)
- 			WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0);
- 		WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0);
- 		drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n",
- 				 __func__, new_state->base.crtc->base.id);
- 
- 		scoped_guard(mutex, &dm->dc_lock) {
- 			dc_exit_ips_for_hw_access(dm->dc);
- 			amdgpu_dm_psr_set_event(dm, new_state->stream, true,
- 				psr_event_vrr_transition, true);
- 			amdgpu_dm_replay_set_event(dm, new_state->stream, true,
- 				replay_event_vrr, true);
- 		}
- 	} else if (old_vrr_active && !new_vrr_active) {
- 		/* Transition VRR active -> inactive:
- 		 * Allow vblank irq disable again for fixed refresh rate.
- 		 */
- 		if (vrr_gates_vupdate)
- 			WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0);
- 		drm_crtc_vblank_put(new_state->base.crtc);
- 		drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n",
- 				 __func__, new_state->base.crtc->base.id);
- 
- 		scoped_guard(mutex, &dm->dc_lock) {
- 			dc_exit_ips_for_hw_access(dm->dc);
- 			amdgpu_dm_psr_set_event(dm, new_state->stream, false,
- 				psr_event_vrr_transition, false);
- 			amdgpu_dm_replay_set_event(dm, new_state->stream, false,
- 				replay_event_vrr, false);
- 		}
- 	}
- }
- 
  static void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state)
  {
  	struct drm_plane *plane;
@@@ -10401,14 -3862,12 +3867,12 @@@ static void amdgpu_dm_commit_planes(str
  			continue;
  
  		bundle->surface_updates[planes_count].surface = dc_plane;
- 		if (new_pcrtc_state->color_mgmt_changed || new_plane_state->color_mgmt_changed) {
+ 		if (new_pcrtc_state->color_mgmt_changed) {
  			bundle->surface_updates[planes_count].gamma = &dc_plane->gamma_correction;
  			bundle->surface_updates[planes_count].in_transfer_func = &dc_plane->in_transfer_func;
  			bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
  			bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult;
- 			bundle->surface_updates[planes_count].func_shaper = &dc_plane->in_shaper_func;
- 			bundle->surface_updates[planes_count].lut3d_func = &dc_plane->lut3d_func;
- 			bundle->surface_updates[planes_count].blend_tf = &dc_plane->blend_tf;
+ 			bundle->surface_updates[planes_count].cm = &dc_plane->cm;
  		}
  
  		amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
@@@ -10428,7 -3887,6 +3892,6 @@@
  
  		fill_dc_plane_info_and_addr(
  			dm->adev, new_plane_state,
- 			afb->tiling_flags,
  			&bundle->plane_infos[planes_count],
  			&bundle->flip_addrs[planes_count].address,
  			afb->tmz_surface);
@@@ -10503,7 -3961,7 +3966,7 @@@
  		}
  
  		if (plane == pcrtc->primary)
- 			update_freesync_state_on_stream(
+ 			amdgpu_dm_update_freesync_state_on_stream(
  				dm,
  				acrtc_state,
  				acrtc_state->stream,
@@@ -10624,7 -4082,7 +4087,7 @@@
  		 * re-adjust the min/max bounds now that DC doesn't handle this
  		 * as part of commit.
  		 */
- 		if (is_dc_timing_adjust_needed(dm_old_crtc_state, acrtc_state)) {
+ 		if (amdgpu_dm_is_dc_timing_adjust_needed(dm_old_crtc_state, acrtc_state)) {
  			spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
  			dc_stream_adjust_vmin_vmax(
  				dm->dc, acrtc_state->stream,
@@@ -10784,87 -4242,6 +4247,6 @@@ cleanup
  	kfree(bundle);
  }
  
- static void amdgpu_dm_commit_audio(struct drm_device *dev,
- 				   struct drm_atomic_commit *state)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_state *old_con_state, *new_con_state;
- 	struct drm_crtc_state *new_crtc_state;
- 	struct dm_crtc_state *new_dm_crtc_state;
- 	const struct dc_stream_status *status;
- 	int i, inst;
- 
- 	/* Notify device removals. */
- 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
- 		if (old_con_state->crtc != new_con_state->crtc) {
- 			/* CRTC changes require notification. */
- 			goto notify;
- 		}
- 
- 		if (!new_con_state->crtc)
- 			continue;
- 
- 		new_crtc_state = drm_atomic_get_new_crtc_state(
- 			state, new_con_state->crtc);
- 
- 		if (!new_crtc_state)
- 			continue;
- 
- 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
- 			continue;
- 
- notify:
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 		mutex_lock(&adev->dm.audio_lock);
- 		inst = aconnector->audio_inst;
- 		aconnector->audio_inst = -1;
- 		mutex_unlock(&adev->dm.audio_lock);
- 
- 		amdgpu_dm_audio_eld_notify(adev, inst);
- 	}
- 
- 	/* Notify audio device additions. */
- 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
- 		if (!new_con_state->crtc)
- 			continue;
- 
- 		new_crtc_state = drm_atomic_get_new_crtc_state(
- 			state, new_con_state->crtc);
- 
- 		if (!new_crtc_state)
- 			continue;
- 
- 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
- 			continue;
- 
- 		new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
- 		if (!new_dm_crtc_state->stream)
- 			continue;
- 
- 		status = dc_stream_get_status(new_dm_crtc_state->stream);
- 		if (!status)
- 			continue;
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 		mutex_lock(&adev->dm.audio_lock);
- 		inst = status->audio_inst;
- 		aconnector->audio_inst = inst;
- 		mutex_unlock(&adev->dm.audio_lock);
- 
- 		amdgpu_dm_audio_eld_notify(adev, inst);
- 	}
- }
- 
  /*
   * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC
   * @crtc_state: the DRM CRTC state
@@@ -10879,10 -4256,57 +4261,57 @@@ static void amdgpu_dm_crtc_copy_transie
  	stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state);
  }
  
+ /**
+  * amdgpu_dm_crtc_complete_writeback - finish a pending writeback job
+  * @acrtc: the CRTC whose pending writeback should be completed
+  *
+  * Clears the pending state, signals the writeback out fence and releases the
+  * vblank reference taken in dm_set_writeback() while the writeback was armed.
+  * The pending flag is tested and cleared under the writeback job lock, so this
+  * is safe to call concurrently from the completion vblank IRQ
+  * (dm_crtc_high_irq()) and from the writeback teardown path
+  * (dm_clear_writeback()); only the caller that observes the pending job
+  * performs the completion.
+  *
+  * Return: true if a pending writeback job was completed by this call.
+  */
+ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc)
+ {
+ 	unsigned long flags;
+ 	bool pending;
+ 
+ 	if (!acrtc->wb_conn)
+ 		return false;
+ 
+ 	spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
+ 	pending = acrtc->wb_pending;
+ 	acrtc->wb_pending = false;
+ 	acrtc->wb_frame_done = false;
+ 	spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
+ 
+ 	if (!pending)
+ 		return false;
+ 
+ 	drm_writeback_signal_completion(acrtc->wb_conn, 0);
+ 	drm_crtc_vblank_put(&acrtc->base);
+ 
+ 	return true;
+ }
+ EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
+ 
  static void dm_clear_writeback(struct amdgpu_display_manager *dm,
+ 			      struct amdgpu_crtc *acrtc,
  			      struct dm_crtc_state *crtc_state)
  {
  	dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
+ 
+ 	/*
+ 	 * If the writeback is still pending when it is torn down (its
+ 	 * completion vblank IRQ never fired), signal the out fence so a
+ 	 * waiting client does not stall and release the vblank reference
+ 	 * taken in dm_set_writeback().
+ 	 */
+ 	amdgpu_dm_crtc_complete_writeback(acrtc);
  }
  
  /**
@@@ -11035,7 -4459,7 +4464,7 @@@ static void amdgpu_dm_commit_streams(st
  
  		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
  
- 		dm_clear_writeback(dm, dm_old_crtc_state);
+ 		dm_clear_writeback(dm, acrtc, dm_old_crtc_state);
  		acrtc->wb_enabled = false;
  	}
  
@@@ -11309,9 -4733,25 +4738,25 @@@ static void dm_set_writeback(struct amd
  
  	dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info);
  
- 	acrtc->wb_pending = true;
  	acrtc->wb_conn = wb_conn;
  	drm_writeback_queue_job(wb_conn, new_con_state);
+ 
+ 	/*
+ 	 * Writeback completion is detected in the CRTC vblank IRQ
+ 	 * (dm_crtc_high_irq()). Take a vblank reference so the vblank interrupt
+ 	 * stays enabled while the writeback is pending; otherwise a
+ 	 * writeback-only commit right after drm_crtc_vblank_on() (e.g.
+ 	 * re-enabling a CRTC that was disabled) has no other vblank reference,
+ 	 * the IRQ never fires and the out fence times out. The matching put
+ 	 * happens once completion is signalled in dm_crtc_high_irq(), or when
+ 	 * the writeback is torn down in dm_clear_writeback().
+ 	 *
+ 	 * Arm wb_pending only after the reference is held so the completion IRQ
+ 	 * cannot run its matching vblank_put before this get.
+ 	 */
+ 	WARN_ON(drm_crtc_vblank_get(&acrtc->base));
+ 	acrtc->wb_frame_done = false;
+ 	acrtc->wb_pending = true;
  }
  
  static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
@@@ -11462,6 -4902,75 +4907,75 @@@ static int amdgpu_dm_atomic_setup_commi
  	return 0;
  }
  
+ STATIC_IFN_KUNIT void set_multisync_trigger_params(
+ 		struct dc_stream_state *stream)
+ {
+ 	struct dc_stream_state *master = NULL;
+ 
+ 	if (stream->triggered_crtc_reset.enabled) {
+ 		master = stream->triggered_crtc_reset.event_source;
+ 		stream->triggered_crtc_reset.event =
+ 			master->timing.flags.VSYNC_POSITIVE_POLARITY ?
+ 			CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING;
+ 		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL;
+ 	}
+ }
+ EXPORT_IF_KUNIT(set_multisync_trigger_params);
+ 
+ STATIC_IFN_KUNIT void set_master_stream(struct dc_stream_state *stream_set[],
+ 					int stream_count)
+ {
+ 	int j, highest_rfr = 0, master_stream = 0;
+ 
+ 	for (j = 0;  j < stream_count; j++) {
+ 		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
+ 			int refresh_rate = 0;
+ 
+ 			refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/
+ 				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
+ 			if (refresh_rate > highest_rfr) {
+ 				highest_rfr = refresh_rate;
+ 				master_stream = j;
+ 			}
+ 		}
+ 	}
+ 	for (j = 0;  j < stream_count; j++) {
+ 		if (stream_set[j])
+ 			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
+ 	}
+ }
+ EXPORT_IF_KUNIT(set_master_stream);
+ 
+ STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
+ {
+ 	int i = 0;
+ 	struct dc_stream_state *stream;
+ 
+ 	if (context->stream_count < 2)
+ 		return;
+ 	for (i = 0; i < context->stream_count ; i++) {
+ 		if (!context->streams[i])
+ 			continue;
+ 		/*
+ 		 * TODO: add a function to read AMD VSDB bits and set
+ 		 * crtc_sync_master.multi_sync_enabled flag
+ 		 * For now it's set to false
+ 		 */
+ 	}
+ 
+ 	set_master_stream(context->streams, context->stream_count);
+ 
+ 	for (i = 0; i < context->stream_count ; i++) {
+ 		stream = context->streams[i];
+ 
+ 		if (!stream)
+ 			continue;
+ 
+ 		set_multisync_trigger_params(stream);
+ 	}
+ }
+ EXPORT_IF_KUNIT(dm_enable_per_frame_crtc_master_sync);
+ 
  /**
   * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
   * @state: The atomic state to commit
@@@ -11530,7 -5039,7 +5044,7 @@@ static void amdgpu_dm_atomic_commit_tai
  
  		if ((new_con_state->hdmi.broadcast_rgb != old_con_state->hdmi.broadcast_rgb) &&
  			(dm_old_crtc_state->stream->output_color_space !=
- 				get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state)))
+ 				amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state)))
  			output_color_space_changed = true;
  
  		abm_changed = dm_new_crtc_state->abm_level !=
@@@ -11544,7 -5053,7 +5058,7 @@@
  
  		stream_update.stream = dm_new_crtc_state->stream;
  		if (scaling_changed) {
- 			update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode,
+ 			amdgpu_dm_update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode,
  					dm_new_con_state, dm_new_crtc_state->stream);
  
  			stream_update.src = dm_new_crtc_state->stream->src;
@@@ -11553,7 -5062,7 +5067,7 @@@
  
  		if (output_color_space_changed) {
  			dm_new_crtc_state->stream->output_color_space
- 				= get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state);
+ 				= amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state);
  
  			stream_update.output_color_space = &dm_new_crtc_state->stream->output_color_space;
  		}
@@@ -11565,7 -5074,7 +5079,7 @@@
  		}
  
  		if (hdr_changed) {
- 			fill_hdr_info_packet(new_con_state, &hdr_packet);
+ 			amdgpu_dm_fill_hdr_info_packet(new_con_state, &hdr_packet);
  			stream_update.hdr_static_metadata = &hdr_packet;
  		}
  
@@@ -11624,7 -5133,7 +5138,7 @@@
  		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
  
  		/* For freesync config update on crtc state and params for irq */
- 		update_stream_irq_parameters(dm, dm_new_crtc_state);
+ 		amdgpu_dm_update_stream_irq_parameters(dm, dm_new_crtc_state);
  
  #ifdef CONFIG_DEBUG_FS
  		spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
@@@ -11773,104 -5282,6 +5287,6 @@@
  	trace_amdgpu_dm_atomic_commit_tail_finish(state);
  }
  
- static int dm_force_atomic_commit(struct drm_connector *connector)
- {
- 	int ret = 0;
- 	struct drm_device *ddev = connector->dev;
- 	struct drm_atomic_commit *state = drm_atomic_commit_alloc(ddev);
- 	struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
- 	struct drm_plane *plane = disconnected_acrtc->base.primary;
- 	struct drm_connector_state *conn_state;
- 	struct drm_crtc_state *crtc_state;
- 	struct drm_plane_state *plane_state;
- 
- 	if (!state)
- 		return -ENOMEM;
- 
- 	state->acquire_ctx = ddev->mode_config.acquire_ctx;
- 
- 	/* Construct an atomic state to restore previous display setting */
- 
- 	/*
- 	 * Attach connectors to drm_atomic_commit
- 	 */
- 	conn_state = drm_atomic_get_connector_state(state, connector);
- 
- 	/* Check for error in getting connector state */
- 	if (IS_ERR(conn_state)) {
- 		ret = PTR_ERR(conn_state);
- 		goto out;
- 	}
- 
- 	/* Attach crtc to drm_atomic_commit*/
- 	crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
- 
- 	/* Check for error in getting crtc state */
- 	if (IS_ERR(crtc_state)) {
- 		ret = PTR_ERR(crtc_state);
- 		goto out;
- 	}
- 
- 	/* force a restore */
- 	crtc_state->mode_changed = true;
- 
- 	/* Attach plane to drm_atomic_commit */
- 	plane_state = drm_atomic_get_plane_state(state, plane);
- 
- 	/* Check for error in getting plane state */
- 	if (IS_ERR(plane_state)) {
- 		ret = PTR_ERR(plane_state);
- 		goto out;
- 	}
- 
- 	/* Call commit internally with the state we just constructed */
- 	ret = drm_atomic_commit(state);
- 
- out:
- 	drm_atomic_commit_put(state);
- 	if (ret)
- 		drm_err(ddev, "Restoring old state failed with %i\n", ret);
- 
- 	return ret;
- }
- 
- /*
-  * This function handles all cases when set mode does not come upon hotplug.
-  * This includes when a display is unplugged then plugged back into the
-  * same port and when running without usermode desktop manager supprot
-  */
- void dm_restore_drm_connector_state(struct drm_device *dev,
- 				    struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct amdgpu_crtc *disconnected_acrtc;
- 	struct dm_crtc_state *acrtc_state;
- 
- 	if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 		return;
- 
- 	aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if (!aconnector->dc_sink || !connector->state || !connector->encoder)
- 		return;
- 
- 	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
- 	if (!disconnected_acrtc)
- 		return;
- 
- 	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state);
- 	if (!acrtc_state->stream)
- 		return;
- 
- 	/*
- 	 * If the previous sink is not released and different from the current,
- 	 * we deduce we are in a state where we can not rely on usermode call
- 	 * to turn on the display, so we do it here
- 	 */
- 	if (acrtc_state->stream->sink != aconnector->dc_sink)
- 		dm_force_atomic_commit(&aconnector->base);
- }
- 
  /*
   * Grabs all modesetting locks to serialize against any blocking commits,
   * Waits for completion of all non blocking commits.
@@@ -11922,104 -5333,6 +5338,6 @@@ static int do_aquire_global_lock(struc
  	return ret < 0 ? ret : 0;
  }
  
- static void get_freesync_config_for_crtc(
- 	struct dm_crtc_state *new_crtc_state,
- 	struct dm_connector_state *new_con_state)
- {
- 	struct mod_freesync_config config = {0};
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_display_mode *mode = &new_crtc_state->base.mode;
- 	int vrefresh = drm_mode_vrefresh(mode);
- 	bool fs_vid_mode = false;
- 
- 	if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 		return;
- 
- 	aconnector = to_amdgpu_dm_connector(new_con_state->base.connector);
- 
- 	new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
- 					vrefresh >= aconnector->min_vfreq &&
- 					vrefresh <= aconnector->max_vfreq;
- 
- 	if (new_crtc_state->vrr_supported) {
- 		new_crtc_state->stream->ignore_msa_timing_param = true;
- 		fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
- 
- 		config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000;
- 		config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000;
- 		config.vsif_supported = true;
- 		config.btr = true;
- 
- 		if (fs_vid_mode) {
- 			config.state = VRR_STATE_ACTIVE_FIXED;
- 			config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz;
- 			goto out;
- 		} else if (new_crtc_state->base.vrr_enabled) {
- 			config.state = VRR_STATE_ACTIVE_VARIABLE;
- 		} else {
- 			config.state = VRR_STATE_INACTIVE;
- 		}
- 	} else {
- 		config.state = VRR_STATE_UNSUPPORTED;
- 	}
- out:
- 	new_crtc_state->freesync_config = config;
- }
- 
- static void reset_freesync_config_for_crtc(
- 	struct dm_crtc_state *new_crtc_state)
- {
- 	new_crtc_state->vrr_supported = false;
- 
- 	memset(&new_crtc_state->vrr_infopacket, 0,
- 	       sizeof(new_crtc_state->vrr_infopacket));
- }
- 
- static bool
- is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
- 				 struct drm_crtc_state *new_crtc_state)
- {
- 	const struct drm_display_mode *old_mode, *new_mode;
- 
- 	if (!old_crtc_state || !new_crtc_state)
- 		return false;
- 
- 	old_mode = &old_crtc_state->mode;
- 	new_mode = &new_crtc_state->mode;
- 
- 	if (old_mode->clock       == new_mode->clock &&
- 	    old_mode->hdisplay    == new_mode->hdisplay &&
- 	    old_mode->vdisplay    == new_mode->vdisplay &&
- 	    old_mode->htotal      == new_mode->htotal &&
- 	    old_mode->vtotal      != new_mode->vtotal &&
- 	    old_mode->hsync_start == new_mode->hsync_start &&
- 	    old_mode->vsync_start != new_mode->vsync_start &&
- 	    old_mode->hsync_end   == new_mode->hsync_end &&
- 	    old_mode->vsync_end   != new_mode->vsync_end &&
- 	    old_mode->hskew       == new_mode->hskew &&
- 	    old_mode->vscan       == new_mode->vscan &&
- 	    (old_mode->vsync_end - old_mode->vsync_start) ==
- 	    (new_mode->vsync_end - new_mode->vsync_start))
- 		return true;
- 
- 	return false;
- }
- 
- static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
- {
- 	u64 num, den, res;
- 	struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
- 
- 	dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
- 
- 	num = (unsigned long long)new_crtc_state->mode.clock * 1000 * 1000000;
- 	den = (unsigned long long)new_crtc_state->mode.htotal *
- 	      (unsigned long long)new_crtc_state->mode.vtotal;
- 
- 	res = div_u64(num, den);
- 	dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res;
- }
- 
  static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
  			 struct drm_atomic_commit *state,
  			 struct drm_crtc *crtc,
@@@ -12072,7 -5385,7 +5390,7 @@@
  		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
  			goto skip_modeset;
  
- 		new_stream = create_validate_stream_for_sink(connector,
+ 		new_stream = amdgpu_dm_create_validate_stream_for_sink(connector,
  							     &new_crtc_state->mode,
  							     dm_new_conn_state,
  							     dm_old_crtc_state->stream);
@@@ -12100,7 -5413,7 +5418,7 @@@
  
  		dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
  
- 		ret = fill_hdr_info_packet(drm_new_conn_state,
+ 		ret = amdgpu_dm_fill_hdr_info_packet(drm_new_conn_state,
  					   &new_stream->hdr_static_metadata);
  		if (ret)
  			goto fail;
@@@ -12116,7 -5429,7 +5434,7 @@@
  		 */
  		if (amdgpu_freesync_vid_mode &&
  		    dm_new_crtc_state->stream &&
- 		    is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
+ 		    amdgpu_dm_is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
  			goto skip_modeset;
  
  		if (dm_new_crtc_state->stream &&
@@@ -12158,24 -5471,24 +5476,24 @@@
  		if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
  		    dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
  		    dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream) &&
- 		    is_timing_unchanged_for_freesync(new_crtc_state,
+ 		    amdgpu_dm_is_timing_unchanged_for_freesync(new_crtc_state,
  						     old_crtc_state)) {
  			new_crtc_state->mode_changed = false;
  			drm_dbg_driver(adev_to_drm(adev),
  				"Mode change not required for front porch change, setting mode_changed to %d",
  				new_crtc_state->mode_changed);
  
- 			set_freesync_fixed_config(dm_new_crtc_state);
+ 			amdgpu_dm_set_freesync_fixed_config(dm_new_crtc_state);
  
  			goto skip_modeset;
  		} else if (amdgpu_freesync_vid_mode && aconnector &&
- 			   is_freesync_video_mode(&new_crtc_state->mode,
+ 			   amdgpu_dm_is_freesync_video_mode(&new_crtc_state->mode,
  						  aconnector)) {
  			struct drm_display_mode *high_mode;
  
- 			high_mode = get_highest_refresh_rate_mode(aconnector, false);
+ 			high_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false);
  			if (!drm_mode_equal(&new_crtc_state->mode, high_mode))
- 				set_freesync_fixed_config(dm_new_crtc_state);
+ 				amdgpu_dm_set_freesync_fixed_config(dm_new_crtc_state);
  		}
  
  		ret = dm_atomic_get_state(state, &dm_state);
@@@ -12197,7 -5510,7 +5515,7 @@@
  		dc_stream_release(dm_old_crtc_state->stream);
  		dm_new_crtc_state->stream = NULL;
  
- 		reset_freesync_config_for_crtc(dm_new_crtc_state);
+ 		amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
  
  		*lock_and_validation_needed = true;
  
@@@ -12266,7 -5579,7 +5584,7 @@@ skip_modeset
  	/* Scaling or underscan settings */
  	if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) ||
  				drm_atomic_crtc_needs_modeset(new_crtc_state))
- 		update_stream_scaling_settings(adev_to_drm(adev),
+ 		amdgpu_dm_update_stream_scaling_settings(adev_to_drm(adev),
  			&new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
  
  	/* ABM settings */
@@@ -12285,7 -5598,7 +5603,7 @@@
  	}
  
  	/* Update Freesync settings. */
- 	get_freesync_config_for_crtc(dm_new_crtc_state,
+ 	amdgpu_dm_get_freesync_config_for_crtc(dm_new_crtc_state,
  				     dm_new_conn_state);
  
  	return ret;
@@@ -12362,10 -5675,6 +5680,6 @@@ static bool should_reset_plane(struct d
  	if (new_crtc_state->color_mgmt_changed)
  		return true;
  
- 	/* Plane color pipeline or its colorop changes. */
- 	if (new_plane_state->color_mgmt_changed)
- 		return true;
- 
  	/*
  	 * On zpos change, planes need to be reordered by removing and re-adding
  	 * them one by one to the dc state, in order of descending zpos.
@@@ -12453,140 -5762,13 +5767,13 @@@
  		new_afb = (struct amdgpu_framebuffer *)new_other_state->fb;
  
  		/* Tiling and DCC changes also require bandwidth updates. */
- 		if (old_afb->tiling_flags != new_afb->tiling_flags ||
- 		    old_afb->base.modifier != new_afb->base.modifier)
+ 		if (old_afb->base.modifier != new_afb->base.modifier)
  			return true;
  	}
  
  	return false;
  }
  
- static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
- 			      struct drm_plane_state *new_plane_state,
- 			      struct drm_framebuffer *fb)
- {
- 	struct amdgpu_device *adev = drm_to_adev(new_acrtc->base.dev);
- 	struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
- 	unsigned int pitch;
- 	bool linear;
- 
- 	if (fb->width > new_acrtc->max_cursor_width ||
- 	    fb->height > new_acrtc->max_cursor_height) {
- 		drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size %dx%d\n",
- 				 new_plane_state->fb->width,
- 				 new_plane_state->fb->height);
- 		return -EINVAL;
- 	}
- 	if (new_plane_state->src_w != fb->width << 16 ||
- 	    new_plane_state->src_h != fb->height << 16) {
- 		drm_dbg_atomic(adev_to_drm(adev), "Cropping not supported for cursor plane\n");
- 		return -EINVAL;
- 	}
- 
- 	/* Pitch in pixels */
- 	pitch = fb->pitches[0] / fb->format->cpp[0];
- 
- 	if (fb->width != pitch) {
- 		drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d doesn't match pitch %d",
- 				 fb->width, pitch);
- 		return -EINVAL;
- 	}
- 
- 	switch (pitch) {
- 	case 64:
- 	case 128:
- 	case 256:
- 		/* FB pitch is supported by cursor plane */
- 		break;
- 	default:
- 		drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch %d px\n", pitch);
- 		return -EINVAL;
- 	}
- 
- 	/* Core DRM takes care of checking FB modifiers, so we only need to
- 	 * check tiling flags when the FB doesn't have a modifier.
- 	 */
- 	if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) {
- 		if (adev->family == AMDGPU_FAMILY_GC_12_0_0) {
- 			linear = AMDGPU_TILING_GET(afb->tiling_flags, GFX12_SWIZZLE_MODE) == 0;
- 		} else if (adev->family >= AMDGPU_FAMILY_AI) {
- 			linear = AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0;
- 		} else {
- 			linear = AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_2D_TILED_THIN1 &&
- 				 AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 &&
- 				 AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
- 		}
- 		if (!linear) {
- 			drm_dbg_atomic(adev_to_drm(adev), "Cursor FB not linear");
- 			return -EINVAL;
- 		}
- 	}
- 
- 	return 0;
- }
- 
- /*
-  * Helper function for checking the cursor in native mode
-  */
- static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc,
- 					struct drm_plane *plane,
- 					struct drm_plane_state *new_plane_state,
- 					bool enable)
- {
- 
- 	struct amdgpu_crtc *new_acrtc;
- 	int ret;
- 
- 	if (!enable || !new_plane_crtc ||
- 	    drm_atomic_plane_disabling(plane->state, new_plane_state))
- 		return 0;
- 
- 	new_acrtc = to_amdgpu_crtc(new_plane_crtc);
- 
- 	if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) {
- 		drm_dbg_atomic(new_plane_crtc->dev, "Cropping not supported for cursor plane\n");
- 		return -EINVAL;
- 	}
- 
- 	if (new_plane_state->fb) {
- 		ret = dm_check_cursor_fb(new_acrtc, new_plane_state,
- 						new_plane_state->fb);
- 		if (ret)
- 			return ret;
- 	}
- 
- 	return 0;
- }
- 
- static bool dm_should_update_native_cursor(struct drm_atomic_commit *state,
- 					   struct drm_crtc *old_plane_crtc,
- 					   struct drm_crtc *new_plane_crtc,
- 					   bool enable)
- {
- 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
- 	struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
- 
- 	if (!enable) {
- 		if (old_plane_crtc == NULL)
- 			return true;
- 
- 		old_crtc_state = drm_atomic_get_old_crtc_state(
- 			state, old_plane_crtc);
- 		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- 
- 		return dm_old_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE;
- 	} else {
- 		if (new_plane_crtc == NULL)
- 			return true;
- 
- 		new_crtc_state = drm_atomic_get_new_crtc_state(
- 			state, new_plane_crtc);
- 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
- 
- 		return dm_new_crtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE;
- 	}
- }
- 
  static int dm_update_plane_state(struct dc *dc,
  				 struct drm_atomic_commit *state,
  				 struct drm_plane *plane,
@@@ -12611,14 -5793,14 +5798,14 @@@
  	dm_new_plane_state = to_dm_plane_state(new_plane_state);
  	dm_old_plane_state = to_dm_plane_state(old_plane_state);
  
- 	update_native_cursor = dm_should_update_native_cursor(state,
- 							      old_plane_crtc,
- 							      new_plane_crtc,
- 							      enable);
+ 	update_native_cursor = amdgpu_dm_should_update_native_cursor(state,
+ 								     old_plane_crtc,
+ 								     new_plane_crtc,
+ 								     enable);
  
  	if (plane->type == DRM_PLANE_TYPE_CURSOR && update_native_cursor) {
- 		ret = dm_check_native_cursor_state(new_plane_crtc, plane,
- 						    new_plane_state, enable);
+ 		ret = amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane,
+ 							  new_plane_state, enable);
  		if (ret)
  			return ret;
  
@@@ -12740,7 -5922,7 +5927,7 @@@
  		/* Tell DC to do a full surface update every time there
  		 * is a plane change. Inefficient, but works for now.
  		 */
- 		dm_new_plane_state->dc_state->update_flags.bits.full_update = 1;
+ 		dm_new_plane_state->dc_state->update_bits.full_update = 1;
  
  		*lock_and_validation_needed = true;
  	}
@@@ -12748,8 -5930,8 +5935,8 @@@
  out:
  	/* If enabling cursor overlay failed, attempt fallback to native mode */
  	if (enable && ret == -EINVAL && plane->type == DRM_PLANE_TYPE_CURSOR) {
- 		ret = dm_check_native_cursor_state(new_plane_crtc, plane,
- 						    new_plane_state, enable);
+ 		ret = amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane,
+ 							  new_plane_state, enable);
  		if (ret)
  			return ret;
  
@@@ -12759,35 -5941,6 +5946,6 @@@
  	return ret;
  }
  
- static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state,
- 				       int *src_w, int *src_h)
- {
- 	switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
- 	case DRM_MODE_ROTATE_90:
- 	case DRM_MODE_ROTATE_270:
- 		*src_w = plane_state->src_h >> 16;
- 		*src_h = plane_state->src_w >> 16;
- 		break;
- 	case DRM_MODE_ROTATE_0:
- 	case DRM_MODE_ROTATE_180:
- 	default:
- 		*src_w = plane_state->src_w >> 16;
- 		*src_h = plane_state->src_h >> 16;
- 		break;
- 	}
- }
- 
- static void
- dm_get_plane_scale(struct drm_plane_state *plane_state,
- 		   int *out_plane_scale_w, int *out_plane_scale_h)
- {
- 	int plane_src_w, plane_src_h;
- 
- 	dm_get_oriented_plane_size(plane_state, &plane_src_w, &plane_src_h);
- 	*out_plane_scale_w = plane_src_w ? plane_state->crtc_w * 1000 / plane_src_w : 0;
- 	*out_plane_scale_h = plane_src_h ? plane_state->crtc_h * 1000 / plane_src_h : 0;
- }
- 
  /*
   * The normalized_zpos value cannot be used by this iterator directly. It's only
   * calculated for enabled planes, potentially causing normalized_zpos collisions
@@@ -12795,7 -5948,7 +5953,7 @@@
   * so that the iterator will not generate the same object twice, or loop
   * indefinitely.
   */
- static inline struct __drm_planes_state *__get_next_zpos(
+ struct __drm_planes_state *amdgpu_dm_get_next_zpos(
  	struct drm_atomic_commit *state,
  	struct __drm_planes_state *prev)
  {
@@@ -12833,19 -5986,6 +5991,6 @@@
  	return &state->planes[highest_i];
  }
  
- /*
-  * Use the uniqueness of the plane's (zpos, drm obj ID) combination to iterate
-  * by descending zpos, as read from the new plane state. This is the same
-  * ordering as defined by drm_atomic_normalize_zpos().
-  */
- #define for_each_oldnew_plane_in_descending_zpos(__state, plane, old_plane_state, new_plane_state) \
- 	for (struct __drm_planes_state *__i = __get_next_zpos((__state), NULL); \
- 	     __i != NULL; __i = __get_next_zpos((__state), __i))		\
- 		for_each_if(((plane) = __i->ptr,				\
- 			     (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
- 			     (old_plane_state) = __i->old_state,		\
- 			     (new_plane_state) = __i->new_state, 1))
- 
  static int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state, struct drm_crtc *crtc)
  {
  	struct drm_connector *connector;
@@@ -12876,219 -6016,6 +6021,6 @@@
  	return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_root->mst_mgr);
  }
  
- /**
-  * DOC: Cursor Modes - Native vs Overlay
-  *
-  * In native mode, the cursor uses a integrated cursor pipe within each DCN hw
-  * plane. It does not require a dedicated hw plane to enable, but it is
-  * subjected to the same z-order and scaling as the hw plane. It also has format
-  * restrictions, a RGB cursor in native mode cannot be enabled within a non-RGB
-  * hw plane.
-  *
-  * In overlay mode, the cursor uses a separate DCN hw plane, and thus has its
-  * own scaling and z-pos. It also has no blending restrictions. It lends to a
-  * cursor behavior more akin to a DRM client's expectations. However, it does
-  * occupy an extra DCN plane, and therefore will only be used if a DCN plane is
-  * available.
-  */
- 
- /**
-  * dm_plane_color_pipeline_active() - Check if a plane's color pipeline active.
-  * @state: DRM atomic state
-  * @plane: DRM plane to check
-  * @use_old: if true, inspect the old colorop states; otherwise the new ones
-  *
-  * A color pipeline may be selected (color_pipeline != NULL) but still is
-  * inactive if every colorop in the chain is bypassed.  Only return
-  * true when at least one colorop has bypass == false, meaning the cursor
-  * would be subjected to the transformation in native mode.
-  *
-  * Return: true if the pipeline modifies pixels, false otherwise.
-  */
- static bool dm_plane_color_pipeline_active(struct drm_atomic_commit *state,
- 					   struct drm_plane *plane,
- 					   bool use_old)
- {
- 	struct drm_colorop *colorop;
- 	struct drm_colorop_state *old_colorop_state, *new_colorop_state;
- 	int i;
- 
- 	for_each_oldnew_colorop_in_state(state, colorop, old_colorop_state, new_colorop_state, i) {
- 		struct drm_colorop_state *cstate = use_old ? old_colorop_state : new_colorop_state;
- 
- 		if (cstate->colorop->plane != plane)
- 			continue;
- 		if (!cstate->bypass)
- 			return true;
- 	}
- 	return false;
- }
- 
- /**
-  * dm_crtc_get_cursor_mode() - Determine the required cursor mode on crtc
-  * @adev: amdgpu device
-  * @state: DRM atomic state
-  * @dm_crtc_state: amdgpu state for the CRTC containing the cursor
-  * @cursor_mode: Returns the required cursor mode on dm_crtc_state
-  *
-  * Get whether the cursor should be enabled in native mode, or overlay mode, on
-  * the dm_crtc_state.
-  *
-  * The cursor should be enabled in overlay mode if there exists an underlying
-  * plane - on which the cursor may be blended - that is either YUV formatted,
-  * scaled differently from the cursor, or has a color pipeline active.
-  *
-  * Since zpos info is required, drm_atomic_normalize_zpos must be called before
-  * calling this function.
-  *
-  * Return: 0 on success, or an error code if getting the cursor plane state
-  * failed.
-  */
- static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
- 				   struct drm_atomic_commit *state,
- 				   struct dm_crtc_state *dm_crtc_state,
- 				   enum amdgpu_dm_cursor_mode *cursor_mode)
- {
- 	struct drm_plane_state *old_plane_state, *plane_state, *cursor_state;
- 	struct drm_crtc_state *crtc_state = &dm_crtc_state->base;
- 	struct drm_plane *plane;
- 	bool consider_mode_change = false;
- 	bool entire_crtc_covered = false;
- 	bool cursor_changed = false;
- 	int underlying_scale_w, underlying_scale_h;
- 	int cursor_scale_w, cursor_scale_h;
- 	int i;
- 
- 	/* Overlay cursor not supported on HW before DCN
- 	 * DCN401/420 does not have the cursor-on-scaled-plane or cursor-on-yuv-plane restrictions
- 	 * as previous DCN generations, so enable native mode on DCN401/420
- 	 *
- 	 * Always set native cursor mode when the CRTC is disabled,
- 	 * to make sure it doesn't cause atomic commits to fail when
- 	 * they are trying to disable the CRTC.
- 	 */
- 	if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1) ||
- 	    amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
- 	    amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
- 	    !dm_crtc_state->base.enable) {
- 		*cursor_mode = DM_CURSOR_NATIVE_MODE;
- 		return 0;
- 	}
- 
- 	/* Init cursor_mode to be the same as current */
- 	*cursor_mode = dm_crtc_state->cursor_mode;
- 
- 	/*
- 	 * Cursor mode can change if a plane's format changes, scale changes, is
- 	 * enabled/disabled, z-order changes, or color management properties change.
- 	 */
- 	for_each_oldnew_plane_in_state(state, plane, old_plane_state, plane_state, i) {
- 		int new_scale_w, new_scale_h, old_scale_w, old_scale_h;
- 
- 		/* Only care about planes on this CRTC */
- 		if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 0)
- 			continue;
- 
- 		if (plane->type == DRM_PLANE_TYPE_CURSOR)
- 			cursor_changed = true;
- 
- 		if (drm_atomic_plane_enabling(old_plane_state, plane_state) ||
- 		    drm_atomic_plane_disabling(old_plane_state, plane_state) ||
- 		    old_plane_state->fb->format != plane_state->fb->format) {
- 			consider_mode_change = true;
- 			break;
- 		}
- 
- 		dm_get_plane_scale(plane_state, &new_scale_w, &new_scale_h);
- 		dm_get_plane_scale(old_plane_state, &old_scale_w, &old_scale_h);
- 		if (new_scale_w != old_scale_w || new_scale_h != old_scale_h) {
- 			consider_mode_change = true;
- 			break;
- 		}
- 
- 		if (dm_plane_color_pipeline_active(state, plane, true) !=
- 		    dm_plane_color_pipeline_active(state, plane, false)) {
- 			consider_mode_change = true;
- 			break;
- 		}
- 	}
- 
- 	if (!consider_mode_change && !crtc_state->zpos_changed)
- 		return 0;
- 
- 	/*
- 	 * If no cursor change on this CRTC, and not enabled on this CRTC, then
- 	 * no need to set cursor mode. This avoids needlessly locking the cursor
- 	 * state.
- 	 */
- 	if (!cursor_changed &&
- 	    !(drm_plane_mask(crtc_state->crtc->cursor) & crtc_state->plane_mask)) {
- 		return 0;
- 	}
- 
- 	cursor_state = drm_atomic_get_plane_state(state,
- 						  crtc_state->crtc->cursor);
- 	if (IS_ERR(cursor_state))
- 		return PTR_ERR(cursor_state);
- 
- 	/* Cursor is disabled */
- 	if (!cursor_state->fb)
- 		return 0;
- 
- 	/* For all planes in descending z-order (all of which are below cursor
- 	 * as per zpos definitions), check their scaling and format
- 	 */
- 	for_each_oldnew_plane_in_descending_zpos(state, plane, old_plane_state, plane_state) {
- 
- 		/* Only care about non-cursor planes on this CRTC */
- 		if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 0 ||
- 		    plane->type == DRM_PLANE_TYPE_CURSOR)
- 			continue;
- 
- 		/* Underlying plane is YUV format - use overlay cursor */
- 		if (amdgpu_dm_plane_is_video_format(plane_state->fb->format->format)) {
- 			*cursor_mode = DM_CURSOR_OVERLAY_MODE;
- 			return 0;
- 		}
- 
- 		/* Underlying plane has an active color pipeline - cursor would be transformed */
- 		if (dm_plane_color_pipeline_active(state, plane, false)) {
- 			*cursor_mode = DM_CURSOR_OVERLAY_MODE;
- 			return 0;
- 		}
- 
- 		dm_get_plane_scale(plane_state,
- 				   &underlying_scale_w, &underlying_scale_h);
- 		dm_get_plane_scale(cursor_state,
- 				   &cursor_scale_w, &cursor_scale_h);
- 
- 		/* Underlying plane has different scale - use overlay cursor */
- 		if (cursor_scale_w != underlying_scale_w &&
- 		    cursor_scale_h != underlying_scale_h) {
- 			*cursor_mode = DM_CURSOR_OVERLAY_MODE;
- 			return 0;
- 		}
- 
- 		/* If this plane covers the whole CRTC, no need to check planes underneath */
- 		if (plane_state->crtc_x <= 0 && plane_state->crtc_y <= 0 &&
- 		    plane_state->crtc_x + plane_state->crtc_w >= crtc_state->mode.hdisplay &&
- 		    plane_state->crtc_y + plane_state->crtc_h >= crtc_state->mode.vdisplay) {
- 			entire_crtc_covered = true;
- 			break;
- 		}
- 	}
- 
- 	/* If planes do not cover the entire CRTC, use overlay mode to enable
- 	 * cursor over holes
- 	 */
- 	if (entire_crtc_covered)
- 		*cursor_mode = DM_CURSOR_NATIVE_MODE;
- 	else
- 		*cursor_mode = DM_CURSOR_OVERLAY_MODE;
- 
- 	return 0;
- }
- 
  static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
  					    struct drm_atomic_commit *state,
  					    struct drm_crtc_state *crtc_state)
@@@ -13161,7 -6088,7 +6093,7 @@@ static int amdgpu_dm_atomic_check(struc
  
  	ret = drm_atomic_helper_check_modeset(dev, state);
  	if (ret) {
- 		drm_dbg_atomic(dev, "drm_atomic_helper_check_modeset() failed\n");
+ 		drm_dbg_atomic(dev, "drm_atomic_helper_check_modeset() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13176,7 -6103,7 +6108,7 @@@
  
  		new_crtc_state = drm_atomic_get_crtc_state(state, new_con_state->crtc);
  		if (IS_ERR(new_crtc_state)) {
- 			drm_dbg_atomic(dev, "drm_atomic_get_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_get_crtc_state() failed: %pe\n", new_crtc_state);
  			ret = PTR_ERR(new_crtc_state);
  			goto fail;
  		}
@@@ -13196,7 -6123,7 +6128,7 @@@
  			if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
  				ret = add_affected_mst_dsc_crtcs(state, crtc);
  				if (ret) {
- 					drm_dbg_atomic(dev, "add_affected_mst_dsc_crtcs() failed\n");
+ 					drm_dbg_atomic(dev, "add_affected_mst_dsc_crtcs() failed: %pe\n", ERR_PTR(ret));
  					goto fail;
  				}
  			}
@@@ -13213,7 -6140,7 +6145,7 @@@
  
  		ret = amdgpu_dm_verify_lut_sizes(new_crtc_state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "amdgpu_dm_verify_lut_sizes() failed\n");
+ 			drm_dbg_atomic(dev, "amdgpu_dm_verify_lut_sizes() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13222,13 -6149,13 +6154,13 @@@
  
  		ret = drm_atomic_add_affected_connectors(state, crtc);
  		if (ret) {
- 			drm_dbg_atomic(dev, "drm_atomic_add_affected_connectors() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_add_affected_connectors() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
  		ret = drm_atomic_add_affected_planes(state, crtc);
  		if (ret) {
- 			drm_dbg_atomic(dev, "drm_atomic_add_affected_planes() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_add_affected_planes() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13267,7 -6194,7 +6199,7 @@@
  
  			if (IS_ERR(new_plane_state)) {
  				ret = PTR_ERR(new_plane_state);
- 				drm_dbg_atomic(dev, "new_plane_state is BAD\n");
+ 				drm_dbg_atomic(dev, "new_plane_state is BAD: %pe\n", new_plane_state);
  				goto fail;
  			}
  		}
@@@ -13281,7 -6208,7 +6213,7 @@@
  	 */
  	ret = drm_atomic_normalize_zpos(dev, state);
  	if (ret) {
- 		drm_dbg(dev, "drm_atomic_normalize_zpos() failed\n");
+ 		drm_dbg(dev, "drm_atomic_normalize_zpos() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13292,10 -6219,10 +6224,10 @@@
  	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
  		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
  
- 		ret = dm_crtc_get_cursor_mode(adev, state, dm_new_crtc_state,
- 					      &dm_new_crtc_state->cursor_mode);
+ 		ret = amdgpu_dm_crtc_get_cursor_mode(adev, state, dm_new_crtc_state,
+ 						     &dm_new_crtc_state->cursor_mode);
  		if (ret) {
- 			drm_dbg(dev, "Failed to determine cursor mode\n");
+ 			drm_dbg(dev, "Failed to determine cursor mode: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13327,7 -6254,7 +6259,7 @@@
  					    &lock_and_validation_needed,
  					    &is_top_most_overlay);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_plane_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13340,7 -6267,7 +6272,7 @@@
  					   false,
  					   &lock_and_validation_needed);
  		if (ret) {
- 			drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13353,7 -6280,7 +6285,7 @@@
  					   true,
  					   &lock_and_validation_needed);
  		if (ret) {
- 			drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13367,7 -6294,7 +6299,7 @@@
  					    &lock_and_validation_needed,
  					    &is_top_most_overlay);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_plane_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13383,7 -6310,7 +6315,7 @@@
  	/* Run this here since we want to validate the streams we created */
  	ret = drm_atomic_helper_check_planes(dev, state);
  	if (ret) {
- 		drm_dbg_atomic(dev, "drm_atomic_helper_check_planes() failed\n");
+ 		drm_dbg_atomic(dev, "drm_atomic_helper_check_planes() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13427,8 -6354,8 +6359,8 @@@
  		}
  
  		/* If HW can only do native cursor, check restrictions again */
- 		ret = dm_crtc_get_cursor_mode(adev, state, dm_new_crtc_state,
- 					      &required_cursor_mode);
+ 		ret = amdgpu_dm_crtc_get_cursor_mode(adev, state, dm_new_crtc_state,
+ 						     &required_cursor_mode);
  		if (ret) {
  			drm_dbg_driver(crtc->dev,
  				       "[CRTC:%d:%s] Checking cursor mode failed\n",
@@@ -13521,13 -6448,13 +6453,13 @@@
  	if (lock_and_validation_needed) {
  		ret = dm_atomic_get_state(state, &dm_state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_atomic_get_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_atomic_get_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
  		ret = do_aquire_global_lock(dev, state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "do_aquire_global_lock() failed\n");
+ 			drm_dbg_atomic(dev, "do_aquire_global_lock() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13535,7 -6462,7 +6467,7 @@@
  		if (dc_resource_is_dsc_encoding_supported(dc)) {
  			ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars);
  			if (ret) {
- 				drm_dbg_atomic(dev, "MST_DSC compute_mst_dsc_configs_for_state() failed\n");
+ 				drm_dbg_atomic(dev, "MST_DSC compute_mst_dsc_configs_for_state() failed: %pe\n", ERR_PTR(ret));
  				ret = -EINVAL;
  				goto fail;
  			}
@@@ -13544,7 -6471,7 +6476,7 @@@
  
  		ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_mst_vcpi_slots_for_dsc() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_mst_vcpi_slots_for_dsc() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13556,7 -6483,7 +6488,7 @@@
  		 */
  		ret = drm_dp_mst_atomic_check(state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "MST drm_dp_mst_atomic_check() failed\n");
+ 			drm_dbg_atomic(dev, "MST drm_dp_mst_atomic_check() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  		status = dc_validate_global_state(dc, dm_state->context, DC_VALIDATE_MODE_ONLY);
@@@ -13645,380 -6572,13 +6577,13 @@@ fail
  	else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
  		drm_dbg_atomic(dev, "Atomic check stopped due to signal.\n");
  	else
- 		drm_dbg_atomic(dev, "Atomic check failed with err: %d\n", ret);
+ 		drm_dbg_atomic(dev, "Atomic check failed: %pe\n", ERR_PTR(ret));
  
  	trace_amdgpu_dm_atomic_check_finish(state, ret);
  
  	return ret;
  }
  
- static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
- 		unsigned int offset,
- 		unsigned int total_length,
- 		u8 *data,
- 		unsigned int length,
- 		struct amdgpu_hdmi_vsdb_info *vsdb)
- {
- 	bool res;
- 	union dmub_rb_cmd cmd;
- 	struct dmub_cmd_send_edid_cea *input;
- 	struct dmub_cmd_edid_cea_output *output;
- 
- 	if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES)
- 		return false;
- 
- 	memset(&cmd, 0, sizeof(cmd));
- 
- 	input = &cmd.edid_cea.data.input;
- 
- 	cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA;
- 	cmd.edid_cea.header.sub_type = 0;
- 	cmd.edid_cea.header.payload_bytes =
- 		sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
- 	input->offset = offset;
- 	input->length = length;
- 	input->cea_total_length = total_length;
- 	memcpy(input->payload, data, length);
- 
- 	res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
- 	if (!res) {
- 		drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n");
- 		return false;
- 	}
- 
- 	output = &cmd.edid_cea.data.output;
- 
- 	if (output->type == DMUB_CMD__EDID_CEA_ACK) {
- 		if (!output->ack.success) {
- 			drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n",
- 					output->ack.offset);
- 		}
- 	} else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) {
- 		if (!output->amd_vsdb.vsdb_found)
- 			return false;
- 
- 		vsdb->freesync_supported = output->amd_vsdb.freesync_supported;
- 		vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version;
- 		vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate;
- 		vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate;
- 		vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code;
- 	} else {
- 		drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n");
- 		return false;
- 	}
- 
- 	return true;
- }
- 
- static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	int i;
- 
- 	/* send extension block to DMCU for parsing */
- 	for (i = 0; i < len; i += 8) {
- 		bool res;
- 		int offset;
- 
- 		/* send 8 bytes a time */
- 		if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8))
- 			return false;
- 
- 		if (i+8 == len) {
- 			/* EDID block sent completed, expect result */
- 			int version, min_rate, max_rate;
- 
- 			res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate);
- 			if (res) {
- 				/* amd vsdb found */
- 				vsdb_info->freesync_supported = 1;
- 				vsdb_info->amd_vsdb_version = version;
- 				vsdb_info->min_refresh_rate_hz = min_rate;
- 				vsdb_info->max_refresh_rate_hz = max_rate;
- 				/* Not enabled on DMCU*/
- 				vsdb_info->freesync_mccs_vcp_code = 0;
- 				return true;
- 			}
- 			/* not amd vsdb */
- 			return false;
- 		}
- 
- 		/* check for ack*/
- 		res = dc_edid_parser_recv_cea_ack(dm->dc, &offset);
- 		if (!res)
- 			return false;
- 	}
- 
- 	return false;
- }
- 
- static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	int i;
- 
- 	/* send extension block to DMCU for parsing */
- 	for (i = 0; i < len; i += 8) {
- 		/* send 8 bytes a time */
- 		if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info))
- 			return false;
- 	}
- 
- 	return vsdb_info->freesync_supported;
- }
- 
- static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
- 	bool ret;
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	if (adev->dm.dmub_srv)
- 		ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
- 	else
- 		ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
- 	mutex_unlock(&adev->dm.dc_lock);
- 	return ret;
- }
- 
- static void parse_edid_displayid_vrr(struct drm_connector *connector,
- 				     const struct edid *edid)
- {
- 	u8 *edid_ext = NULL;
- 	int i;
- 	int j = 0;
- 	u16 min_vfreq;
- 	u16 max_vfreq;
- 
- 	if (!edid || !edid->extensions)
- 		return;
- 
- 	/* Find DisplayID extension */
- 	for (i = 0; i < edid->extensions; i++) {
- 		edid_ext = (void *)(edid + (i + 1));
- 		if (edid_ext[0] == DISPLAYID_EXT)
- 			break;
- 	}
- 
- 	if (i == edid->extensions)
- 		return;
- 
- 	while (j < EDID_LENGTH) {
- 		/* Get dynamic video timing range from DisplayID if available */
- 		if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25	&&
- 		    (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) {
- 			min_vfreq = edid_ext[j+9];
- 			if (edid_ext[j+1] & 7)
- 				max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8);
- 			else
- 				max_vfreq = edid_ext[j+10];
- 
- 			if (max_vfreq && min_vfreq) {
- 				connector->display_info.monitor_range.max_vfreq = max_vfreq;
- 				connector->display_info.monitor_range.min_vfreq = min_vfreq;
- 
- 				return;
- 			}
- 		}
- 		j++;
- 	}
- }
- 
- static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
- 			struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 
- 	vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
- 	vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
- 
- 	return connector->display_info.amd_vsdb.version != 0;
- }
- 
- static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
- 			       const struct edid *edid,
- 			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	u8 *edid_ext = NULL;
- 	int i;
- 	bool valid_vsdb_found = false;
- 
- 	/*----- drm_find_cea_extension() -----*/
- 	/* No EDID or EDID extensions */
- 	if (edid == NULL || edid->extensions == 0)
- 		return -ENODEV;
- 
- 	/* Find CEA extension */
- 	for (i = 0; i < edid->extensions; i++) {
- 		edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1);
- 		if (edid_ext[0] == CEA_EXT)
- 			break;
- 	}
- 
- 	if (i == edid->extensions)
- 		return -ENODEV;
- 
- 	/*----- cea_db_offsets() -----*/
- 	if (edid_ext[0] != CEA_EXT)
- 		return -ENODEV;
- 
- 	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
- 
- 	return valid_vsdb_found ? i : -ENODEV;
- }
- 
- /**
-  * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
-  *
-  * @connector: Connector to query.
-  * @drm_edid: DRM EDID from monitor
-  * @do_mccs: Controls whether MCCS (Monitor Control Command Set) over
-  *	      DDC (Display Data Channel) transactions are performed. When true,
-  *	      the driver queries the monitor to get or update additional FreeSync
-  *	      capability information. When false, these transactions are skipped.
-  *
-  * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep
-  * track of some of the display information in the internal data struct used by
-  * amdgpu_dm. This function checks which type of connector we need to set the
-  * FreeSync parameters.
-  */
- void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
- 				    const struct drm_edid *drm_edid, bool do_mccs)
- {
- 	int i = 0;
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 	struct dm_connector_state *dm_con_state = NULL;
- 	struct dc_sink *sink;
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
- 	const struct edid *edid;
- 	bool freesync_capable = false;
- 	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
- 
- 	if (!connector->state) {
- 		drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
- 		goto update;
- 	}
- 
- 	sink = amdgpu_dm_connector->dc_sink ?
- 		amdgpu_dm_connector->dc_sink :
- 		amdgpu_dm_connector->dc_em_sink;
- 
- 	drm_edid_connector_update(connector, drm_edid);
- 
- 	if (!drm_edid || !sink) {
- 		dm_con_state = to_dm_connector_state(connector->state);
- 
- 		amdgpu_dm_connector->min_vfreq = 0;
- 		amdgpu_dm_connector->max_vfreq = 0;
- 		freesync_capable = false;
- 
- 		goto update;
- 	}
- 
- 	dm_con_state = to_dm_connector_state(connector->state);
- 
- 	if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
- 		goto update;
- 
- 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
- 
- 	/* Some eDP panels only have the refresh rate range info in DisplayID */
- 	if ((connector->display_info.monitor_range.min_vfreq == 0 ||
- 	     connector->display_info.monitor_range.max_vfreq == 0))
- 		parse_edid_displayid_vrr(connector, edid);
- 
- 	if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 		     sink->sink_signal == SIGNAL_TYPE_EDP)) {
- 		if (amdgpu_dm_connector->dc_link &&
- 		    amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
- 			amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
- 			amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
- 			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 				freesync_capable = true;
- 		}
- 
- 		get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
- 
- 		if (vsdb_info.replay_mode) {
- 			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
- 			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
- 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
- 		}
- 
- 	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
- 		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- 		if (i >= 0) {
- 			amdgpu_dm_connector->vsdb_info = vsdb_info;
- 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
- 
- 			if (vsdb_info.freesync_supported) {
- 				amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- 				if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 					freesync_capable = true;
- 
- 				connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- 			}
- 		}
- 	}
- 
- 	if (amdgpu_dm_connector->dc_link)
- 		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
- 
- 	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
- 		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- 		if (i >= 0) {
- 			amdgpu_dm_connector->vsdb_info = vsdb_info;
- 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
- 
- 			if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
- 				amdgpu_dm_connector->pack_sdp_v1_3 = true;
- 				amdgpu_dm_connector->as_type = as_type;
- 
- 				amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- 				if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 					freesync_capable = true;
- 
- 				connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- 			}
- 		}
- 	}
- 
- 	/* Handle MCCS */
- 	if (do_mccs) {
- 		dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
- 
- 		if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)
- 			freesync_capable = false;
- 
- 		if (sink->mccs_caps.freesync_supported && freesync_capable)
- 			dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
- 	}
- 
- update:
- 	if (dm_con_state)
- 		dm_con_state->freesync_capable = freesync_capable;
- 
- 	if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable &&
- 	    amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) {
- 		amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false;
- 		amdgpu_dm_connector->dc_link->replay_settings.replay_feature_enabled = false;
- 	}
- 
- 	if (connector->vrr_capable_property)
- 		drm_connector_set_vrr_capable_property(connector,
- 						       freesync_capable);
- }
- 
  void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
  {
  	struct amdgpu_device *adev = drm_to_adev(dev);
@@@ -14038,12 -6598,6 +6603,6 @@@
  	mutex_unlock(&adev->dm.dc_lock);
  }
  
- static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
- {
- 	if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter)
- 		dc_exit_ips_for_hw_access(dc);
- }
- 
  void dm_write_reg_func(const struct dc_context *ctx, uint32_t address,
  		       u32 value, const char *func_name)
  {
@@@ -14072,13 -6626,6 +6631,6 @@@ uint32_t dm_read_reg_func(const struct 
  	}
  #endif
  
- 	if (ctx->dmub_srv &&
- 	    ctx->dmub_srv->reg_helper_offload.gather_in_progress &&
- 	    !ctx->dmub_srv->reg_helper_offload.should_burst_write) {
- 		ASSERT(false);
- 		return 0;
- 	}
- 
  	amdgpu_dm_exit_ips_for_hw_access(ctx->dc);
  
  	value = cgs_read_register(ctx->cgs_device, address);
@@@ -14088,179 -6635,6 +6640,6 @@@
  	return value;
  }
  
- int amdgpu_dm_process_dmub_aux_transfer_sync(
- 		struct dc_context *ctx,
- 		unsigned int link_index,
- 		struct aux_payload *payload,
- 		enum aux_return_code_type *operation_result)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 	struct dmub_notification *p_notify = adev->dm.dmub_notify;
- 	int ret = -1;
- 
- 	mutex_lock(&adev->dm.dpia_aux_lock);
- 	if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) {
- 		*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
- 		goto out;
- 	}
- 
- 	if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
- 		drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
- 		*operation_result = AUX_RET_ERROR_TIMEOUT;
- 		goto out;
- 	}
- 
- 	if (p_notify->result != AUX_RET_SUCCESS) {
- 		/*
- 		 * Transient states before tunneling is enabled could
- 		 * lead to this error. We can ignore this for now.
- 		 */
- 		if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) {
- 			drm_warn(adev_to_drm(adev), "DPIA AUX failed on 0x%x(%d), error %d\n",
- 					payload->address, payload->length,
- 					p_notify->result);
- 		}
- 		*operation_result = p_notify->result;
- 		goto out;
- 	}
- 
- 	payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF;
- 	if (adev->dm.dmub_notify->aux_reply.command & 0xF0)
- 		/* The reply is stored in the top nibble of the command. */
- 		payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF;
- 
- 	/*write req may receive a byte indicating partially written number as well*/
- 	if (p_notify->aux_reply.length)
- 		memcpy(payload->data, p_notify->aux_reply.data,
- 				p_notify->aux_reply.length);
- 
- 	/* success */
- 	ret = p_notify->aux_reply.length;
- 	*operation_result = p_notify->result;
- out:
- 	reinit_completion(&adev->dm.dmub_aux_transfer_done);
- 	mutex_unlock(&adev->dm.dpia_aux_lock);
- 	return ret;
- }
- 
- static void abort_fused_io(
- 		struct dc_context *ctx,
- 		const struct dmub_cmd_fused_request *request
- )
- {
- 	union dmub_rb_cmd command = { 0 };
- 	struct dmub_rb_cmd_fused_io *io = &command.fused_io;
- 
- 	io->header.type = DMUB_CMD__FUSED_IO;
- 	io->header.sub_type = DMUB_CMD__FUSED_IO_ABORT;
- 	io->header.payload_bytes = sizeof(*io) - sizeof(io->header);
- 	io->request = *request;
- 	dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT);
- }
- 
- static bool execute_fused_io(
- 		struct amdgpu_device *dev,
- 		struct dc_context *ctx,
- 		union dmub_rb_cmd *commands,
- 		uint8_t count,
- 		uint32_t timeout_us
- )
- {
- 	const uint8_t ddc_line = commands[0].fused_io.request.u.aux.ddc_line;
- 
- 	if (ddc_line >= ARRAY_SIZE(dev->dm.fused_io))
- 		return false;
- 
- 	struct fused_io_sync *sync = &dev->dm.fused_io[ddc_line];
- 	struct dmub_rb_cmd_fused_io *first = &commands[0].fused_io;
- 	const bool result = dm_execute_dmub_cmd_list(ctx, count, commands, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
- 			&& first->header.ret_status
- 			&& first->request.status == FUSED_REQUEST_STATUS_SUCCESS;
- 
- 	if (!result)
- 		return false;
- 
- 	while (wait_for_completion_timeout(&sync->replied, usecs_to_jiffies(timeout_us))) {
- 		reinit_completion(&sync->replied);
- 
- 		struct dmub_cmd_fused_request *reply = (struct dmub_cmd_fused_request *) sync->reply_data;
- 
- 		static_assert(sizeof(*reply) <= sizeof(sync->reply_data), "Size mismatch");
- 
- 		if (reply->identifier == first->request.identifier) {
- 			first->request = *reply;
- 			return true;
- 		}
- 	}
- 
- 	reinit_completion(&sync->replied);
- 	first->request.status = FUSED_REQUEST_STATUS_TIMEOUT;
- 	abort_fused_io(ctx, &first->request);
- 	return false;
- }
- 
- bool amdgpu_dm_execute_fused_io(
- 		struct amdgpu_device *dev,
- 		struct dc_link *link,
- 		union dmub_rb_cmd *commands,
- 		uint8_t count,
- 		uint32_t timeout_us)
- {
- 	struct amdgpu_display_manager *dm = &dev->dm;
- 
- 	mutex_lock(&dm->dpia_aux_lock);
- 
- 	const bool result = execute_fused_io(dev, link->ctx, commands, count, timeout_us);
- 
- 	mutex_unlock(&dm->dpia_aux_lock);
- 	return result;
- }
- 
- int amdgpu_dm_process_dmub_set_config_sync(
- 		struct dc_context *ctx,
- 		unsigned int link_index,
- 		struct set_config_cmd_payload *payload,
- 		enum set_config_status *operation_result)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 	bool is_cmd_complete;
- 	int ret;
- 
- 	mutex_lock(&adev->dm.dpia_aux_lock);
- 	is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc,
- 			link_index, payload, adev->dm.dmub_notify);
- 
- 	if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
- 		ret = 0;
- 		*operation_result = adev->dm.dmub_notify->sc_status;
- 	} else {
- 		drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
- 		ret = -1;
- 		*operation_result = SET_CONFIG_UNKNOWN_ERROR;
- 	}
- 
- 	if (!is_cmd_complete)
- 		reinit_completion(&adev->dm.dmub_aux_transfer_done);
- 	mutex_unlock(&adev->dm.dpia_aux_lock);
- 	return ret;
- }
- 
- bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 
- 	guard(spinlock_irqsave)(&adev->dm.dmub_lock);
- 	return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
- }
- 
- bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 
- 	guard(spinlock_irqsave)(&adev->dm.dmub_lock);
- 	return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type);
- }
- 
  void dm_acpi_process_phy_transition_interlock(
  	const struct dc_context *ctx,
  	struct dm_process_phy_transition_init_params process_phy_transition_init_params)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-08-03 14:31 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-08-03 14:31 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Matt Roper,
	Rodrigo Vivi, Satyanarayana K V P, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 15807 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_pci.c

between commit:

  130910bac905a ("drm/xe/pf: Disable display in admin only PF mode")

from the origin tree and commits:

  7ef55ae582eba ("drm/xe/pf: Disable display in admin only PF mode")
  b623bd790db04 ("drm/xe: Drop 'force_execlist' module parameter")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

Again, please consider not doing cherry picking as a matter of such
routine.

diff --combined drivers/gpu/drm/xe/xe_pci.c
index 9cd873708136c,5f2a0b19839d1..0000000000000
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@@ -22,10 -22,12 +22,12 @@@
  #include "xe_device.h"
  #include "xe_drv.h"
  #include "xe_gt.h"
+ #include "xe_gt_printk.h"
  #include "xe_gt_sriov_vf.h"
  #include "xe_guc.h"
  #include "xe_mmio.h"
  #include "xe_module.h"
+ #include "xe_pci_error.h"
  #include "xe_pci_rebar.h"
  #include "xe_pci_sriov.h"
  #include "xe_pci_types.h"
@@@ -35,6 -37,7 +37,7 @@@
  #include "xe_step.h"
  #include "xe_survivability_mode.h"
  #include "xe_tile.h"
+ #include "xe_tile_printk.h"
  
  enum toggle_d3cold {
  	D3COLD_DISABLE,
@@@ -119,6 -122,7 +122,7 @@@ static const struct xe_graphics_desc gr
  static const struct xe_graphics_desc graphics_xe3p_lpg = {
  	XE2_GFX_FEATURES,
  	.has_indirect_ring_state = 1,
+ 	.has_uncorrectable_error_reporting = 1,
  	.multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE),
  	.num_geometry_xecore_fuse_regs = 3,
  	.num_compute_xecore_fuse_regs = 3,
@@@ -128,6 -132,7 +132,7 @@@ static const struct xe_graphics_desc gr
  	XE2_GFX_FEATURES,
  	.has_access_counter = 0,
  	.has_indirect_ring_state = 1,
+ 	.has_uncorrectable_error_reporting = 1,
  	.hw_engine_mask =
  		GENMASK(XE_HW_ENGINE_BCS8, XE_HW_ENGINE_BCS1) |
  		GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0),
@@@ -150,6 -155,14 +155,14 @@@ static const struct xe_media_desc media
  		BIT(XE_HW_ENGINE_GSCCS0)
  };
  
+ static const struct xe_media_desc media_xe3p_hpm = {
+ 	.has_uncorrectable_error_reporting = 1,
+ 	.hw_engine_mask =
+ 		GENMASK(XE_HW_ENGINE_VCS7, XE_HW_ENGINE_VCS0) |
+ 		GENMASK(XE_HW_ENGINE_VECS3, XE_HW_ENGINE_VECS0) |
+ 		BIT(XE_HW_ENGINE_GSCCS0)
+ };
+ 
  /* Pre-GMDID Graphics IPs */
  static const struct xe_ip graphics_ip_xelp = { 1200, "Xe_LP", &graphics_xelp };
  static const struct xe_ip graphics_ip_xelpp = { 1210, "Xe_LP+", &graphics_xelp };
@@@ -185,7 -198,7 +198,7 @@@ static const struct xe_ip media_ips[] 
  	{ 3000, "Xe3_LPM", &media_xelpmp },
  	{ 3002, "Xe3_LPM", &media_xelpmp },
  	{ 3500, "Xe3p_LPM", &media_xelpmp },
- 	{ 3503, "Xe3p_HPM", &media_xelpmp },
+ 	{ 3503, "Xe3p_HPM", &media_xe3p_hpm },
  };
  
  #define MULTI_LRC_MASK \
@@@ -355,6 -368,7 +368,7 @@@ static const __maybe_unused struct xe_d
  	PLATFORM(PVC),
  	.dma_mask_size = 52,
  	.has_display = false,
+ 	.has_drm_ras = true,
  	.has_gsc_nvm = 1,
  	.has_heci_gscfi = 1,
  	.max_gt_per_tile = 1,
@@@ -447,7 -461,6 +461,6 @@@ static const struct xe_device_desc nvls
  	.has_sriov = true,
  	.max_gt_per_tile = 2,
  	MULTI_LRC_MASK,
- 	.require_force_probe = true,
  	.va_bits = 48,
  	.vm_max_level = 4,
  };
@@@ -457,6 -470,7 +470,7 @@@ static const struct xe_device_desc cri_
  	PLATFORM(CRESCENTISLAND),
  	.dma_mask_size = 52,
  	.has_display = false,
+ 	.has_drm_ras = true,
  	.has_flat_ccs = false,
  	.has_gsc_nvm = 1,
  	.has_i2c = true,
@@@ -599,8 -613,6 +613,6 @@@ static int read_gmdid(struct xe_device 
  	struct xe_reg gmdid_reg = GMD_ID;
  	u32 val;
  
- 	KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid);
- 
  	if (IS_SRIOV_VF(xe)) {
  		/*
  		 * To get the value of the GMDID register, VFs must obtain it
@@@ -726,14 -738,30 +738,30 @@@ static int handle_gmdid(struct xe_devic
  	return 0;
  }
  
- static void init_devid(struct xe_device *xe)
+ struct xe_probed_info {
+ 	u16 devid;
+ 	u8 revid;
+ 	u8 tile_count;
+ 	struct xe_step_info step;
+ 	const struct xe_ip *graphics_ip;
+ 	const struct xe_ip *media_ip;
+ };
+ 
+ /*
+  * Probe from the hardware the info required by xe_info_init_early().
+  */
+ static int xe_probe_info_early(struct xe_device *xe,
+ 			       const struct xe_device_desc *desc,
+ 			       struct xe_probed_info *probed_info)
  {
  	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
  
- 	KUNIT_STATIC_STUB_REDIRECT(init_devid, xe);
+ 	probed_info->devid = pdev->device;
+ 	probed_info->revid = pdev->revision;
  
- 	xe->info.devid = pdev->device;
- 	xe->info.revid = pdev->revision;
+ 	xe_step_platform_get(desc->platform, probed_info->revid, &probed_info->step);
+ 
+ 	return 0;
  }
  
  /*
@@@ -742,17 -770,20 +770,20 @@@
   */
  static int xe_info_init_early(struct xe_device *xe,
  			      const struct xe_device_desc *desc,
- 			      const struct xe_subplatform_desc *subplatform_desc)
+ 			      const struct xe_subplatform_desc *subplatform_desc,
+ 			      struct xe_probed_info *probed_info)
  {
  	int err;
  
+ 	xe->info.devid = probed_info->devid;
+ 	xe->info.revid = probed_info->revid;
+ 	xe->info.step.platform = probed_info->step.platform;
+ 
  	xe->info.platform_name = desc->platform_name;
  	xe->info.platform = desc->platform;
  	xe->info.subplatform = subplatform_desc ?
  		subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
  
- 	init_devid(xe);
- 
  	xe->info.dma_mask_size = desc->dma_mask_size;
  	xe->info.va_bits = desc->va_bits;
  	xe->info.vm_max_level = desc->vm_max_level;
@@@ -760,6 -791,7 +791,7 @@@
  
  	xe->info.is_dgfx = desc->is_dgfx;
  	xe->info.has_cached_pt = desc->has_cached_pt;
+ 	xe->info.has_drm_ras = desc->has_drm_ras;
  	xe->info.has_fan_control = desc->has_fan_control;
  	/* runtime fusing may force flat_ccs to disabled later */
  	xe->info.has_flat_ccs = desc->has_flat_ccs;
@@@ -790,14 -822,10 +822,10 @@@
  				 xe_modparam.probe_display &&
  				 desc->has_display &&
  				 !xe_device_is_admin_only(xe);
- 	xe->info.force_execlist = xe_modparam.force_execlist;
  
  	xe_assert(xe, desc->max_gt_per_tile > 0);
  	xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE);
  	xe->info.max_gt_per_tile = desc->max_gt_per_tile;
- 	xe->info.tile_count = 1 + desc->max_remote_tiles;
- 
- 	xe_step_platform_get(xe);
  
  	err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0);
  	if (err)
@@@ -806,22 -834,21 +834,21 @@@
  	return 0;
  }
  
- /*
-  * Possibly override number of tile based on configuration register.
-  */
- static void xe_info_probe_tile_count(struct xe_device *xe)
+ static void xe_probe_tile_count(struct xe_device *xe,
+ 				const struct xe_device_desc *desc,
+ 				struct xe_probed_info *probed_info)
  {
  	struct xe_mmio *mmio;
  	u8 tile_count;
  	u32 mtcfg;
  
- 	KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe);
+ 	probed_info->tile_count = 1 + desc->max_remote_tiles;
  
  	/*
  	 * Probe for tile count only for platforms that support multiple
  	 * tiles.
  	 */
- 	if (xe->info.tile_count == 1)
+ 	if (probed_info->tile_count == 1)
  		return;
  
  	mmio = xe_root_tile_mmio(xe);
@@@ -834,10 -861,10 +861,10 @@@
  	mtcfg = xe_mmio_read32(mmio, XEHP_MTCFG_ADDR);
  	tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1;
  
- 	if (tile_count < xe->info.tile_count) {
+ 	if (tile_count < probed_info->tile_count) {
  		drm_info(&xe->drm, "tile_count: %d, reduced_tile_count %d\n",
- 			 xe->info.tile_count, tile_count);
- 		xe->info.tile_count = tile_count;
+ 			 probed_info->tile_count, tile_count);
+ 		probed_info->tile_count = tile_count;
  	}
  }
  
@@@ -849,7 -876,7 +876,7 @@@ static struct xe_gt *alloc_primary_gt(s
  	struct xe_gt *gt;
  
  	if (!xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev))) {
- 		xe_info(xe, "Primary GT disabled via configfs\n");
+ 		xe_tile_info(tile, "Primary GT disabled via configfs\n");
  		return NULL;
  	}
  
@@@ -860,7 -887,13 +887,13 @@@
  	gt->info.type = XE_GT_TYPE_MAIN;
  	gt->info.id = tile->id * xe->info.max_gt_per_tile;
  	gt->info.has_indirect_ring_state = graphics_desc->has_indirect_ring_state;
+ 	gt->info.has_uncorrectable_error_reporting =
+ 		graphics_desc->has_uncorrectable_error_reporting;
  	gt->info.multi_queue_engine_class_mask = graphics_desc->multi_queue_engine_class_mask;
+ 	if (!xe_configfs_get_enable_multi_queue(to_pci_dev(xe->drm.dev))) {
+ 		xe_gt_info(gt, "Multi-queue disabled via configfs\n");
+ 		gt->info.multi_queue_engine_class_mask = 0;
+ 	}
  	gt->info.engine_mask = graphics_desc->hw_engine_mask;
  	gt->info.num_geometry_xecore_fuse_regs = graphics_desc->num_geometry_xecore_fuse_regs;
  	gt->info.num_compute_xecore_fuse_regs = graphics_desc->num_compute_xecore_fuse_regs;
@@@ -891,7 -924,7 +924,7 @@@ static struct xe_gt *alloc_media_gt(str
  	struct xe_gt *gt;
  
  	if (!xe_configfs_media_gt_allowed(to_pci_dev(xe->drm.dev))) {
- 		xe_info(xe, "Media GT disabled via configfs\n");
+ 		xe_tile_info(tile, "Media GT disabled via configfs\n");
  		return NULL;
  	}
  
@@@ -905,11 -938,70 +938,70 @@@
  	gt->info.type = XE_GT_TYPE_MEDIA;
  	gt->info.id = tile->id * xe->info.max_gt_per_tile + 1;
  	gt->info.has_indirect_ring_state = media_desc->has_indirect_ring_state;
+ 	gt->info.has_uncorrectable_error_reporting = media_desc->has_uncorrectable_error_reporting;
  	gt->info.engine_mask = media_desc->hw_engine_mask;
  
  	return gt;
  }
  
+ static int xe_probe_ips(struct xe_device *xe,
+ 			const struct xe_device_desc *desc,
+ 			struct xe_probed_info *probed_info)
+ {
+ 	/*
+ 	 * If this platform supports GMD_ID, we'll detect the proper IP
+ 	 * descriptor to use from hardware registers.
+ 	 * desc->pre_gmdid_graphics_ip will only ever be set at this point for
+ 	 * platforms before GMD_ID. In that case the IP descriptions and
+ 	 * versions are simply derived from that.
+ 	 */
+ 	if (desc->pre_gmdid_graphics_ip) {
+ 		probed_info->graphics_ip = desc->pre_gmdid_graphics_ip;
+ 		probed_info->media_ip = desc->pre_gmdid_media_ip;
+ 		xe_step_pre_gmdid_get(xe, &probed_info->step);
+ 	} else {
+ 		int err;
+ 		u32 graphics_revid, media_revid;
+ 
+ 		xe_assert(xe, !desc->pre_gmdid_media_ip);
+ 
+ 		err = handle_gmdid(xe, &probed_info->graphics_ip, &probed_info->media_ip,
+ 				   &graphics_revid, &media_revid);
+ 		if (err)
+ 			return err;
+ 
+ 		xe_step_gmdid_get(xe, graphics_revid, media_revid, &probed_info->step);
+ 	}
+ 
+ 	/*
+ 	 * If we couldn't detect the graphics IP, that's considered a fatal
+ 	 * error and we should abort driver load.  Failing to detect media
+ 	 * IP is non-fatal; we'll just proceed without enabling media support.
+ 	 */
+ 	if (!probed_info->graphics_ip)
+ 		return -ENODEV;
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Probe from the hardware the info required by xe_info_init().
+  */
+ static int xe_probe_info(struct xe_device *xe,
+ 			 const struct xe_device_desc *desc,
+ 			 struct xe_probed_info *probed_info)
+ {
+ 	int err;
+ 
+ 	xe_probe_tile_count(xe, desc, probed_info);
+ 
+ 	err = xe_probe_ips(xe, desc, probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	return 0;
+ }
+ 
  /*
   * Initialize device info content that does require knowledge about
   * graphics / media IP version.
@@@ -917,46 -1009,24 +1009,24 @@@
   * present in device info.
   */
  static int xe_info_init(struct xe_device *xe,
- 			const struct xe_device_desc *desc)
+ 			const struct xe_device_desc *desc,
+ 			struct xe_probed_info *probed_info)
  {
- 	u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0;
  	const struct xe_ip *graphics_ip;
  	const struct xe_ip *media_ip;
  	const struct xe_graphics_desc *graphics_desc;
  	const struct xe_media_desc *media_desc;
  	struct xe_tile *tile;
  	struct xe_gt *gt;
- 	int ret;
  	u8 id;
  
- 	/*
- 	 * If this platform supports GMD_ID, we'll detect the proper IP
- 	 * descriptor to use from hardware registers.
- 	 * desc->pre_gmdid_graphics_ip will only ever be set at this point for
- 	 * platforms before GMD_ID. In that case the IP descriptions and
- 	 * versions are simply derived from that.
- 	 */
- 	if (desc->pre_gmdid_graphics_ip) {
- 		graphics_ip = desc->pre_gmdid_graphics_ip;
- 		media_ip = desc->pre_gmdid_media_ip;
- 		xe_step_pre_gmdid_get(xe);
- 	} else {
- 		xe_assert(xe, !desc->pre_gmdid_media_ip);
- 		ret = handle_gmdid(xe, &graphics_ip, &media_ip,
- 				   &graphics_gmdid_revid, &media_gmdid_revid);
- 		if (ret)
- 			return ret;
+ 	graphics_ip = probed_info->graphics_ip;
+ 	media_ip = probed_info->media_ip;
  
- 		xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid);
- 	}
- 
- 	/*
- 	 * If we couldn't detect the graphics IP, that's considered a fatal
- 	 * error and we should abort driver load.  Failing to detect media
- 	 * IP is non-fatal; we'll just proceed without enabling media support.
- 	 */
- 	if (!graphics_ip)
- 		return -ENODEV;
+ 	xe->info.tile_count = probed_info->tile_count;
+ 	xe->info.step.basedie = probed_info->step.basedie;
+ 	xe->info.step.graphics = probed_info->step.graphics;
+ 	xe->info.step.media = probed_info->step.media;
  
  	xe->info.graphics_verx100 = graphics_ip->verx100;
  	xe->info.graphics_name = graphics_ip->name;
@@@ -989,8 -1059,6 +1059,6 @@@
  		xe->info.has_soc_remapper_telem = 0;
  	}
  
- 	xe_info_probe_tile_count(xe);
- 
  	for_each_remote_tile(tile, xe, id) {
  		int err;
  
@@@ -1079,9 -1147,11 +1147,11 @@@ static void xe_pci_remove(struct pci_de
   */
  static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
+ 	struct xe_probed_info probed_info = {};
  	const struct xe_device_desc *desc = (const void *)ent->driver_data;
  	const struct xe_subplatform_desc *subplatform_desc;
  	struct xe_device *xe;
+ 	void *group;
  	int err;
  
  	subplatform_desc = find_subplatform(desc, pdev->device);
@@@ -1109,6 -1179,11 +1179,11 @@@
  	if (xe_display_driver_probe_defer(pdev))
  		return -EPROBE_DEFER;
  
+ 	/* Group all devres so xe_pci_error_slot_reset() can release them as a unit. */
+ 	group = devres_open_group(&pdev->dev, NULL, GFP_KERNEL);
+ 	if (!group)
+ 		return -ENOMEM;
+ 
  	err = pcim_enable_device(pdev);
  	if (err)
  		return err;
@@@ -1117,13 -1192,19 +1192,19 @@@
  	if (IS_ERR(xe))
  		return PTR_ERR(xe);
  
+ 	xe->devres_group = group;
+ 
  	pci_set_drvdata(pdev, &xe->drm);
  
  	xe_pm_assert_unbounded_bridge(xe);
  
  	pci_set_master(pdev);
  
- 	err = xe_info_init_early(xe, desc, subplatform_desc);
+ 	err = xe_probe_info_early(xe, desc, &probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	err = xe_info_init_early(xe, desc, subplatform_desc, &probed_info);
  	if (err)
  		return err;
  
@@@ -1142,7 -1223,11 +1223,11 @@@
  	if (err)
  		return err;
  
- 	err = xe_info_init(xe, desc);
+ 	err = xe_probe_info(xe, desc, &probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	err = xe_info_init(xe, desc, &probed_info);
  	if (err)
  		return err;
  
@@@ -1355,6 -1440,7 +1440,7 @@@ static struct pci_driver xe_pci_driver 
  	.remove = xe_pci_remove,
  	.shutdown = xe_pci_shutdown,
  	.sriov_configure = xe_pci_sriov_configure,
+ 	.err_handler = &xe_pci_error_handlers,
  #ifdef CONFIG_PM_SLEEP
  	.driver.pm = &xe_pm_ops,
  #endif

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-08-03 14:31 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-08-03 14:31 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Boris Brezillon, Laura Nao, Linux Kernel Mailing List,
	Linux Next Mailing List, Rodrigo Vivi, Satyanarayana K V P,
	Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 5056 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_device.c

between commit:

  130910bac905a ("drm/xe/pf: Disable display in admin only PF mode")

from the origin tree and commits:

  7ef55ae582eba ("drm/xe/pf: Disable display in admin only PF mode")
  21fcb222f0d1e ("drm: Remove DRIVER_GEM_GPUVA feature flag")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

*Please* consider using merges rather than cherry picking.

diff --combined drivers/gpu/drm/xe/xe_device.c
index 9d119c95a569a,7007b6113760a..0000000000000
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@@ -61,6 -61,7 +61,7 @@@
  #include "xe_psmi.h"
  #include "xe_pxp.h"
  #include "xe_query.h"
+ #include "xe_ras.h"
  #include "xe_shrinker.h"
  #include "xe_soc_remapper.h"
  #include "xe_survivability_mode.h"
@@@ -281,7 -282,7 +282,7 @@@ static vm_fault_t barrier_fault(struct 
  	pgprot_t prot;
  	int idx;
  
 -	prot = vm_get_page_prot(vma->vm_flags);
 +	prot = vma_get_page_prot(vma);
  
  	if (drm_dev_enter(dev, &idx)) {
  		unsigned long pfn;
@@@ -396,7 -397,7 +397,7 @@@ static const struct drm_driver regular_
  	    XE_DISPLAY_DRIVER_FEATURES |
  	    DRIVER_GEM |
  	    DRIVER_RENDER | DRIVER_SYNCOBJ |
- 	    DRIVER_SYNCOBJ_TIMELINE | DRIVER_GEM_GPUVA,
+ 	    DRIVER_SYNCOBJ_TIMELINE,
  	.open = xe_file_open,
  	.postclose = xe_file_close,
  
@@@ -426,7 -427,7 +427,7 @@@ static const struct drm_ioctl_desc xe_i
  
  static const struct drm_driver admin_only_driver = {
  	.driver_features =
- 	    DRIVER_GEM | DRIVER_RENDER | DRIVER_GEM_GPUVA,
+ 	    DRIVER_GEM | DRIVER_RENDER,
  	.open = xe_file_open,
  	.postclose = xe_file_close,
  	.ioctls = xe_ioctls_admin_only,
@@@ -736,9 -737,11 +737,11 @@@ static void vf_update_device_info(struc
  	xe->info.probe_display = 0;
  	xe->info.has_heci_cscfi = 0;
  	xe->info.has_heci_gscfi = 0;
+ 	xe->info.has_i2c = 0;
  	xe->info.has_late_bind = 0;
  	xe->info.skip_guc_pc = 1;
  	xe->info.skip_pcode = 1;
+ 	xe->info.has_drm_ras = false;
  }
  
  static int xe_device_vram_alloc(struct xe_device *xe)
@@@ -918,6 -921,27 +921,27 @@@ static void xe_device_wedged_fini(struc
  		xe_pm_runtime_put(xe);
  }
  
+ #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
+ static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
+ {
+ 	int err;
+ 
+ 	err = drmm_mutex_init(&xe->drm, &xe->page_size_alloc_ctrl.lock);
+ 	if (err)
+ 		return err;
+ 
+ 	xe->page_size_alloc_ctrl.mode = XE_PAGE_SIZE_ALLOC_CTRL_MODE_NONE;
+ 	xe->page_size_alloc_ctrl.cur_index = 0;
+ 
+ 	return 0;
+ }
+ #else
+ static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
+ {
+ 	return 0;
+ }
+ #endif
+ 
  int xe_device_probe(struct xe_device *xe)
  {
  	struct xe_tile *tile;
@@@ -947,6 -971,15 +971,15 @@@
  			return err;
  	}
  
+ 	/*
+ 	 * Wa_16029380221: The affected GT will always use non-coherent
+ 	 * access to page tables, so we must do uncached writes from the
+ 	 * CPU.
+ 	 */
+ 	for_each_gt(gt, xe, id)
+ 		if (XE_GT_WA(gt, 16029380221))
+ 			xe->info.has_cached_pt = false;
+ 
  	for_each_tile(tile, xe, id) {
  		err = xe_ggtt_init_early(tile->mem.ggtt);
  		if (err)
@@@ -987,6 -1020,16 +1020,16 @@@
  	if (err)
  		return err;
  
+ 	err = xe_soc_remapper_init(xe);
+ 	if (err)
+ 		return err;
+ 
+ 	err = xe_sysctrl_init(xe);
+ 	if (err)
+ 		return err;
+ 
+ 	xe_ras_init(xe);
+ 
  	/*
  	 * Now that GT is initialized (TTM in particular),
  	 * we can try to init display, and inherit the initial fb.
@@@ -1027,10 -1070,6 +1070,6 @@@
  
  	xe_nvm_init(xe);
  
- 	err = xe_soc_remapper_init(xe);
- 	if (err)
- 		return err;
- 
  	err = xe_heci_gsc_init(xe);
  	if (err)
  		return err;
@@@ -1055,6 -1094,10 +1094,10 @@@
  	if (err)
  		return err;
  
+ 	err = xe_debug_page_size_alloc_ctrl_init(xe);
+ 	if (err)
+ 		return err;
+ 
  	err = drm_dev_register(&xe->drm, 0);
  	if (err)
  		return err;
@@@ -1069,10 -1112,6 +1112,6 @@@
  	if (err)
  		goto err_unregister_display;
  
- 	err = xe_sysctrl_init(xe);
- 	if (err)
- 		goto err_unregister_display;
- 
  	err = xe_device_sysfs_init(xe);
  	if (err)
  		goto err_unregister_display;
@@@ -1127,14 -1166,14 +1166,14 @@@ void xe_device_shutdown(struct xe_devic
  
  	drm_dbg(&xe->drm, "Shutting down device\n");
  
- 	xe_display_pm_shutdown(xe);
+ 	xe_display_shutdown(xe);
  
  	xe_irq_suspend(xe);
  
  	for_each_gt(gt, xe, id)
  		xe_gt_shutdown(gt);
  
- 	xe_display_pm_shutdown_late(xe);
+ 	xe_display_shutdown_late(xe);
  
  	if (!xe_driver_flr_disabled(xe)) {
  		/* BOOM! */

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-07-31 14:01 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-07-31 14:01 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Linux Kernel Mailing List, Linux Next Mailing List,
	Shahyan Soltani, Srinivasan Shanmugam

[-- Attachment #1: Type: text/plain, Size: 6467 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c

between commit:

  04cc4aa3617b0 ("drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid()")

from the origin tree and commit:

  b0ae60ea3f3f1 ("drm/amdgpu: Resolve VM through DRM PASID ownership")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index dc6a9d7dd0b28,aac8ace9d7a63..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@@ -2506,14 -2506,16 +2506,16 @@@ amdgpu_vm_get_task_info_vm(struct amdgp
  struct amdgpu_task_info *
  amdgpu_vm_get_task_info_pasid(struct amdgpu_device *adev, u32 pasid)
  {
+ 	struct amdgpu_fpriv *fpriv;
  	struct amdgpu_task_info *ti;
  	struct amdgpu_vm *vm;
  	unsigned long flags;
  
- 	xa_lock_irqsave(&adev->vm_manager.pasids, flags);
- 	vm = xa_load(&adev->vm_manager.pasids, pasid);
+ 	amdgpu_pasid_lock(&flags);
+ 	fpriv = amdgpu_pasid_get_fpriv_locked(pasid);
+ 	vm = fpriv ? &fpriv->vm : NULL;
  	ti = amdgpu_vm_get_task_info_vm(vm);
- 	xa_unlock_irqrestore(&adev->vm_manager.pasids, flags);
+ 	amdgpu_pasid_unlock(flags);
  
  	return ti;
  }
@@@ -2554,7 -2556,6 +2556,6 @@@ void amdgpu_vm_set_task_info(struct amd
   * @adev: amdgpu_device pointer
   * @vm: requested vm
   * @xcp_id: GPU partition selection id
-  * @pasid: the pasid the VM is using on this GPU
   *
   * Init @vm fields.
   *
@@@ -2562,7 -2563,7 +2563,7 @@@
   * 0 for success, error for failure.
   */
  int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
- 		   int32_t xcp_id, uint32_t pasid)
+ 		   int32_t xcp_id)
  {
  	struct amdgpu_bo *root_bo;
  	struct amdgpu_bo_vm *root;
@@@ -2637,26 -2638,12 +2638,12 @@@
  	if (r)
  		dev_dbg(adev->dev, "Failed to create task info for VM\n");
  
- 	/* Store new PASID in XArray (if non-zero) */
- 	if (pasid != 0) {
- 		r = xa_err(xa_store_irq(&adev->vm_manager.pasids, pasid, vm, GFP_KERNEL));
- 		if (r < 0)
- 			goto error_free_root;
- 
- 		vm->pasid = pasid;
- 	}
- 
  	amdgpu_bo_unreserve(vm->root.bo);
  	amdgpu_bo_unref(&root_bo);
  
  	return 0;
  
  error_free_root:
- 	/* If PASID was partially set, erase it from XArray before failing */
- 	if (vm->pasid != 0) {
- 		xa_erase_irq(&adev->vm_manager.pasids, vm->pasid);
- 		vm->pasid = 0;
- 	}
  	amdgpu_vm_pt_free_root(adev, vm);
  	amdgpu_bo_unreserve(vm->root.bo);
  	amdgpu_bo_unref(&root_bo);
@@@ -2763,11 -2750,6 +2750,6 @@@ void amdgpu_vm_fini(struct amdgpu_devic
  
  	root = amdgpu_bo_ref(vm->root.bo);
  	amdgpu_bo_reserve(root, true);
- 	/* Remove PASID mapping before destroying VM */
- 	if (vm->pasid != 0) {
- 		xa_erase_irq(&adev->vm_manager.pasids, vm->pasid);
- 		vm->pasid = 0;
- 	}
  	dma_fence_wait(vm->last_unlocked, false);
  	dma_fence_put(vm->last_unlocked);
  	dma_fence_wait(vm->last_tlb_flush, false);
@@@ -2863,8 -2845,6 +2845,6 @@@ void amdgpu_vm_manager_init(struct amdg
  #else
  	adev->vm_manager.vm_update_mode = 0;
  #endif
- 
- 	xa_init_flags(&adev->vm_manager.pasids, XA_FLAGS_LOCK_IRQ);
  }
  
  /**
@@@ -2876,9 -2856,6 +2856,6 @@@
   */
  void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
  {
- 	WARN_ON(!xa_empty(&adev->vm_manager.pasids));
- 	xa_destroy(&adev->vm_manager.pasids);
- 
  	amdgpu_vmid_mgr_fini(adev);
  	amdgpu_pasid_mgr_cleanup();
  }
@@@ -2935,14 -2912,16 +2912,16 @@@ struct amdgpu_vm *amdgpu_vm_lock_by_pas
  					  u32 pasid, struct drm_exec *exec)
  {
  	unsigned long irqflags;
+ 	struct amdgpu_fpriv *fpriv;
  	struct amdgpu_bo *root;
  	struct amdgpu_vm *vm;
  	int r;
  
- 	xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
- 	vm = xa_load(&adev->vm_manager.pasids, pasid);
- 	root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
- 	xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
+ 	amdgpu_pasid_lock(&irqflags);
+ 	fpriv = amdgpu_pasid_get_fpriv_locked(pasid);
+ 	vm = fpriv ? &fpriv->vm : NULL;
+ 	root = vm && vm->root.bo ? amdgpu_bo_ref(vm->root.bo) : NULL;
+ 	amdgpu_pasid_unlock(irqflags);
  
  	if (!root)
  		return NULL;
@@@ -2954,11 -2933,17 +2933,17 @@@
  	}
  
  	/* Double check that the VM still exists */
- 	xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
- 	vm = xa_load(&adev->vm_manager.pasids, pasid);
- 	if (vm && vm->root.bo != root)
+ 	amdgpu_pasid_lock(&irqflags);
+ 	fpriv = amdgpu_pasid_get_fpriv_locked(pasid);
+ 	if (!fpriv) {
  		vm = NULL;
- 	xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
+ 	} else {
+ 		vm = &fpriv->vm;
+ 		if (vm->root.bo != root)
+ 			vm = NULL;
+ 	}
+ 	amdgpu_pasid_unlock(irqflags);
+ 
  	if (!vm) {
  		drm_exec_unlock_obj(exec, &root->tbo.base);
  		amdgpu_bo_unref(&root);
@@@ -3010,8 -2995,6 +2995,8 @@@ bool amdgpu_vm_handle_fault(struct amdg
  	is_compute_context = vm->is_compute_context;
  
  	if (is_compute_context) {
 +		__label__ drm_exec_retry;
 +
  		/* Release the root PD lock since svm_range_restore_pages
  		 * might try to take it.
  		 * TODO: rework svm_range_restore_pages so that this isn't
@@@ -3157,12 -3140,14 +3142,14 @@@ void amdgpu_vm_update_fault_cache(struc
  				  uint32_t status,
  				  unsigned int vmhub)
  {
+ 	struct amdgpu_fpriv *fpriv;
  	struct amdgpu_vm *vm;
  	unsigned long flags;
  
- 	xa_lock_irqsave(&adev->vm_manager.pasids, flags);
+ 	amdgpu_pasid_lock(&flags);
  
- 	vm = xa_load(&adev->vm_manager.pasids, pasid);
+ 	fpriv = amdgpu_pasid_get_fpriv_locked(pasid);
+ 	vm = fpriv ? &fpriv->vm : NULL;
  	/* Don't update the fault cache if status is 0.  In the multiple
  	 * fault case, subsequent faults will return a 0 status which is
  	 * useless for userspace and replaces the useful fault status, so
@@@ -3195,7 -3180,7 +3182,7 @@@
  			WARN_ONCE(1, "Invalid vmhub %u\n", vmhub);
  		}
  	}
- 	xa_unlock_irqrestore(&adev->vm_manager.pasids, flags);
+ 	amdgpu_pasid_unlock(flags);
  }
  
  void amdgpu_vm_print_task_info(struct amdgpu_device *adev,

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-07-20 14:44 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-07-20 14:44 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Matt Roper,
	Rodrigo Vivi, Satyanarayana K V P, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 11895 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_pci.c

between commit:

  130910bac905a ("drm/xe/pf: Disable display in admin only PF mode")

from the origin tree and commit:

  b623bd790db04 ("drm/xe: Drop 'force_execlist' module parameter")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/xe/xe_pci.c
index 9cd873708136c,91af603e94315..0000000000000
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@@ -26,6 -26,7 +26,7 @@@
  #include "xe_guc.h"
  #include "xe_mmio.h"
  #include "xe_module.h"
+ #include "xe_pci_error.h"
  #include "xe_pci_rebar.h"
  #include "xe_pci_sriov.h"
  #include "xe_pci_types.h"
@@@ -355,6 -356,7 +356,7 @@@ static const __maybe_unused struct xe_d
  	PLATFORM(PVC),
  	.dma_mask_size = 52,
  	.has_display = false,
+ 	.has_drm_ras = true,
  	.has_gsc_nvm = 1,
  	.has_heci_gscfi = 1,
  	.max_gt_per_tile = 1,
@@@ -457,6 -459,7 +459,7 @@@ static const struct xe_device_desc cri_
  	PLATFORM(CRESCENTISLAND),
  	.dma_mask_size = 52,
  	.has_display = false,
+ 	.has_drm_ras = true,
  	.has_flat_ccs = false,
  	.has_gsc_nvm = 1,
  	.has_i2c = true,
@@@ -599,8 -602,6 +602,6 @@@ static int read_gmdid(struct xe_device 
  	struct xe_reg gmdid_reg = GMD_ID;
  	u32 val;
  
- 	KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid);
- 
  	if (IS_SRIOV_VF(xe)) {
  		/*
  		 * To get the value of the GMDID register, VFs must obtain it
@@@ -726,14 -727,30 +727,30 @@@ static int handle_gmdid(struct xe_devic
  	return 0;
  }
  
- static void init_devid(struct xe_device *xe)
+ struct xe_probed_info {
+ 	u16 devid;
+ 	u8 revid;
+ 	u8 tile_count;
+ 	struct xe_step_info step;
+ 	const struct xe_ip *graphics_ip;
+ 	const struct xe_ip *media_ip;
+ };
+ 
+ /*
+  * Probe from the hardware the info required by xe_info_init_early().
+  */
+ static int xe_probe_info_early(struct xe_device *xe,
+ 			       const struct xe_device_desc *desc,
+ 			       struct xe_probed_info *probed_info)
  {
  	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
  
- 	KUNIT_STATIC_STUB_REDIRECT(init_devid, xe);
+ 	probed_info->devid = pdev->device;
+ 	probed_info->revid = pdev->revision;
  
- 	xe->info.devid = pdev->device;
- 	xe->info.revid = pdev->revision;
+ 	xe_step_platform_get(desc->platform, probed_info->revid, &probed_info->step);
+ 
+ 	return 0;
  }
  
  /*
@@@ -742,17 -759,20 +759,20 @@@
   */
  static int xe_info_init_early(struct xe_device *xe,
  			      const struct xe_device_desc *desc,
- 			      const struct xe_subplatform_desc *subplatform_desc)
+ 			      const struct xe_subplatform_desc *subplatform_desc,
+ 			      struct xe_probed_info *probed_info)
  {
  	int err;
  
+ 	xe->info.devid = probed_info->devid;
+ 	xe->info.revid = probed_info->revid;
+ 	xe->info.step.platform = probed_info->step.platform;
+ 
  	xe->info.platform_name = desc->platform_name;
  	xe->info.platform = desc->platform;
  	xe->info.subplatform = subplatform_desc ?
  		subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
  
- 	init_devid(xe);
- 
  	xe->info.dma_mask_size = desc->dma_mask_size;
  	xe->info.va_bits = desc->va_bits;
  	xe->info.vm_max_level = desc->vm_max_level;
@@@ -760,6 -780,7 +780,7 @@@
  
  	xe->info.is_dgfx = desc->is_dgfx;
  	xe->info.has_cached_pt = desc->has_cached_pt;
+ 	xe->info.has_drm_ras = desc->has_drm_ras;
  	xe->info.has_fan_control = desc->has_fan_control;
  	/* runtime fusing may force flat_ccs to disabled later */
  	xe->info.has_flat_ccs = desc->has_flat_ccs;
@@@ -788,16 -809,11 +809,11 @@@
  
  	xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) &&
  				 xe_modparam.probe_display &&
- 				 desc->has_display &&
- 				 !xe_device_is_admin_only(xe);
- 	xe->info.force_execlist = xe_modparam.force_execlist;
+ 				 desc->has_display;
  
  	xe_assert(xe, desc->max_gt_per_tile > 0);
  	xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE);
  	xe->info.max_gt_per_tile = desc->max_gt_per_tile;
- 	xe->info.tile_count = 1 + desc->max_remote_tiles;
- 
- 	xe_step_platform_get(xe);
  
  	err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0);
  	if (err)
@@@ -806,22 -822,21 +822,21 @@@
  	return 0;
  }
  
- /*
-  * Possibly override number of tile based on configuration register.
-  */
- static void xe_info_probe_tile_count(struct xe_device *xe)
+ static void xe_probe_tile_count(struct xe_device *xe,
+ 				const struct xe_device_desc *desc,
+ 				struct xe_probed_info *probed_info)
  {
  	struct xe_mmio *mmio;
  	u8 tile_count;
  	u32 mtcfg;
  
- 	KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe);
+ 	probed_info->tile_count = 1 + desc->max_remote_tiles;
  
  	/*
  	 * Probe for tile count only for platforms that support multiple
  	 * tiles.
  	 */
- 	if (xe->info.tile_count == 1)
+ 	if (probed_info->tile_count == 1)
  		return;
  
  	mmio = xe_root_tile_mmio(xe);
@@@ -834,10 -849,10 +849,10 @@@
  	mtcfg = xe_mmio_read32(mmio, XEHP_MTCFG_ADDR);
  	tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1;
  
- 	if (tile_count < xe->info.tile_count) {
+ 	if (tile_count < probed_info->tile_count) {
  		drm_info(&xe->drm, "tile_count: %d, reduced_tile_count %d\n",
- 			 xe->info.tile_count, tile_count);
- 		xe->info.tile_count = tile_count;
+ 			 probed_info->tile_count, tile_count);
+ 		probed_info->tile_count = tile_count;
  	}
  }
  
@@@ -910,25 -925,10 +925,10 @@@ static struct xe_gt *alloc_media_gt(str
  	return gt;
  }
  
- /*
-  * Initialize device info content that does require knowledge about
-  * graphics / media IP version.
-  * Make sure that GT / tile structures allocated by the driver match the data
-  * present in device info.
-  */
- static int xe_info_init(struct xe_device *xe,
- 			const struct xe_device_desc *desc)
+ static int xe_probe_ips(struct xe_device *xe,
+ 			const struct xe_device_desc *desc,
+ 			struct xe_probed_info *probed_info)
  {
- 	u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0;
- 	const struct xe_ip *graphics_ip;
- 	const struct xe_ip *media_ip;
- 	const struct xe_graphics_desc *graphics_desc;
- 	const struct xe_media_desc *media_desc;
- 	struct xe_tile *tile;
- 	struct xe_gt *gt;
- 	int ret;
- 	u8 id;
- 
  	/*
  	 * If this platform supports GMD_ID, we'll detect the proper IP
  	 * descriptor to use from hardware registers.
@@@ -937,17 -937,21 +937,21 @@@
  	 * versions are simply derived from that.
  	 */
  	if (desc->pre_gmdid_graphics_ip) {
- 		graphics_ip = desc->pre_gmdid_graphics_ip;
- 		media_ip = desc->pre_gmdid_media_ip;
- 		xe_step_pre_gmdid_get(xe);
+ 		probed_info->graphics_ip = desc->pre_gmdid_graphics_ip;
+ 		probed_info->media_ip = desc->pre_gmdid_media_ip;
+ 		xe_step_pre_gmdid_get(xe, &probed_info->step);
  	} else {
- 		xe_assert(xe, !desc->pre_gmdid_media_ip);
- 		ret = handle_gmdid(xe, &graphics_ip, &media_ip,
- 				   &graphics_gmdid_revid, &media_gmdid_revid);
- 		if (ret)
- 			return ret;
+ 		int err;
+ 		u32 graphics_revid, media_revid;
  
- 		xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid);
+ 		xe_assert(xe, !desc->pre_gmdid_media_ip);
+ 
+ 		err = handle_gmdid(xe, &probed_info->graphics_ip, &probed_info->media_ip,
+ 				   &graphics_revid, &media_revid);
+ 		if (err)
+ 			return err;
+ 
+ 		xe_step_gmdid_get(xe, graphics_revid, media_revid, &probed_info->step);
  	}
  
  	/*
@@@ -955,9 -959,56 +959,56 @@@
  	 * error and we should abort driver load.  Failing to detect media
  	 * IP is non-fatal; we'll just proceed without enabling media support.
  	 */
- 	if (!graphics_ip)
+ 	if (!probed_info->graphics_ip)
  		return -ENODEV;
  
+ 	return 0;
+ }
+ 
+ /*
+  * Probe from the hardware the info required by xe_info_init().
+  */
+ static int xe_probe_info(struct xe_device *xe,
+ 			 const struct xe_device_desc *desc,
+ 			 struct xe_probed_info *probed_info)
+ {
+ 	int err;
+ 
+ 	xe_probe_tile_count(xe, desc, probed_info);
+ 
+ 	err = xe_probe_ips(xe, desc, probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Initialize device info content that does require knowledge about
+  * graphics / media IP version.
+  * Make sure that GT / tile structures allocated by the driver match the data
+  * present in device info.
+  */
+ static int xe_info_init(struct xe_device *xe,
+ 			const struct xe_device_desc *desc,
+ 			struct xe_probed_info *probed_info)
+ {
+ 	const struct xe_ip *graphics_ip;
+ 	const struct xe_ip *media_ip;
+ 	const struct xe_graphics_desc *graphics_desc;
+ 	const struct xe_media_desc *media_desc;
+ 	struct xe_tile *tile;
+ 	struct xe_gt *gt;
+ 	u8 id;
+ 
+ 	graphics_ip = probed_info->graphics_ip;
+ 	media_ip = probed_info->media_ip;
+ 
+ 	xe->info.tile_count = probed_info->tile_count;
+ 	xe->info.step.basedie = probed_info->step.basedie;
+ 	xe->info.step.graphics = probed_info->step.graphics;
+ 	xe->info.step.media = probed_info->step.media;
+ 
  	xe->info.graphics_verx100 = graphics_ip->verx100;
  	xe->info.graphics_name = graphics_ip->name;
  	graphics_desc = graphics_ip->desc;
@@@ -989,8 -1040,6 +1040,6 @@@
  		xe->info.has_soc_remapper_telem = 0;
  	}
  
- 	xe_info_probe_tile_count(xe);
- 
  	for_each_remote_tile(tile, xe, id) {
  		int err;
  
@@@ -1049,12 -1098,6 +1098,12 @@@ static void xe_pci_remove(struct pci_de
  		return;
  
  	xe_device_remove(xe);
 +
 +	/*
 +	 * Preserve remove-time flush after moving destroy work to module
 +	 * lifetime.
 +	 */
 +	xe_destroy_wq_flush();
  	xe_pm_fini(xe);
  }
  
@@@ -1079,9 -1122,11 +1128,11 @@@
   */
  static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
+ 	struct xe_probed_info probed_info = {};
  	const struct xe_device_desc *desc = (const void *)ent->driver_data;
  	const struct xe_subplatform_desc *subplatform_desc;
  	struct xe_device *xe;
+ 	void *group;
  	int err;
  
  	subplatform_desc = find_subplatform(desc, pdev->device);
@@@ -1109,6 -1154,11 +1160,11 @@@
  	if (xe_display_driver_probe_defer(pdev))
  		return -EPROBE_DEFER;
  
+ 	/* Group all devres so xe_pci_error_slot_reset() can release them as a unit. */
+ 	group = devres_open_group(&pdev->dev, NULL, GFP_KERNEL);
+ 	if (!group)
+ 		return -ENOMEM;
+ 
  	err = pcim_enable_device(pdev);
  	if (err)
  		return err;
@@@ -1117,13 -1167,19 +1173,19 @@@
  	if (IS_ERR(xe))
  		return PTR_ERR(xe);
  
+ 	xe->devres_group = group;
+ 
  	pci_set_drvdata(pdev, &xe->drm);
  
  	xe_pm_assert_unbounded_bridge(xe);
  
  	pci_set_master(pdev);
  
- 	err = xe_info_init_early(xe, desc, subplatform_desc);
+ 	err = xe_probe_info_early(xe, desc, &probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	err = xe_info_init_early(xe, desc, subplatform_desc, &probed_info);
  	if (err)
  		return err;
  
@@@ -1142,7 -1198,11 +1204,11 @@@
  	if (err)
  		return err;
  
- 	err = xe_info_init(xe, desc);
+ 	err = xe_probe_info(xe, desc, &probed_info);
+ 	if (err)
+ 		return err;
+ 
+ 	err = xe_info_init(xe, desc, &probed_info);
  	if (err)
  		return err;
  
@@@ -1355,6 -1415,7 +1421,7 @@@ static struct pci_driver xe_pci_driver 
  	.remove = xe_pci_remove,
  	.shutdown = xe_pci_shutdown,
  	.sriov_configure = xe_pci_sriov_configure,
+ 	.err_handler = &xe_pci_error_handlers,
  #ifdef CONFIG_PM_SLEEP
  	.driver.pm = &xe_pm_ops,
  #endif

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-07-20 14:44 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-07-20 14:44 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Boris Brezillon, Laura Nao, Linux Kernel Mailing List,
	Linux Next Mailing List, Rodrigo Vivi, Satyanarayana K V P,
	Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 1244 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_device.c

between commit:

  130910bac905a ("drm/xe/pf: Disable display in admin only PF mode")

from the origin tree and commit:

  21fcb222f0d1e ("drm: Remove DRIVER_GEM_GPUVA feature flag")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_device.c
index 9d119c95a569a,ad7f3e61d4579..0000000000000
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@@ -426,7 -427,8 +427,7 @@@ static const struct drm_ioctl_desc xe_i
  
  static const struct drm_driver admin_only_driver = {
  	.driver_features =
- 	    DRIVER_GEM | DRIVER_RENDER | DRIVER_GEM_GPUVA,
 -	    XE_DISPLAY_DRIVER_FEATURES |
+ 	    DRIVER_GEM | DRIVER_RENDER,
  	.open = xe_file_open,
  	.postclose = xe_file_close,
  	.ioctls = xe_ioctls_admin_only,

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-06-09 17:53 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-06-09 17:53 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Christian König, Honglei Huang,
	Linux Kernel Mailing List, Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 2034 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c

between commits:

  962d684b5dc074 ("drm/amdgpu: fix amdgpu_hmm_range_get_pages")
  1c824497d8acd3 ("drm/amdgpu: fix calling VM invalidation in amdgpu_hmm_invalidate_gfx")
  58bafc666c484b ("drm/amdgpu: fix waiting for all submissions for userptrs")

from the origin tree and commits:

  c08972f555945c ("drm/amdgpu: fix amdgpu_hmm_range_get_pages")
  b6444d1bcbc34f ("drm/amdgpu: fix calling VM invalidation in amdgpu_hmm_invalidate_gfx")
  91250893cbaa25 ("drm/amdgpu: fix waiting for all submissions for userptrs")
  342981fff32802 ("drm/amdgpu: drop retry loop in amdgpu_hmm_range_get_pages")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
index e452444b33b08b,99bc9ad67d5b83..00000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
@@@ -174,7 -174,6 +174,6 @@@ int amdgpu_hmm_range_get_pages(struct m
  	const u64 max_bytes = SZ_2G;
  
  	struct hmm_range *hmm_range = &range->hmm_range;
- 	unsigned long timeout;
  	unsigned long *pfns;
  	unsigned long end;
  	int r;
@@@ -201,15 -200,9 +200,9 @@@
  		pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
  			hmm_range->start, hmm_range->end);
  
- 		timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
- 
- retry:
  		r = hmm_range_fault(hmm_range);
- 		if (unlikely(r)) {
- 			if (r == -EBUSY && !time_after(jiffies, timeout))
- 				goto retry;
+ 		if (unlikely(r))
  			goto out_free_pfns;
- 		}
  
  		if (hmm_range->end == end)
  			break;

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-06-04 14:13 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-06-04 14:13 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Christian König, Linux Kernel Mailing List,
	Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 28411 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c

between commit:

  1c824497d8acd ("drm/amdgpu: fix calling VM invalidation in amdgpu_hmm_invalidate_gfx")

from the origin tree and commit:

  b6444d1bcbc34 ("drm/amdgpu: fix calling VM invalidation in amdgpu_hmm_invalidate_gfx")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 381901bc539fd,7d51880b48608..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@@ -138,6 -138,47 +138,47 @@@ static void amdgpu_vm_assert_locked(str
  	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
  }
  
+ /* Initialize the amdgpu_vm_bo_status object */
+ static void amdgpu_vm_bo_status_init(struct amdgpu_vm_bo_status *lists)
+ {
+ 	INIT_LIST_HEAD(&lists->evicted);
+ 	INIT_LIST_HEAD(&lists->moved);
+ 	INIT_LIST_HEAD(&lists->idle);
+ }
+ 
+ /*
+  * Make sure we have the lock to modify the vm_bo status and return the object
+  * with the status lists.
+  */
+ static struct amdgpu_vm_bo_status *
+ amdgpu_vm_bo_lock_lists(struct amdgpu_vm_bo_base *vm_bo)
+ {
+ 	struct amdgpu_vm *vm = vm_bo->vm;
+ 	struct amdgpu_bo *bo = vm_bo->bo;
+ 
+ 	if (amdgpu_vm_is_bo_always_valid(vm, bo)) {
+ 		/* No extra locking needed, protected by the root PD resv lock */
+ 		amdgpu_vm_assert_locked(vm);
+ 
+ 		if (bo->tbo.type == ttm_bo_type_kernel)
+ 			return &vm->kernel;
+ 
+ 		return &vm->always_valid;
+ 	}
+ 
+ 	spin_lock(&vm_bo->vm->individual_lock);
+ 	return &vm->individual;
+ }
+ 
+ /* Eventually unlock the status list lock again */
+ static void amdgpu_vm_bo_unlock_lists(struct amdgpu_vm_bo_base *vm_bo)
+ {
+ 	if (amdgpu_vm_is_bo_always_valid(vm_bo->vm, vm_bo->bo))
+ 		amdgpu_vm_assert_locked(vm_bo->vm);
+ 	else
+ 		spin_unlock(&vm_bo->vm->individual_lock);
+ }
+ 
  /**
   * amdgpu_vm_is_bo_always_valid - check if the BO is VM always valid
   *
@@@ -157,37 -198,44 +198,44 @@@ bool amdgpu_vm_is_bo_always_valid(struc
   *
   * @vm_bo: vm_bo which is evicted
   *
-  * State for PDs/PTs and per VM BOs which are not at the location they should
-  * be.
+  * State for vm_bo objects meaning the underlying BO was evicted and need to
+  * move in place again.
   */
  static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo)
  {
- 	struct amdgpu_vm *vm = vm_bo->vm;
- 	struct amdgpu_bo *bo = vm_bo->bo;
+ 	struct amdgpu_vm_bo_status *lists;
  
+ 	lists = amdgpu_vm_bo_lock_lists(vm_bo);
  	vm_bo->moved = true;
- 	amdgpu_vm_assert_locked(vm);
- 	spin_lock(&vm_bo->vm->status_lock);
- 	if (bo->tbo.type == ttm_bo_type_kernel)
- 		list_move(&vm_bo->vm_status, &vm->evicted);
- 	else
- 		list_move_tail(&vm_bo->vm_status, &vm->evicted);
- 	spin_unlock(&vm_bo->vm->status_lock);
+ 	list_move(&vm_bo->vm_status, &lists->evicted);
+ 	amdgpu_vm_bo_unlock_lists(vm_bo);
  }
  /**
   * amdgpu_vm_bo_moved - vm_bo is moved
   *
   * @vm_bo: vm_bo which is moved
   *
-  * State for per VM BOs which are moved, but that change is not yet reflected
-  * in the page tables.
+  * State for vm_bo objects meaning the underlying BO was moved but the new
+  * location not yet reflected in the page tables.
   */
  static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo)
  {
- 	amdgpu_vm_assert_locked(vm_bo->vm);
- 	spin_lock(&vm_bo->vm->status_lock);
- 	list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
- 	spin_unlock(&vm_bo->vm->status_lock);
+ 	struct amdgpu_vm_bo_status *lists;
+ 	struct amdgpu_bo *bo = vm_bo->bo;
+ 
+ 	/*
+ 	 * The root PD doesn't have a parent PDE and goes directly into the
+ 	 * idle state.
+ 	 */
+ 	lists = amdgpu_vm_bo_lock_lists(vm_bo);
+ 	if (bo && bo->tbo.type == ttm_bo_type_kernel && !bo->parent) {
+ 		vm_bo->moved = false;
+ 		list_move(&vm_bo->vm_status, &lists->idle);
+ 	} else {
+ 		vm_bo->moved = true;
+ 		list_move(&vm_bo->vm_status, &lists->moved);
+ 	}
+ 	amdgpu_vm_bo_unlock_lists(vm_bo);
  }
  
  /**
@@@ -195,120 -243,54 +243,54 @@@
   *
   * @vm_bo: vm_bo which is now idle
   *
-  * State for PDs/PTs and per VM BOs which have gone through the state machine
-  * and are now idle.
+  * State for vm_bo objects meaning we are done with the state machine and no
+  * further action is necessary.
   */
  static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
  {
- 	amdgpu_vm_assert_locked(vm_bo->vm);
- 	spin_lock(&vm_bo->vm->status_lock);
- 	list_move(&vm_bo->vm_status, &vm_bo->vm->idle);
- 	spin_unlock(&vm_bo->vm->status_lock);
- 	vm_bo->moved = false;
- }
+ 	struct amdgpu_vm_bo_status *lists;
  
- /**
-  * amdgpu_vm_bo_invalidated - vm_bo is invalidated
-  *
-  * @vm_bo: vm_bo which is now invalidated
-  *
-  * State for normal BOs which are invalidated and that change not yet reflected
-  * in the PTs.
-  */
- static void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo)
- {
- 	spin_lock(&vm_bo->vm->status_lock);
- 	list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated);
- 	spin_unlock(&vm_bo->vm->status_lock);
- }
- 
- /**
-  * amdgpu_vm_bo_evicted_user - vm_bo is evicted
-  *
-  * @vm_bo: vm_bo which is evicted
-  *
-  * State for BOs used by user mode queues which are not at the location they
-  * should be.
-  */
- static void amdgpu_vm_bo_evicted_user(struct amdgpu_vm_bo_base *vm_bo)
- {
- 	vm_bo->moved = true;
- 	spin_lock(&vm_bo->vm->status_lock);
- 	list_move(&vm_bo->vm_status, &vm_bo->vm->evicted_user);
- 	spin_unlock(&vm_bo->vm->status_lock);
- }
- 
- /**
-  * amdgpu_vm_bo_relocated - vm_bo is reloacted
-  *
-  * @vm_bo: vm_bo which is relocated
-  *
-  * State for PDs/PTs which needs to update their parent PD.
-  * For the root PD, just move to idle state.
-  */
- static void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo)
- {
- 	amdgpu_vm_assert_locked(vm_bo->vm);
- 	if (vm_bo->bo->parent) {
- 		spin_lock(&vm_bo->vm->status_lock);
- 		list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
- 		spin_unlock(&vm_bo->vm->status_lock);
- 	} else {
- 		amdgpu_vm_bo_idle(vm_bo);
- 	}
- }
- 
- /**
-  * amdgpu_vm_bo_done - vm_bo is done
-  *
-  * @vm_bo: vm_bo which is now done
-  *
-  * State for normal BOs which are invalidated and that change has been updated
-  * in the PTs.
-  */
- static void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo)
- {
- 	amdgpu_vm_assert_locked(vm_bo->vm);
- 	spin_lock(&vm_bo->vm->status_lock);
- 	list_move(&vm_bo->vm_status, &vm_bo->vm->done);
- 	spin_unlock(&vm_bo->vm->status_lock);
+ 	lists = amdgpu_vm_bo_lock_lists(vm_bo);
+ 	if (!amdgpu_vm_is_bo_always_valid(vm_bo->vm, vm_bo->bo))
+ 		vm_bo->moved = false;
+ 	list_move(&vm_bo->vm_status, &lists->idle);
+ 	amdgpu_vm_bo_unlock_lists(vm_bo);
  }
  
  /**
   * amdgpu_vm_bo_reset_state_machine - reset the vm_bo state machine
   * @vm: the VM which state machine to reset
   *
-  * Move all vm_bo object in the VM into a state where they will be updated
-  * again during validation.
+  * Move all vm_bo object in the VM into a state where their location will be
+  * updated in the page tables again.
   */
  static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm)
  {
  	struct amdgpu_vm_bo_base *vm_bo, *tmp;
  
+ 	/*
+ 	 * Don't use list splice here, we need the special handling for the root
+ 	 * PD and set the moved flag appropriately.
+ 	 */
  	amdgpu_vm_assert_locked(vm);
+ 	list_for_each_entry_safe(vm_bo, tmp, &vm->kernel.idle, vm_status)
+ 		amdgpu_vm_bo_moved(vm_bo);
+ 	list_for_each_entry_safe(vm_bo, tmp, &vm->always_valid.idle, vm_status)
+ 		amdgpu_vm_bo_moved(vm_bo);
  
- 	spin_lock(&vm->status_lock);
- 	list_splice_init(&vm->done, &vm->invalidated);
- 	list_for_each_entry(vm_bo, &vm->invalidated, vm_status)
+ 	spin_lock(&vm->individual_lock);
+ 	list_for_each_entry_safe(vm_bo, tmp, &vm->individual.idle, vm_status) {
  		vm_bo->moved = true;
- 
- 	list_for_each_entry_safe(vm_bo, tmp, &vm->idle, vm_status) {
- 		struct amdgpu_bo *bo = vm_bo->bo;
- 
- 		vm_bo->moved = true;
- 		if (!bo || bo->tbo.type != ttm_bo_type_kernel)
- 			list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
- 		else if (bo->parent)
- 			list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
+ 		list_move(&vm_bo->vm_status, &vm->individual.moved);
  	}
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->individual_lock);
  }
  
  /**
   * amdgpu_vm_update_shared - helper to update shared memory stat
   * @base: base structure for tracking BO usage in a VM
   *
-  * Takes the vm status_lock and updates the shared memory stat. If the basic
+  * Takes the vm stats_lock and updates the shared memory stat. If the basic
   * stat changed (e.g. buffer was moved) amdgpu_vm_update_stats need to be called
   * as well.
   */
@@@ -321,7 -303,7 +303,7 @@@ static void amdgpu_vm_update_shared(str
  	bool shared;
  
  	dma_resv_assert_held(bo->tbo.base.resv);
- 	spin_lock(&vm->status_lock);
+ 	spin_lock(&vm->stats_lock);
  	shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base);
  	if (base->shared != shared) {
  		base->shared = shared;
@@@ -333,7 -315,7 +315,7 @@@
  			vm->stats[bo_memtype].drm.private += size;
  		}
  	}
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->stats_lock);
  }
  
  /**
@@@ -358,11 -340,11 +340,11 @@@ void amdgpu_vm_bo_update_shared(struct 
   *        be bo->tbo.resource
   * @sign: if we should add (+1) or subtract (-1) from the stat
   *
-  * Caller need to have the vm status_lock held. Useful for when multiple update
+  * Caller need to have the vm stats_lock held. Useful for when multiple update
   * need to happen at the same time.
   */
  static void amdgpu_vm_update_stats_locked(struct amdgpu_vm_bo_base *base,
- 			    struct ttm_resource *res, int sign)
+ 					  struct ttm_resource *res, int sign)
  {
  	struct amdgpu_vm *vm = base->vm;
  	struct amdgpu_bo *bo = base->bo;
@@@ -386,7 -368,8 +368,8 @@@
  		 */
  		if (bo->flags & AMDGPU_GEM_CREATE_DISCARDABLE)
  			vm->stats[res_memtype].drm.purgeable += size;
- 		if (!(bo->preferred_domains & amdgpu_mem_type_to_domain(res_memtype)))
+ 		if (!(bo->preferred_domains &
+ 		      amdgpu_mem_type_to_domain(res_memtype)))
  			vm->stats[bo_memtype].evicted += size;
  	}
  }
@@@ -405,9 -388,9 +388,9 @@@ void amdgpu_vm_update_stats(struct amdg
  {
  	struct amdgpu_vm *vm = base->vm;
  
- 	spin_lock(&vm->status_lock);
+ 	spin_lock(&vm->stats_lock);
  	amdgpu_vm_update_stats_locked(base, res, sign);
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->stats_lock);
  }
  
  /**
@@@ -428,37 -411,34 +411,34 @@@ void amdgpu_vm_bo_base_init(struct amdg
  	base->next = NULL;
  	INIT_LIST_HEAD(&base->vm_status);
  
+ 	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
  	if (!bo)
  		return;
+ 
  	base->next = bo->vm_bo;
  	bo->vm_bo = base;
  
- 	spin_lock(&vm->status_lock);
+ 	spin_lock(&vm->stats_lock);
  	base->shared = drm_gem_object_is_shared_for_memory_stats(&bo->tbo.base);
  	amdgpu_vm_update_stats_locked(base, bo->tbo.resource, +1);
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->stats_lock);
  
- 	if (!amdgpu_vm_is_bo_always_valid(vm, bo))
+ 	if (!amdgpu_vm_is_bo_always_valid(vm, bo)) {
+ 		amdgpu_vm_bo_idle(base);
  		return;
- 
- 	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
+ 	}
  
  	ttm_bo_set_bulk_move(&bo->tbo, &vm->lru_bulk_move);
- 	if (bo->tbo.type == ttm_bo_type_kernel && bo->parent)
- 		amdgpu_vm_bo_relocated(base);
- 	else
- 		amdgpu_vm_bo_idle(base);
- 
- 	if (bo->preferred_domains &
- 	    amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type))
- 		return;
  
  	/*
- 	 * we checked all the prerequisites, but it looks like this per vm bo
- 	 * is currently evicted. add the bo to the evicted list to make sure it
- 	 * is validated on next vm use to avoid fault.
- 	 * */
- 	amdgpu_vm_bo_evicted(base);
+ 	 * When a per VM isn't in the desired domain put it into the evicted
+ 	 * state to make sure that it gets validated on the next best occasion.
+ 	 */
+ 	if (bo->preferred_domains &
+ 	    amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type))
+ 		amdgpu_vm_bo_moved(base);
+ 	else
+ 		amdgpu_vm_bo_evicted(base);
  }
  
  /**
@@@ -479,41 -459,41 +459,41 @@@ int amdgpu_vm_lock_pd(struct amdgpu_vm 
  }
  
  /**
-  * amdgpu_vm_lock_done_list - lock all BOs on the done list
+  * amdgpu_vm_lock_individual - lock all BOs on the individual idle list
   * @vm: vm providing the BOs
   * @exec: drm execution context
   * @num_fences: number of extra fences to reserve
   *
-  * Lock the BOs on the done list in the DRM execution context.
+  * Lock the BOs on the individual idle list in the DRM execution context.
   */
- int amdgpu_vm_lock_done_list(struct amdgpu_vm *vm, struct drm_exec *exec,
- 			     unsigned int num_fences)
+ int amdgpu_vm_lock_individual(struct amdgpu_vm *vm, struct drm_exec *exec,
+ 			      unsigned int num_fences)
  {
- 	struct list_head *prev = &vm->done;
+ 	struct list_head *prev = &vm->individual.idle;
  	struct amdgpu_bo_va *bo_va;
  	struct amdgpu_bo *bo;
  	int ret;
  
  	/* We can only trust prev->next while holding the lock */
- 	spin_lock(&vm->status_lock);
- 	while (!list_is_head(prev->next, &vm->done)) {
+ 	spin_lock(&vm->individual_lock);
+ 	while (!list_is_head(prev->next, &vm->individual.idle)) {
  		bo_va = list_entry(prev->next, typeof(*bo_va), base.vm_status);
  
  		bo = bo_va->base.bo;
  		if (bo) {
  			amdgpu_bo_ref(bo);
- 			spin_unlock(&vm->status_lock);
+ 			spin_unlock(&vm->individual_lock);
  
- 			ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 1);
+ 			ret = drm_exec_prepare_obj(exec, &bo->tbo.base, num_fences);
  			amdgpu_bo_unref(&bo);
  			if (unlikely(ret))
  				return ret;
  
- 			spin_lock(&vm->status_lock);
+ 			spin_lock(&vm->individual_lock);
  		}
  		prev = prev->next;
  	}
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->individual_lock);
  
  	return 0;
  }
@@@ -609,10 -589,10 +589,10 @@@ int amdgpu_vm_validate(struct amdgpu_de
  		       void *param)
  {
  	uint64_t new_vm_generation = amdgpu_vm_generation(adev, vm);
- 	struct amdgpu_vm_bo_base *bo_base;
- 	struct amdgpu_bo *bo;
+ 	struct amdgpu_vm_bo_base *bo_base, *tmp;
  	int r;
  
+ 	dma_resv_assert_held(vm->root.bo->tbo.base.resv);
  	if (vm->generation != new_vm_generation) {
  		vm->generation = new_vm_generation;
  		amdgpu_vm_bo_reset_state_machine(vm);
@@@ -622,50 -602,60 +602,60 @@@
  			return r;
  	}
  
- 	spin_lock(&vm->status_lock);
- 	while (!list_empty(&vm->evicted)) {
- 		bo_base = list_first_entry(&vm->evicted,
- 					   struct amdgpu_vm_bo_base,
- 					   vm_status);
- 		spin_unlock(&vm->status_lock);
- 
- 		bo = bo_base->bo;
- 
- 		r = validate(param, bo);
+ 	list_for_each_entry_safe(bo_base, tmp, &vm->kernel.evicted, vm_status) {
+ 		r = validate(param, bo_base->bo);
  		if (r)
  			return r;
  
- 		if (bo->tbo.type != ttm_bo_type_kernel) {
- 			amdgpu_vm_bo_moved(bo_base);
- 		} else {
- 			vm->update_funcs->map_table(to_amdgpu_bo_vm(bo));
- 			amdgpu_vm_bo_relocated(bo_base);
- 		}
- 		spin_lock(&vm->status_lock);
+ 		vm->update_funcs->map_table(to_amdgpu_bo_vm(bo_base->bo));
+ 		amdgpu_vm_bo_moved(bo_base);
  	}
- 	while (ticket && !list_empty(&vm->evicted_user)) {
- 		bo_base = list_first_entry(&vm->evicted_user,
- 					   struct amdgpu_vm_bo_base,
- 					   vm_status);
- 		spin_unlock(&vm->status_lock);
- 
- 		bo = bo_base->bo;
- 		dma_resv_assert_held(bo->tbo.base.resv);
- 
- 		r = validate(param, bo);
- 		if (r)
- 			return r;
- 
- 		amdgpu_vm_bo_invalidated(bo_base);
- 
- 		spin_lock(&vm->status_lock);
- 	}
- 	spin_unlock(&vm->status_lock);
  
+ 	/*
+ 	 * As soon as all page tables are in place we can start updating them
+ 	 * again.
+ 	 */
  	amdgpu_vm_eviction_lock(vm);
  	vm->evicting = false;
  	amdgpu_vm_eviction_unlock(vm);
  
+ 	list_for_each_entry_safe(bo_base, tmp, &vm->always_valid.evicted,
+ 				 vm_status) {
+ 		r = validate(param, bo_base->bo);
+ 		if (r)
+ 			return r;
+ 
+ 		amdgpu_vm_bo_moved(bo_base);
+ 	}
+ 
+ 	if (!ticket)
+ 		return 0;
+ 
+ 	spin_lock(&vm->individual_lock);
+ restart:
+ 	list_for_each_entry(bo_base, &vm->individual.evicted, vm_status) {
+ 		struct amdgpu_bo *bo = bo_base->bo;
+ 
+ 		if (dma_resv_locking_ctx(bo->tbo.base.resv) != ticket)
+ 			continue;
+ 
+ 		spin_unlock(&vm->individual_lock);
+ 
+ 		r = validate(param, bo);
+ 		if (r)
+ 			return r;
+ 
+ 		amdgpu_vm_bo_moved(bo_base);
+ 
+ 		/* It's a bit inefficient to always jump back to the start, but
+ 		 * we would need to re-structure the KFD for properly fixing
+ 		 * that.
+ 		 */
+ 		spin_lock(&vm->individual_lock);
+ 		goto restart;
+ 	}
+ 	spin_unlock(&vm->individual_lock);
+ 
  	return 0;
  }
  
@@@ -689,9 -679,7 +679,7 @@@ bool amdgpu_vm_ready(struct amdgpu_vm *
  	ret = !vm->evicting;
  	amdgpu_vm_eviction_unlock(vm);
  
- 	spin_lock(&vm->status_lock);
- 	ret &= list_empty(&vm->evicted);
- 	spin_unlock(&vm->status_lock);
+ 	ret &= list_empty(&vm->kernel.evicted);
  
  	spin_lock(&vm->immediate.lock);
  	ret &= !vm->immediate.stopped;
@@@ -985,18 -973,13 +973,13 @@@ int amdgpu_vm_update_pdes(struct amdgpu
  			  struct amdgpu_vm *vm, bool immediate)
  {
  	struct amdgpu_vm_update_params params;
- 	struct amdgpu_vm_bo_base *entry;
+ 	struct amdgpu_vm_bo_base *entry, *tmp;
  	bool flush_tlb_needed = false;
- 	LIST_HEAD(relocated);
  	int r, idx;
  
  	amdgpu_vm_assert_locked(vm);
  
- 	spin_lock(&vm->status_lock);
- 	list_splice_init(&vm->relocated, &relocated);
- 	spin_unlock(&vm->status_lock);
- 
- 	if (list_empty(&relocated))
+ 	if (list_empty(&vm->kernel.moved))
  		return 0;
  
  	if (!drm_dev_enter(adev_to_drm(adev), &idx))
@@@ -1012,7 -995,7 +995,7 @@@
  	if (r)
  		goto error;
  
- 	list_for_each_entry(entry, &relocated, vm_status) {
+ 	list_for_each_entry(entry, &vm->kernel.moved, vm_status) {
  		/* vm_flush_needed after updating moved PDEs */
  		flush_tlb_needed |= entry->moved;
  
@@@ -1028,11 -1011,8 +1011,8 @@@
  	if (flush_tlb_needed)
  		atomic64_inc(&vm->tlb_seq);
  
- 	while (!list_empty(&relocated)) {
- 		entry = list_first_entry(&relocated, struct amdgpu_vm_bo_base,
- 					 vm_status);
+ 	list_for_each_entry_safe(entry, tmp, &vm->kernel.moved, vm_status)
  		amdgpu_vm_bo_idle(entry);
- 	}
  
  error:
  	drm_dev_exit(idx);
@@@ -1163,7 -1143,7 +1143,7 @@@ int amdgpu_vm_update_range(struct amdgp
  	params.pages_addr = pages_addr;
  	params.unlocked = unlocked;
  	params.needs_flush = flush_tlb;
- 	params.allow_override = allow_override;
+ 	params.override_pte = allow_override && adev->gmc.override_pte;
  	INIT_LIST_HEAD(&params.tlb_flush_waitlist);
  
  	amdgpu_vm_eviction_lock(vm);
@@@ -1260,9 -1240,9 +1240,9 @@@ error_free
  void amdgpu_vm_get_memory(struct amdgpu_vm *vm,
  			  struct amdgpu_mem_stats stats[__AMDGPU_PL_NUM])
  {
- 	spin_lock(&vm->status_lock);
+ 	spin_lock(&vm->stats_lock);
  	memcpy(stats, vm->stats, sizeof(*stats) * __AMDGPU_PL_NUM);
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->stats_lock);
  }
  
  /**
@@@ -1406,7 -1386,7 +1386,7 @@@ int amdgpu_vm_bo_update(struct amdgpu_d
  		else
  			amdgpu_vm_bo_idle(&bo_va->base);
  	} else {
- 		amdgpu_vm_bo_done(&bo_va->base);
+ 		amdgpu_vm_bo_idle(&bo_va->base);
  	}
  
  	list_splice_init(&bo_va->invalids, &bo_va->valids);
@@@ -1629,31 -1609,27 +1609,27 @@@ int amdgpu_vm_handle_moved(struct amdgp
  			   struct amdgpu_vm *vm,
  			   struct ww_acquire_ctx *ticket)
  {
- 	struct amdgpu_bo_va *bo_va;
+ 	struct amdgpu_bo_va *bo_va, *tmp;
  	struct dma_resv *resv;
  	struct amdgpu_bo *bo;
  	bool clear, unlock;
  	int r;
  
- 	spin_lock(&vm->status_lock);
- 	while (!list_empty(&vm->moved)) {
- 		bo_va = list_first_entry(&vm->moved, struct amdgpu_bo_va,
- 					 base.vm_status);
- 		spin_unlock(&vm->status_lock);
- 
+ 	list_for_each_entry_safe(bo_va, tmp, &vm->always_valid.moved,
+ 				 base.vm_status) {
  		/* Per VM BOs never need to bo cleared in the page tables */
  		r = amdgpu_vm_bo_update(adev, bo_va, false);
  		if (r)
  			return r;
- 		spin_lock(&vm->status_lock);
  	}
  
- 	while (!list_empty(&vm->invalidated)) {
- 		bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
- 					 base.vm_status);
+ 	spin_lock(&vm->individual_lock);
+ 	while (!list_empty(&vm->individual.moved)) {
+ 		bo_va = list_first_entry(&vm->individual.moved,
+ 					 typeof(*bo_va), base.vm_status);
  		bo = bo_va->base.bo;
  		resv = bo->tbo.base.resv;
- 		spin_unlock(&vm->status_lock);
+ 		spin_unlock(&vm->individual_lock);
  
  		/* Try to reserve the BO to avoid clearing its ptes */
  		if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
@@@ -1684,11 -1660,11 +1660,11 @@@
  		    drm_gem_is_imported(&bo_va->base.bo->tbo.base) &&
  		    (!bo_va->base.bo->tbo.resource ||
  		     bo_va->base.bo->tbo.resource->mem_type == TTM_PL_SYSTEM))
- 			amdgpu_vm_bo_evicted_user(&bo_va->base);
+ 			amdgpu_vm_bo_evicted(&bo_va->base);
  
- 		spin_lock(&vm->status_lock);
+ 		spin_lock(&vm->individual_lock);
  	}
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->individual_lock);
  
  	return 0;
  }
@@@ -2226,9 -2202,9 +2202,9 @@@ void amdgpu_vm_bo_del(struct amdgpu_dev
  		}
  	}
  
- 	spin_lock(&vm->status_lock);
+ 	spin_lock(&vm->individual_lock);
  	list_del(&bo_va->base.vm_status);
- 	spin_unlock(&vm->status_lock);
+ 	spin_unlock(&vm->individual_lock);
  
  	list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
  		list_del(&mapping->list);
@@@ -2308,14 -2284,7 +2284,7 @@@ void amdgpu_vm_bo_invalidate(struct amd
  
  		if (bo_base->moved)
  			continue;
- 		bo_base->moved = true;
- 
- 		if (bo->tbo.type == ttm_bo_type_kernel)
- 			amdgpu_vm_bo_relocated(bo_base);
- 		else if (amdgpu_vm_is_bo_always_valid(vm, bo))
- 			amdgpu_vm_bo_moved(bo_base);
- 		else
- 			amdgpu_vm_bo_invalidated(bo_base);
+ 		amdgpu_vm_bo_moved(bo_base);
  	}
  }
  
@@@ -2336,10 -2305,10 +2305,10 @@@ void amdgpu_vm_bo_move(struct amdgpu_b
  	for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) {
  		struct amdgpu_vm *vm = bo_base->vm;
  
- 		spin_lock(&vm->status_lock);
+ 		spin_lock(&vm->stats_lock);
  		amdgpu_vm_update_stats_locked(bo_base, bo->tbo.resource, -1);
  		amdgpu_vm_update_stats_locked(bo_base, new_mem, +1);
- 		spin_unlock(&vm->status_lock);
+ 		spin_unlock(&vm->stats_lock);
  	}
  
  	amdgpu_vm_bo_invalidate(bo, evicted);
@@@ -2603,16 -2572,14 +2572,14 @@@ int amdgpu_vm_init(struct amdgpu_devic
  	vm->va = RB_ROOT_CACHED;
  	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
  		vm->reserved_vmid[i] = NULL;
- 	INIT_LIST_HEAD(&vm->evicted);
- 	INIT_LIST_HEAD(&vm->evicted_user);
- 	INIT_LIST_HEAD(&vm->relocated);
- 	INIT_LIST_HEAD(&vm->moved);
- 	INIT_LIST_HEAD(&vm->idle);
- 	INIT_LIST_HEAD(&vm->invalidated);
- 	spin_lock_init(&vm->status_lock);
+ 
+ 	amdgpu_vm_bo_status_init(&vm->kernel);
+ 	amdgpu_vm_bo_status_init(&vm->always_valid);
+ 	spin_lock_init(&vm->individual_lock);
+ 	amdgpu_vm_bo_status_init(&vm->individual);
  	INIT_LIST_HEAD(&vm->freed);
- 	INIT_LIST_HEAD(&vm->done);
  	INIT_KFIFO(vm->faults);
+ 	spin_lock_init(&vm->stats_lock);
  
  	r = amdgpu_vm_init_entities(adev, vm);
  	if (r)
@@@ -3089,6 -3056,42 +3056,42 @@@ error_unlock
  }
  
  #if defined(CONFIG_DEBUG_FS)
+ 
+ /* print the debug info for a specific set of status lists */
+ static void amdgpu_debugfs_vm_bo_status_info(struct seq_file *m,
+ 					     struct amdgpu_vm_bo_status *lists)
+ {
+ 	struct amdgpu_vm_bo_base *base;
+ 	unsigned int id;
+ 
+ 	id = 0;
+ 	seq_puts(m, "\tEvicted BOs:\n");
+ 	list_for_each_entry(base, &lists->evicted, vm_status) {
+ 		if (!base->bo)
+ 			continue;
+ 
+ 		amdgpu_bo_print_info(id++, base->bo, m);
+ 	}
+ 
+ 	id = 0;
+ 	seq_puts(m, "\tMoved BOs:\n");
+ 	list_for_each_entry(base, &lists->moved, vm_status) {
+ 		if (!base->bo)
+ 			continue;
+ 
+ 		amdgpu_bo_print_info(id++, base->bo, m);
+ 	}
+ 
+ 	id = 0;
+ 	seq_puts(m, "\tIdle BOs:\n");
+ 	list_for_each_entry(base, &lists->moved, vm_status) {
+ 		if (!base->bo)
+ 			continue;
+ 
+ 		amdgpu_bo_print_info(id++, base->bo, m);
+ 	}
+ }
+ 
  /**
   * amdgpu_debugfs_vm_bo_info  - print BO info for the VM
   *
@@@ -3099,90 -3102,18 +3102,18 @@@
   */
  void amdgpu_debugfs_vm_bo_info(struct amdgpu_vm *vm, struct seq_file *m)
  {
- 	struct amdgpu_bo_va *bo_va, *tmp;
- 	u64 total_idle = 0;
- 	u64 total_evicted = 0;
- 	u64 total_relocated = 0;
- 	u64 total_moved = 0;
- 	u64 total_invalidated = 0;
- 	u64 total_done = 0;
- 	unsigned int total_idle_objs = 0;
- 	unsigned int total_evicted_objs = 0;
- 	unsigned int total_relocated_objs = 0;
- 	unsigned int total_moved_objs = 0;
- 	unsigned int total_invalidated_objs = 0;
- 	unsigned int total_done_objs = 0;
- 	unsigned int id = 0;
- 
  	amdgpu_vm_assert_locked(vm);
  
- 	spin_lock(&vm->status_lock);
- 	seq_puts(m, "\tIdle BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_idle += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
- 	}
- 	total_idle_objs = id;
- 	id = 0;
+ 	seq_puts(m, "\tKernel PT/PDs:\n");
+ 	amdgpu_debugfs_vm_bo_status_info(m, &vm->kernel);
  
- 	seq_puts(m, "\tEvicted BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_evicted += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
- 	}
- 	total_evicted_objs = id;
- 	id = 0;
+ 	seq_puts(m, "\tPer VM BOs:\n");
+ 	amdgpu_debugfs_vm_bo_status_info(m, &vm->always_valid);
  
- 	seq_puts(m, "\tRelocated BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_relocated += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
- 	}
- 	total_relocated_objs = id;
- 	id = 0;
- 
- 	seq_puts(m, "\tMoved BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_moved += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
- 	}
- 	total_moved_objs = id;
- 	id = 0;
- 
- 	seq_puts(m, "\tInvalidated BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_invalidated += amdgpu_bo_print_info(id++,	bo_va->base.bo, m);
- 	}
- 	total_invalidated_objs = id;
- 	id = 0;
- 
- 	seq_puts(m, "\tDone BOs:\n");
- 	list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) {
- 		if (!bo_va->base.bo)
- 			continue;
- 		total_done += amdgpu_bo_print_info(id++, bo_va->base.bo, m);
- 	}
- 	spin_unlock(&vm->status_lock);
- 	total_done_objs = id;
- 
- 	seq_printf(m, "\tTotal idle size:        %12lld\tobjs:\t%d\n", total_idle,
- 		   total_idle_objs);
- 	seq_printf(m, "\tTotal evicted size:     %12lld\tobjs:\t%d\n", total_evicted,
- 		   total_evicted_objs);
- 	seq_printf(m, "\tTotal relocated size:   %12lld\tobjs:\t%d\n", total_relocated,
- 		   total_relocated_objs);
- 	seq_printf(m, "\tTotal moved size:       %12lld\tobjs:\t%d\n", total_moved,
- 		   total_moved_objs);
- 	seq_printf(m, "\tTotal invalidated size: %12lld\tobjs:\t%d\n", total_invalidated,
- 		   total_invalidated_objs);
- 	seq_printf(m, "\tTotal done size:        %12lld\tobjs:\t%d\n", total_done,
- 		   total_done_objs);
+ 	seq_puts(m, "\tIndividual BOs:\n");
+ 	spin_lock(&vm->individual_lock);
+ 	amdgpu_debugfs_vm_bo_status_info(m, &vm->individual);
+ 	spin_unlock(&vm->individual_lock);
  }
  #endif
  

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-05-18 12:47 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-05-18 12:47 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Balasubramani Vivekanandan, Linux Kernel Mailing List,
	Linux Next Mailing List, Matt Roper, Rodrigo Vivi

[-- Attachment #1: Type: text/plain, Size: 7977 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_migrate.c

between commit:

  4568dfbb8363a ("drm/xe: Make decision to use Xe2-style blitter instructions a feature flag")

from the origin tree and commits:

  09b3998429075 ("drm/xe: Make decision to use Xe2-style blitter instructions a feature flag")
  388768fe17386 ("drm/xe: Refactor emit_clear_main_copy")
  65be72013baf9 ("drm/xe: Refactor emit_clear_link_copy")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/xe/xe_migrate.c
index a22413f892a09,9428dd5e7760c..0000000000000
--- a/drivers/gpu/drm/xe/xe_migrate.c
+++ b/drivers/gpu/drm/xe/xe_migrate.c
@@@ -31,6 -31,7 +31,7 @@@
  #include "xe_map.h"
  #include "xe_mem_pool.h"
  #include "xe_mocs.h"
+ #include "xe_pat.h"
  #include "xe_printk.h"
  #include "xe_pt.h"
  #include "xe_res_cursor.h"
@@@ -217,7 -218,7 +218,7 @@@ static void xe_migrate_prepare_vm(struc
  				  struct xe_vm *vm, u32 *ofs)
  {
  	struct xe_device *xe = tile_to_xe(tile);
- 	u16 pat_index = xe->pat.idx[XE_CACHE_WB];
+ 	u16 pat_index = xe_cache_pat_idx(xe, XE_CACHE_WB);
  	u8 id = tile->id;
  	u32 num_entries = NUM_PT_SLOTS, num_level = vm->pt_root[id]->level;
  #define VRAM_IDENTITY_MAP_COUNT	2
@@@ -337,7 -338,7 +338,7 @@@
  		 * if flat ccs is enabled.
  		 */
  		if (GRAPHICS_VER(xe) >= 20 && xe_device_has_flat_ccs(xe)) {
- 			u16 comp_pat_index = xe->pat.idx[XE_CACHE_NONE_COMPRESSION];
+ 			u16 comp_pat_index = xe_cache_pat_idx(xe, XE_CACHE_NONE_COMPRESSION);
  			u64 vram_offset = IDENTITY_OFFSET +
  				DIV_ROUND_UP_ULL(actual_phy_size, SZ_1G);
  			u64 pt31_ofs = xe_bo_size(bo) - XE_PAGE_SIZE;
@@@ -637,10 -638,10 +638,10 @@@ static void emit_pte(struct xe_migrate 
  
  	/* Indirect access needs compression enabled uncached PAT index */
  	if (GRAPHICS_VERx100(xe) >= 2000)
- 		pat_index = is_comp_pte ? xe->pat.idx[XE_CACHE_NONE_COMPRESSION] :
- 					  xe->pat.idx[XE_CACHE_WB];
+ 		pat_index = is_comp_pte ? xe_cache_pat_idx(xe, XE_CACHE_NONE_COMPRESSION) :
+ 					  xe_cache_pat_idx(xe, XE_CACHE_WB);
  	else
- 		pat_index = xe->pat.idx[XE_CACHE_WB];
+ 		pat_index = xe_cache_pat_idx(xe, XE_CACHE_WB);
  
  	ptes = DIV_ROUND_UP(size, XE_PAGE_SIZE);
  
@@@ -727,7 -728,22 +728,22 @@@ static void emit_copy_ccs(struct xe_gt 
  	bb->len = cs - bb->cs;
  }
  
- #define EMIT_COPY_DW 10
+ static u32 blt_fast_copy_cmd_len(struct xe_device *xe)
+ {
+ 	return 10;
+ }
+ 
+ static u32 blt_mem_copy_cmd_len(struct xe_device *xe)
+ {
+ 	return 10;
+ }
+ 
+ static u32 emit_copy_cmd_len(struct xe_device *xe)
+ {
+ 	return (xe->info.has_mem_copy_instr) ? blt_mem_copy_cmd_len(xe) :
+ 		  blt_fast_copy_cmd_len(xe);
+ }
+ 
  static void emit_xy_fast_copy(struct xe_gt *gt, struct xe_bb *bb, u64 src_ofs,
  			      u64 dst_ofs, unsigned int size,
  			      unsigned int pitch)
@@@ -735,6 -751,7 +751,7 @@@
  	struct xe_device *xe = gt_to_xe(gt);
  	u32 mocs = 0;
  	u32 tile_y = 0;
+ 	u32 len;
  
  	xe_gt_assert(gt, !(pitch & 3));
  	xe_gt_assert(gt, size / pitch <= S16_MAX);
@@@ -747,7 -764,8 +764,8 @@@
  	if (GRAPHICS_VERx100(xe) >= 1250)
  		tile_y = XY_FAST_COPY_BLT_D1_SRC_TILE4 | XY_FAST_COPY_BLT_D1_DST_TILE4;
  
- 	bb->cs[bb->len++] = XY_FAST_COPY_BLT_CMD | (10 - 2);
+ 	len = blt_fast_copy_cmd_len(xe);
+ 	bb->cs[bb->len++] = XY_FAST_COPY_BLT_CMD | (len - 2);
  	bb->cs[bb->len++] = XY_FAST_COPY_BLT_DEPTH_32 | pitch | tile_y | mocs;
  	bb->cs[bb->len++] = 0;
  	bb->cs[bb->len++] = (size / pitch) << 16 | pitch / 4;
@@@ -764,6 -782,7 +782,7 @@@ static void emit_mem_copy(struct xe_gt 
  			  u64 dst_ofs, unsigned int size, unsigned int pitch)
  {
  	u32 mode, copy_type, width;
+ 	u32 len;
  
  	xe_gt_assert(gt, IS_ALIGNED(size, pitch));
  	xe_gt_assert(gt, pitch <= U16_MAX);
@@@ -789,7 -808,9 +808,9 @@@
  
  	xe_gt_assert(gt, width <= U16_MAX);
  
- 	bb->cs[bb->len++] = MEM_COPY_CMD | mode | copy_type;
+ 	len = blt_mem_copy_cmd_len(gt_to_xe(gt));
+ 
+ 	bb->cs[bb->len++] = MEM_COPY_CMD | mode | copy_type | (len - 2);
  	bb->cs[bb->len++] = width - 1;
  	bb->cs[bb->len++] = size / pitch - 1; /* ignored by hw for page-copy/linear above */
  	bb->cs[bb->len++] = pitch - 1;
@@@ -966,7 -987,7 +987,7 @@@ static struct dma_fence *__xe_migrate_c
  		}
  
  		/* Add copy commands size here */
- 		batch_size += ((copy_only_ccs) ? 0 : EMIT_COPY_DW) +
+ 		batch_size += ((copy_only_ccs) ? 0 : emit_copy_cmd_len(xe)) +
  			((needs_ccs_emit ? EMIT_COPY_CCS_DW : 0));
  
  		bb = xe_bb_new(gt, batch_size, usm);
@@@ -1405,7 -1426,7 +1426,7 @@@ struct dma_fence *xe_migrate_vram_copy_
  
  		batch_size += pte_update_size(m, 0, sysmem, &sysmem_it, &vram_L0, &sysmem_L0_ofs,
  					      &sysmem_L0_pt, 0, avail_pts, avail_pts);
- 		batch_size += EMIT_COPY_DW;
+ 		batch_size += emit_copy_cmd_len(xe);
  
  		bb = xe_bb_new(gt, batch_size, usm);
  		if (IS_ERR(bb)) {
@@@ -1460,12 -1481,17 +1481,17 @@@
  	return fence;
  }
  
+ static u32 blt_mem_set_cmd_len(struct xe_device *xe)
+ {
+ 	return 7;
+ }
+ 
  static void emit_clear_link_copy(struct xe_gt *gt, struct xe_bb *bb, u64 src_ofs,
  				 u32 size, u32 pitch)
  {
  	struct xe_device *xe = gt_to_xe(gt);
  	u32 *cs = bb->cs + bb->len;
- 	u32 len = PVC_MEM_SET_CMD_LEN_DW;
+ 	u32 len = blt_mem_set_cmd_len(xe);
  
  	*cs++ = PVC_MEM_SET_CMD | PVC_MEM_SET_MATRIX | (len - 2);
  	*cs++ = pitch - 1;
@@@ -1483,15 -1509,21 +1509,21 @@@
  	bb->len += len;
  }
  
+ static u32 blt_fast_color_cmd_len(struct xe_device *xe)
+ {
+ 	if (GRAPHICS_VERx100(xe) >= 1250)
+ 		return 16;
+ 	else
+ 		return 11;
+ }
+ 
  static void emit_clear_main_copy(struct xe_gt *gt, struct xe_bb *bb,
  				 u64 src_ofs, u32 size, u32 pitch, bool is_vram)
  {
  	struct xe_device *xe = gt_to_xe(gt);
  	u32 *cs = bb->cs + bb->len;
- 	u32 len = XY_FAST_COLOR_BLT_DW;
+ 	u32 len = blt_fast_color_cmd_len(xe);
  
- 	if (GRAPHICS_VERx100(xe) < 1250)
- 		len = 11;
  
  	*cs++ = XY_FAST_COLOR_BLT_CMD | XY_FAST_COLOR_BLT_DEPTH_32 |
  		(len - 2);
@@@ -1526,10 -1558,12 +1558,12 @@@
  
  static u32 emit_clear_cmd_len(struct xe_gt *gt)
  {
+ 	struct xe_device *xe = gt_to_xe(gt);
+ 
  	if (gt->info.has_xe2_blt_instructions)
- 		return PVC_MEM_SET_CMD_LEN_DW;
+ 		return blt_mem_set_cmd_len(xe);
  	else
- 		return XY_FAST_COLOR_BLT_DW;
+ 		return blt_fast_color_cmd_len(xe);
  }
  
  static void emit_clear(struct xe_gt *gt, struct xe_bb *bb, u64 src_ofs,
@@@ -1862,7 -1896,7 +1896,7 @@@ __xe_migrate_update_pgtables(struct xe_
  
  	/* For sysmem PTE's, need to map them in our hole.. */
  	if (!IS_DGFX(xe)) {
- 		u16 pat_index = xe->pat.idx[XE_CACHE_WB];
+ 		u16 pat_index = xe_cache_pat_idx(xe, XE_CACHE_WB);
  		u32 ptes, ofs;
  
  		ppgtt_ofs = NUM_KERNEL_PDE - 1;
@@@ -2084,7 -2118,7 +2118,7 @@@ static void build_pt_update_batch_sram(
  				       struct drm_pagemap_addr *sram_addr,
  				       u32 size, int level)
  {
- 	u16 pat_index = tile_to_xe(m->tile)->pat.idx[XE_CACHE_WB];
+ 	u16 pat_index = xe_cache_pat_idx(tile_to_xe(m->tile), XE_CACHE_WB);
  	u64 gpu_page_size = 0x1ull << xe_pt_shift(level);
  	u32 ptes;
  	int i = 0;
@@@ -2202,7 -2236,7 +2236,7 @@@ static struct dma_fence *xe_migrate_vra
  	xe_assert(xe, npages * PAGE_SIZE <= MAX_PREEMPTDISABLE_TRANSFER);
  
  	batch_size += pte_update_cmd_size(npages << PAGE_SHIFT);
- 	batch_size += EMIT_COPY_DW;
+ 	batch_size += emit_copy_cmd_len(xe);
  
  	bb = xe_bb_new(gt, batch_size, use_usm_batch);
  	if (IS_ERR(bb)) {

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-04-14 13:08 Mark Brown
  2026-04-14 13:12 ` Miguel Ojeda
  0 siblings, 1 reply; 28+ messages in thread
From: Mark Brown @ 2026-04-14 13:08 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Asahi Lina, Danilo Krummrich, Joel Fernandes,
	Linux Kernel Mailing List, Linux Next Mailing List, Miguel Ojeda

[-- Attachment #1: Type: text/plain, Size: 3600 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  rust/kernel/lib.rs

between commit:

  d1aa40daa777c ("rust: kbuild: remove `feature(...)`s that are now stable")

from the origin tree and commits:

  f9f0b4a1f35d3 ("rust: interop: Add list module for C linked list interface")
  80df573af9ef3 ("rust: drm: gem: shmem: Add DRM shmem helper abstraction")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined rust/kernel/lib.rs
index 5d22892447bdd,40de00ce4f971..0000000000000
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@@ -16,17 -16,50 +16,17 @@@
  // Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
  // the unstable features in use.
  //
 -// Stable since Rust 1.79.0.
 -#![feature(generic_nonzero)]
 -#![feature(inline_const)]
 -#![feature(pointer_is_aligned)]
 -#![feature(slice_ptr_len)]
 -//
 -// Stable since Rust 1.80.0.
 -#![feature(slice_flatten)]
 -//
 -// Stable since Rust 1.81.0.
 -#![feature(lint_reasons)]
 -//
 -// Stable since Rust 1.82.0.
 -#![feature(offset_of_nested)]
 -#![feature(raw_ref_op)]
 -//
 -// Stable since Rust 1.83.0.
 -#![feature(const_maybe_uninit_as_mut_ptr)]
 -#![feature(const_mut_refs)]
 -#![feature(const_option)]
 -#![feature(const_ptr_write)]
 -#![feature(const_refs_to_cell)]
 -#![feature(const_refs_to_static)]
 -//
 -// Stable since Rust 1.84.0.
 -#![feature(strict_provenance)]
 -//
  // Stable since Rust 1.89.0.
  #![feature(generic_arg_infer)]
  //
  // Expected to become stable.
  #![feature(arbitrary_self_types)]
 +#![feature(derive_coerce_pointee)]
  //
  // To be determined.
  #![feature(used_with_arg)]
  //
 -// `feature(derive_coerce_pointee)` is expected to become stable. Before Rust
 -// 1.84.0, it did not exist, so enable the predecessor features.
 -#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))]
 -#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))]
 -#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))]
 -#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))]
 -//
 -// `feature(file_with_nul)` is expected to become stable. Before Rust 1.89.0, it did not exist, so
 +// `feature(file_with_nul)` is stable since Rust 1.92.0. Before Rust 1.89.0, it did not exist, so
  // enable it conditionally.
  #![cfg_attr(CONFIG_RUSTC_HAS_FILE_WITH_NUL, feature(file_with_nul))]
  
@@@ -49,6 -82,7 +49,6 @@@ pub mod bits
  #[cfg(CONFIG_BLOCK)]
  pub mod block;
  pub mod bug;
 -#[doc(hidden)]
  pub mod build_assert;
  pub mod clk;
  #[cfg(CONFIG_CONFIGFS_FS)]
@@@ -72,12 -106,15 +72,15 @@@ pub mod faux
  pub mod firmware;
  pub mod fmt;
  pub mod fs;
+ #[cfg(CONFIG_GPU_BUDDY = "y")]
+ pub mod gpu;
  #[cfg(CONFIG_I2C = "y")]
  pub mod i2c;
  pub mod id_pool;
  #[doc(hidden)]
  pub mod impl_flags;
  pub mod init;
+ pub mod interop;
  pub mod io;
  pub mod ioctl;
  pub mod iommu;
@@@ -116,8 -153,10 +119,8 @@@ pub mod scatterlist
  pub mod security;
  pub mod seq_file;
  pub mod sizes;
 -pub mod slice;
  #[cfg(CONFIG_SOC_BUS)]
  pub mod soc;
 -mod static_assert;
  #[doc(hidden)]
  pub mod std_vendor;
  pub mod str;

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-30 15:49 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-30 15:49 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List,
	Maarten Lankhorst, Matthew Brost, Thomas Hellström,
	Dnyaneshwar Bhadane

[-- Attachment #1: Type: text/plain, Size: 21688 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_ggtt.c

between commit:

  01f2557aa684e ("drm/xe: Open-code GGTT MMIO access protection")

from the origin tree and commit:

  e904c56ba6e0d ("drm/xe: Rewrite GGTT VF initialization")
  225d02cb46d0e ("drm/xe: Issue GGTT invalidation under lock in ggtt_node_remove")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/xe/xe_ggtt.c
index d1561ebe4e56c,a848d1a41b9b9..0000000000000
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@@ -66,12 -66,14 +66,14 @@@
   * give us the correct placement for free.
   */
  
+ #define XE_GGTT_FLAGS_64K	BIT(0)
+ #define XE_GGTT_FLAGS_ONLINE	BIT(1)
+ 
  /**
   * struct xe_ggtt_node - A node in GGTT.
   *
-  * This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node
-  * insertion, reservation, or 'ballooning'.
-  * It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon().
+  * This struct is allocated with xe_ggtt_insert_node(,_transform) or xe_ggtt_insert_bo(,_at).
+  * It will be deallocated using xe_ggtt_node_remove().
   */
  struct xe_ggtt_node {
  	/** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */
@@@ -84,6 -86,63 +86,63 @@@
  	bool invalidate_on_remove;
  };
  
+ /**
+  * struct xe_ggtt_pt_ops - GGTT Page table operations
+  * Which can vary from platform to platform.
+  */
+ struct xe_ggtt_pt_ops {
+ 	/** @pte_encode_flags: Encode PTE flags for a given BO */
+ 	u64 (*pte_encode_flags)(struct xe_bo *bo, u16 pat_index);
+ 
+ 	/** @ggtt_set_pte: Directly write into GGTT's PTE */
+ 	xe_ggtt_set_pte_fn ggtt_set_pte;
+ 
+ 	/** @ggtt_get_pte: Directly read from GGTT's PTE */
+ 	u64 (*ggtt_get_pte)(struct xe_ggtt *ggtt, u64 addr);
+ };
+ 
+ /**
+  * struct xe_ggtt - Main GGTT struct
+  *
+  * In general, each tile can contains its own Global Graphics Translation Table
+  * (GGTT) instance.
+  */
+ struct xe_ggtt {
+ 	/** @tile: Back pointer to tile where this GGTT belongs */
+ 	struct xe_tile *tile;
+         /** @start: Start offset of GGTT */
+ 	u64 start;
+ 	/** @size: Total usable size of this GGTT */
+ 	u64 size;
+ 
+ #define XE_GGTT_FLAGS_64K BIT(0)
+ 	/**
+ 	 * @flags: Flags for this GGTT
+ 	 * Acceptable flags:
+ 	 * - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
+ 	 * - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock
+ 	 *   after init
+ 	 */
+ 	unsigned int flags;
+ 	/** @scratch: Internal object allocation used as a scratch page */
+ 	struct xe_bo *scratch;
+ 	/** @lock: Mutex lock to protect GGTT data */
+ 	struct mutex lock;
+ 	/**
+ 	 *  @gsm: The iomem pointer to the actual location of the translation
+ 	 * table located in the GSM for easy PTE manipulation
+ 	 */
+ 	u64 __iomem *gsm;
+ 	/** @pt_ops: Page Table operations per platform */
+ 	const struct xe_ggtt_pt_ops *pt_ops;
+ 	/** @mm: The memory manager used to manage individual GGTT allocations */
+ 	struct drm_mm mm;
+ 	/** @access_count: counts GGTT writes */
+ 	unsigned int access_count;
+ 	/** @wq: Dedicated unordered work queue to process node removals */
+ 	struct workqueue_struct *wq;
+ };
+ 
  static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index)
  {
  	u64 pte = XE_PAGE_PRESENT;
@@@ -193,7 -252,7 +252,7 @@@ static void xe_ggtt_set_pte_and_flush(s
  static u64 xe_ggtt_get_pte(struct xe_ggtt *ggtt, u64 addr)
  {
  	xe_tile_assert(ggtt->tile, !(addr & XE_PTE_MASK));
- 	xe_tile_assert(ggtt->tile, addr < ggtt->size);
+ 	xe_tile_assert(ggtt->tile, addr < ggtt->start + ggtt->size);
  
  	return readq(&ggtt->gsm[addr >> XE_PTE_SHIFT]);
  }
@@@ -299,7 -358,7 +358,7 @@@ static void __xe_ggtt_init_early(struc
  {
  	ggtt->start = start;
  	ggtt->size = size;
- 	drm_mm_init(&ggtt->mm, start, size);
+ 	drm_mm_init(&ggtt->mm, 0, size);
  }
  
  int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size)
@@@ -349,9 -408,15 +408,15 @@@ int xe_ggtt_init_early(struct xe_ggtt *
  		ggtt_start = wopcm;
  		ggtt_size = (gsm_size / 8) * (u64)XE_PAGE_SIZE - ggtt_start;
  	} else {
- 		/* GGTT is expected to be 4GiB */
- 		ggtt_start = wopcm;
- 		ggtt_size = SZ_4G - ggtt_start;
+ 		ggtt_start = xe_tile_sriov_vf_ggtt_base(ggtt->tile);
+ 		ggtt_size = xe_tile_sriov_vf_ggtt(ggtt->tile);
+ 
+ 		if (ggtt_start < wopcm ||
+ 		    ggtt_start + ggtt_size > GUC_GGTT_TOP) {
+ 			xe_tile_err(ggtt->tile, "Invalid GGTT configuration: %#llx-%#llx\n",
+ 				    ggtt_start, ggtt_start + ggtt_size - 1);
+ 			return -ERANGE;
+ 		}
  	}
  
  	ggtt->gsm = ggtt->tile->mmio.regs + SZ_8M;
@@@ -369,7 -434,7 +434,7 @@@
  	else
  		ggtt->pt_ops = &xelp_pt_ops;
  
- 	ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM, 0);
+ 	ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
  	if (!ggtt->wq)
  		return -ENOMEM;
  
@@@ -380,17 -445,7 +445,7 @@@
  		return err;
  
  	ggtt->flags |= XE_GGTT_FLAGS_ONLINE;
- 	err = devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
- 	if (err)
- 		return err;
- 
- 	if (IS_SRIOV_VF(xe)) {
- 		err = xe_tile_sriov_vf_prepare_ggtt(ggtt->tile);
- 		if (err)
- 			return err;
- 	}
- 
- 	return 0;
+ 	return devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
  }
  ALLOW_ERROR_INJECTION(xe_ggtt_init_early, ERRNO); /* See xe_pci_probe() */
  
@@@ -404,12 -459,17 +459,17 @@@ static void xe_ggtt_initial_clear(struc
  	/* Display may have allocated inside ggtt, so be careful with clearing here */
  	mutex_lock(&ggtt->lock);
  	drm_mm_for_each_hole(hole, &ggtt->mm, start, end)
- 		xe_ggtt_clear(ggtt, start, end - start);
+ 		xe_ggtt_clear(ggtt, ggtt->start + start, end - start);
  
  	xe_ggtt_invalidate(ggtt);
  	mutex_unlock(&ggtt->lock);
  }
  
+ static void ggtt_node_fini(struct xe_ggtt_node *node)
+ {
+ 	kfree(node);
+ }
+ 
  static void ggtt_node_remove(struct xe_ggtt_node *node)
  {
  	struct xe_ggtt *ggtt = node->ggtt;
@@@ -418,19 -478,14 +478,14 @@@
  	mutex_lock(&ggtt->lock);
  	bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE;
  	if (bound)
- 		xe_ggtt_clear(ggtt, node->base.start, node->base.size);
+ 		xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));
  	drm_mm_remove_node(&node->base);
  	node->base.size = 0;
+ 	if (bound && node->invalidate_on_remove)
+ 		xe_ggtt_invalidate(ggtt);
  	mutex_unlock(&ggtt->lock);
  
- 	if (!bound)
- 		goto free_node;
- 
- 	if (node->invalidate_on_remove)
- 		xe_ggtt_invalidate(ggtt);
- 
- free_node:
- 	xe_ggtt_node_fini(node);
+ 	ggtt_node_fini(node);
  }
  
  static void ggtt_node_remove_work_func(struct work_struct *work)
@@@ -536,169 -591,38 +591,38 @@@ static void xe_ggtt_invalidate(struct x
  	ggtt_invalidate_gt_tlb(ggtt->tile->media_gt);
  }
  
- static void xe_ggtt_dump_node(struct xe_ggtt *ggtt,
- 			      const struct drm_mm_node *node, const char *description)
- {
- 	char buf[10];
- 
- 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) {
- 		string_get_size(node->size, 1, STRING_UNITS_2, buf, sizeof(buf));
- 		xe_tile_dbg(ggtt->tile, "GGTT %#llx-%#llx (%s) %s\n",
- 			    node->start, node->start + node->size, buf, description);
- 	}
- }
- 
  /**
-  * xe_ggtt_node_insert_balloon_locked - prevent allocation of specified GGTT addresses
-  * @node: the &xe_ggtt_node to hold reserved GGTT node
-  * @start: the starting GGTT address of the reserved region
-  * @end: then end GGTT address of the reserved region
-  *
-  * To be used in cases where ggtt->lock is already taken.
-  * Use xe_ggtt_node_remove_balloon_locked() to release a reserved GGTT node.
-  *
-  * Return: 0 on success or a negative error code on failure.
-  */
- int xe_ggtt_node_insert_balloon_locked(struct xe_ggtt_node *node, u64 start, u64 end)
- {
- 	struct xe_ggtt *ggtt = node->ggtt;
- 	int err;
- 
- 	xe_tile_assert(ggtt->tile, start < end);
- 	xe_tile_assert(ggtt->tile, IS_ALIGNED(start, XE_PAGE_SIZE));
- 	xe_tile_assert(ggtt->tile, IS_ALIGNED(end, XE_PAGE_SIZE));
- 	xe_tile_assert(ggtt->tile, !drm_mm_node_allocated(&node->base));
- 	lockdep_assert_held(&ggtt->lock);
- 
- 	node->base.color = 0;
- 	node->base.start = start;
- 	node->base.size = end - start;
- 
- 	err = drm_mm_reserve_node(&ggtt->mm, &node->base);
- 
- 	if (xe_tile_WARN(ggtt->tile, err, "Failed to balloon GGTT %#llx-%#llx (%pe)\n",
- 			 node->base.start, node->base.start + node->base.size, ERR_PTR(err)))
- 		return err;
- 
- 	xe_ggtt_dump_node(ggtt, &node->base, "balloon");
- 	return 0;
- }
- 
- /**
-  * xe_ggtt_node_remove_balloon_locked - release a reserved GGTT region
-  * @node: the &xe_ggtt_node with reserved GGTT region
-  *
-  * To be used in cases where ggtt->lock is already taken.
-  * See xe_ggtt_node_insert_balloon_locked() for details.
-  */
- void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node)
- {
- 	if (!xe_ggtt_node_allocated(node))
- 		return;
- 
- 	lockdep_assert_held(&node->ggtt->lock);
- 
- 	xe_ggtt_dump_node(node->ggtt, &node->base, "remove-balloon");
- 
- 	drm_mm_remove_node(&node->base);
- }
- 
- static void xe_ggtt_assert_fit(struct xe_ggtt *ggtt, u64 start, u64 size)
- {
- 	struct xe_tile *tile = ggtt->tile;
- 
- 	xe_tile_assert(tile, start >= ggtt->start);
- 	xe_tile_assert(tile, start + size <= ggtt->start + ggtt->size);
- }
- 
- /**
-  * xe_ggtt_shift_nodes_locked - Shift GGTT nodes to adjust for a change in usable address range.
+  * xe_ggtt_shift_nodes() - Shift GGTT nodes to adjust for a change in usable address range.
   * @ggtt: the &xe_ggtt struct instance
-  * @shift: change to the location of area provisioned for current VF
+  * @new_start: new location of area provisioned for current VF
   *
-  * This function moves all nodes from the GGTT VM, to a temp list. These nodes are expected
-  * to represent allocations in range formerly assigned to current VF, before the range changed.
-  * When the GGTT VM is completely clear of any nodes, they are re-added with shifted offsets.
+  * Ensure that all struct &xe_ggtt_node are moved to the @new_start base address
+  * by changing the base offset of the GGTT.
   *
-  * The function has no ability of failing - because it shifts existing nodes, without
-  * any additional processing. If the nodes were successfully existing at the old address,
-  * they will do the same at the new one. A fail inside this function would indicate that
-  * the list of nodes was either already damaged, or that the shift brings the address range
-  * outside of valid bounds. Both cases justify an assert rather than error code.
+  * This function may be called multiple times during recovery, but if
+  * @new_start is unchanged from the current base, it's a noop.
+  *
+  * @new_start should be a value between xe_wopcm_size() and #GUC_GGTT_TOP.
   */
- void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift)
+ void xe_ggtt_shift_nodes(struct xe_ggtt *ggtt, u64 new_start)
  {
- 	struct xe_tile *tile __maybe_unused = ggtt->tile;
- 	struct drm_mm_node *node, *tmpn;
- 	LIST_HEAD(temp_list_head);
+ 	guard(mutex)(&ggtt->lock);
  
- 	lockdep_assert_held(&ggtt->lock);
+ 	xe_tile_assert(ggtt->tile, new_start >= xe_wopcm_size(tile_to_xe(ggtt->tile)));
+ 	xe_tile_assert(ggtt->tile, new_start + ggtt->size <= GUC_GGTT_TOP);
  
- 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG))
- 		drm_mm_for_each_node_safe(node, tmpn, &ggtt->mm)
- 			xe_ggtt_assert_fit(ggtt, node->start + shift, node->size);
- 
- 	drm_mm_for_each_node_safe(node, tmpn, &ggtt->mm) {
- 		drm_mm_remove_node(node);
- 		list_add(&node->node_list, &temp_list_head);
- 	}
- 
- 	list_for_each_entry_safe(node, tmpn, &temp_list_head, node_list) {
- 		list_del(&node->node_list);
- 		node->start += shift;
- 		drm_mm_reserve_node(&ggtt->mm, node);
- 		xe_tile_assert(tile, drm_mm_node_allocated(node));
- 	}
+ 	/* pairs with READ_ONCE in xe_ggtt_node_addr() */
+ 	WRITE_ONCE(ggtt->start, new_start);
  }
  
- static int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
+ static int xe_ggtt_insert_node_locked(struct xe_ggtt_node *node,
  				      u32 size, u32 align, u32 mm_flags)
  {
  	return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0,
  					  mm_flags);
  }
  
- /**
-  * xe_ggtt_node_insert - Insert a &xe_ggtt_node into the GGTT
-  * @node: the &xe_ggtt_node to be inserted
-  * @size: size of the node
-  * @align: alignment constrain of the node
-  *
-  * It cannot be called without first having called xe_ggtt_init() once.
-  *
-  * Return: 0 on success or a negative error code on failure.
-  */
- int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align)
- {
- 	int ret;
- 
- 	if (!node || !node->ggtt)
- 		return -ENOENT;
- 
- 	mutex_lock(&node->ggtt->lock);
- 	ret = xe_ggtt_node_insert_locked(node, size, align,
- 					 DRM_MM_INSERT_HIGH);
- 	mutex_unlock(&node->ggtt->lock);
- 
- 	return ret;
- }
- 
- /**
-  * xe_ggtt_node_init - Initialize %xe_ggtt_node struct
-  * @ggtt: the &xe_ggtt where the new node will later be inserted/reserved.
-  *
-  * This function will allocate the struct %xe_ggtt_node and return its pointer.
-  * This struct will then be freed after the node removal upon xe_ggtt_node_remove()
-  * or xe_ggtt_node_remove_balloon_locked().
-  *
-  * Having %xe_ggtt_node struct allocated doesn't mean that the node is already
-  * allocated in GGTT. Only xe_ggtt_node_insert(), allocation through
-  * xe_ggtt_node_insert_transform(), or xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved
-  * in GGTT.
-  *
-  * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
-  **/
- struct xe_ggtt_node *xe_ggtt_node_init(struct xe_ggtt *ggtt)
+ static struct xe_ggtt_node *ggtt_node_init(struct xe_ggtt *ggtt)
  {
  	struct xe_ggtt_node *node = kzalloc_obj(*node, GFP_NOFS);
  
@@@ -712,30 -636,31 +636,31 @@@
  }
  
  /**
-  * xe_ggtt_node_fini - Forcebly finalize %xe_ggtt_node struct
-  * @node: the &xe_ggtt_node to be freed
+  * xe_ggtt_insert_node - Insert a &xe_ggtt_node into the GGTT
+  * @ggtt: the &xe_ggtt into which the node should be inserted.
+  * @size: size of the node
+  * @align: alignment constrain of the node
   *
-  * If anything went wrong with either xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(),
-  * or xe_ggtt_node_insert_balloon_locked(); and this @node is not going to be reused, then,
-  * this function needs to be called to free the %xe_ggtt_node struct
-  **/
- void xe_ggtt_node_fini(struct xe_ggtt_node *node)
- {
- 	kfree(node);
- }
- 
- /**
-  * xe_ggtt_node_allocated - Check if node is allocated in GGTT
-  * @node: the &xe_ggtt_node to be inspected
-  *
-  * Return: True if allocated, False otherwise.
+  * Return: &xe_ggtt_node on success or a ERR_PTR on failure.
   */
- bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node)
+ struct xe_ggtt_node *xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 align)
  {
- 	if (!node || !node->ggtt)
- 		return false;
+ 	struct xe_ggtt_node *node;
+ 	int ret;
  
- 	return drm_mm_node_allocated(&node->base);
+ 	node = ggtt_node_init(ggtt);
+ 	if (IS_ERR(node))
+ 		return node;
+ 
+ 	guard(mutex)(&ggtt->lock);
+ 	ret = xe_ggtt_insert_node_locked(node, size, align,
+ 					 DRM_MM_INSERT_HIGH);
+ 	if (ret) {
+ 		ggtt_node_fini(node);
+ 		return ERR_PTR(ret);
+ 	}
+ 
+ 	return node;
  }
  
  /**
@@@ -768,7 -693,7 +693,7 @@@ static void xe_ggtt_map_bo(struct xe_gg
  	if (XE_WARN_ON(!node))
  		return;
  
- 	start = node->base.start;
+ 	start = xe_ggtt_node_addr(node);
  	end = start + xe_bo_size(bo);
  
  	if (!xe_bo_is_vram(bo) && !xe_bo_is_stolen(bo)) {
@@@ -809,7 -734,7 +734,7 @@@ void xe_ggtt_map_bo_unlocked(struct xe_
  }
  
  /**
-  * xe_ggtt_node_insert_transform - Insert a newly allocated &xe_ggtt_node into the GGTT
+  * xe_ggtt_insert_node_transform - Insert a newly allocated &xe_ggtt_node into the GGTT
   * @ggtt: the &xe_ggtt where the node will inserted/reserved.
   * @bo: The bo to be transformed
   * @pte_flags: The extra GGTT flags to add to mapping.
@@@ -823,7 -748,7 +748,7 @@@
   *
   * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
   */
- struct xe_ggtt_node *xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt,
+ struct xe_ggtt_node *xe_ggtt_insert_node_transform(struct xe_ggtt *ggtt,
  						   struct xe_bo *bo, u64 pte_flags,
  						   u64 size, u32 align,
  						   xe_ggtt_transform_cb transform, void *arg)
@@@ -831,7 -756,7 +756,7 @@@
  	struct xe_ggtt_node *node;
  	int ret;
  
- 	node = xe_ggtt_node_init(ggtt);
+ 	node = ggtt_node_init(ggtt);
  	if (IS_ERR(node))
  		return ERR_CAST(node);
  
@@@ -840,7 -765,7 +765,7 @@@
  		goto err;
  	}
  
- 	ret = xe_ggtt_node_insert_locked(node, size, align, 0);
+ 	ret = xe_ggtt_insert_node_locked(node, size, align, 0);
  	if (ret)
  		goto err_unlock;
  
@@@ -855,7 -780,7 +780,7 @@@
  err_unlock:
  	mutex_unlock(&ggtt->lock);
  err:
- 	xe_ggtt_node_fini(node);
+ 	ggtt_node_fini(node);
  	return ERR_PTR(ret);
  }
  
@@@ -881,7 -806,7 +806,7 @@@ static int __xe_ggtt_insert_bo_at(struc
  
  	xe_pm_runtime_get_noresume(tile_to_xe(ggtt->tile));
  
- 	bo->ggtt_node[tile_id] = xe_ggtt_node_init(ggtt);
+ 	bo->ggtt_node[tile_id] = ggtt_node_init(ggtt);
  	if (IS_ERR(bo->ggtt_node[tile_id])) {
  		err = PTR_ERR(bo->ggtt_node[tile_id]);
  		bo->ggtt_node[tile_id] = NULL;
@@@ -889,10 -814,30 +814,30 @@@
  	}
  
  	mutex_lock(&ggtt->lock);
+ 	/*
+ 	 * When inheriting the initial framebuffer, the framebuffer is
+ 	 * physically located at VRAM address 0, and usually at GGTT address 0 too.
+ 	 *
+ 	 * The display code will ask for a GGTT allocation between end of BO and
+ 	 * remainder of GGTT, unaware that the start is reserved by WOPCM.
+ 	 */
+ 	if (start >= ggtt->start)
+ 		start -= ggtt->start;
+ 	else
+ 		start = 0;
+ 
+ 	/* Should never happen, but since we handle start, fail graciously for end */
+ 	if (end >= ggtt->start)
+ 		end -= ggtt->start;
+ 	else
+ 		end = 0;
+ 
+ 	xe_tile_assert(ggtt->tile, end >= start + xe_bo_size(bo));
+ 
  	err = drm_mm_insert_node_in_range(&ggtt->mm, &bo->ggtt_node[tile_id]->base,
  					  xe_bo_size(bo), alignment, 0, start, end, 0);
  	if (err) {
- 		xe_ggtt_node_fini(bo->ggtt_node[tile_id]);
+ 		ggtt_node_fini(bo->ggtt_node[tile_id]);
  		bo->ggtt_node[tile_id] = NULL;
  	} else {
  		u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
@@@ -1000,18 -945,16 +945,16 @@@ static u64 xe_encode_vfid_pte(u16 vfid
  	return FIELD_PREP(GGTT_PTE_VFID, vfid) | XE_PAGE_PRESENT;
  }
  
- static void xe_ggtt_assign_locked(struct xe_ggtt *ggtt, const struct drm_mm_node *node, u16 vfid)
+ static void xe_ggtt_assign_locked(const struct xe_ggtt_node *node, u16 vfid)
  {
- 	u64 start = node->start;
- 	u64 size = node->size;
+ 	struct xe_ggtt *ggtt = node->ggtt;
+ 	u64 start = xe_ggtt_node_addr(node);
+ 	u64 size = xe_ggtt_node_size(node);
  	u64 end = start + size - 1;
  	u64 pte = xe_encode_vfid_pte(vfid);
  
  	lockdep_assert_held(&ggtt->lock);
  
- 	if (!drm_mm_node_allocated(node))
- 		return;
- 
  	while (start < end) {
  		ggtt->pt_ops->ggtt_set_pte(ggtt, start, pte);
  		start += XE_PAGE_SIZE;
@@@ -1031,9 -974,8 +974,8 @@@
   */
  void xe_ggtt_assign(const struct xe_ggtt_node *node, u16 vfid)
  {
- 	mutex_lock(&node->ggtt->lock);
- 	xe_ggtt_assign_locked(node->ggtt, &node->base, vfid);
- 	mutex_unlock(&node->ggtt->lock);
+ 	guard(mutex)(&node->ggtt->lock);
+ 	xe_ggtt_assign_locked(node, vfid);
  }
  
  /**
@@@ -1055,14 -997,14 +997,14 @@@ int xe_ggtt_node_save(struct xe_ggtt_no
  	if (!node)
  		return -ENOENT;
  
- 	guard(mutex)(&node->ggtt->lock);
+ 	ggtt = node->ggtt;
+ 	guard(mutex)(&ggtt->lock);
  
  	if (xe_ggtt_node_pt_size(node) != size)
  		return -EINVAL;
  
- 	ggtt = node->ggtt;
- 	start = node->base.start;
- 	end = start + node->base.size - 1;
+ 	start = xe_ggtt_node_addr(node);
+ 	end = start + xe_ggtt_node_size(node) - 1;
  
  	while (start < end) {
  		pte = ggtt->pt_ops->ggtt_get_pte(ggtt, start);
@@@ -1095,14 -1037,14 +1037,14 @@@ int xe_ggtt_node_load(struct xe_ggtt_no
  	if (!node)
  		return -ENOENT;
  
- 	guard(mutex)(&node->ggtt->lock);
+ 	ggtt = node->ggtt;
+ 	guard(mutex)(&ggtt->lock);
  
  	if (xe_ggtt_node_pt_size(node) != size)
  		return -EINVAL;
  
- 	ggtt = node->ggtt;
- 	start = node->base.start;
- 	end = start + node->base.size - 1;
+ 	start = xe_ggtt_node_addr(node);
+ 	end = start + xe_ggtt_node_size(node) - 1;
  
  	while (start < end) {
  		vfid_pte = u64_replace_bits(*buf++, vfid, GGTT_PTE_VFID);
@@@ -1209,7 -1151,8 +1151,8 @@@ u64 xe_ggtt_read_pte(struct xe_ggtt *gg
   */
  u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node)
  {
- 	return node->base.start;
+ 	/* pairs with WRITE_ONCE in xe_ggtt_shift_nodes() */
+ 	return node->base.start + READ_ONCE(node->ggtt->start);
  }
  
  /**

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-27 20:56 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-27 20:56 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List,
	Maarten Lankhorst, Matthew Brost, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 21550 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_ggtt.c

between commit:

  01f2557aa684e5 ("drm/xe: Open-code GGTT MMIO access protection")

from the origin tree and commits:

  4f3a998a173b43 ("drm/xe: Open-code GGTT MMIO access protection")
  e904c56ba6e0d4 ("drm/xe: Rewrite GGTT VF initialization")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/xe/xe_ggtt.c
index d1561ebe4e56ca,21071b64b09dfa..00000000000000
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@@ -66,12 -66,14 +66,14 @@@
   * give us the correct placement for free.
   */
  
+ #define XE_GGTT_FLAGS_64K	BIT(0)
+ #define XE_GGTT_FLAGS_ONLINE	BIT(1)
+ 
  /**
   * struct xe_ggtt_node - A node in GGTT.
   *
-  * This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node
-  * insertion, reservation, or 'ballooning'.
-  * It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon().
+  * This struct is allocated with xe_ggtt_insert_node(,_transform) or xe_ggtt_insert_bo(,_at).
+  * It will be deallocated using xe_ggtt_node_remove().
   */
  struct xe_ggtt_node {
  	/** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */
@@@ -84,6 -86,63 +86,63 @@@
  	bool invalidate_on_remove;
  };
  
+ /**
+  * struct xe_ggtt_pt_ops - GGTT Page table operations
+  * Which can vary from platform to platform.
+  */
+ struct xe_ggtt_pt_ops {
+ 	/** @pte_encode_flags: Encode PTE flags for a given BO */
+ 	u64 (*pte_encode_flags)(struct xe_bo *bo, u16 pat_index);
+ 
+ 	/** @ggtt_set_pte: Directly write into GGTT's PTE */
+ 	xe_ggtt_set_pte_fn ggtt_set_pte;
+ 
+ 	/** @ggtt_get_pte: Directly read from GGTT's PTE */
+ 	u64 (*ggtt_get_pte)(struct xe_ggtt *ggtt, u64 addr);
+ };
+ 
+ /**
+  * struct xe_ggtt - Main GGTT struct
+  *
+  * In general, each tile can contains its own Global Graphics Translation Table
+  * (GGTT) instance.
+  */
+ struct xe_ggtt {
+ 	/** @tile: Back pointer to tile where this GGTT belongs */
+ 	struct xe_tile *tile;
+         /** @start: Start offset of GGTT */
+ 	u64 start;
+ 	/** @size: Total usable size of this GGTT */
+ 	u64 size;
+ 
+ #define XE_GGTT_FLAGS_64K BIT(0)
+ 	/**
+ 	 * @flags: Flags for this GGTT
+ 	 * Acceptable flags:
+ 	 * - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
+ 	 * - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock
+ 	 *   after init
+ 	 */
+ 	unsigned int flags;
+ 	/** @scratch: Internal object allocation used as a scratch page */
+ 	struct xe_bo *scratch;
+ 	/** @lock: Mutex lock to protect GGTT data */
+ 	struct mutex lock;
+ 	/**
+ 	 *  @gsm: The iomem pointer to the actual location of the translation
+ 	 * table located in the GSM for easy PTE manipulation
+ 	 */
+ 	u64 __iomem *gsm;
+ 	/** @pt_ops: Page Table operations per platform */
+ 	const struct xe_ggtt_pt_ops *pt_ops;
+ 	/** @mm: The memory manager used to manage individual GGTT allocations */
+ 	struct drm_mm mm;
+ 	/** @access_count: counts GGTT writes */
+ 	unsigned int access_count;
+ 	/** @wq: Dedicated unordered work queue to process node removals */
+ 	struct workqueue_struct *wq;
+ };
+ 
  static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index)
  {
  	u64 pte = XE_PAGE_PRESENT;
@@@ -193,7 -252,7 +252,7 @@@ static void xe_ggtt_set_pte_and_flush(s
  static u64 xe_ggtt_get_pte(struct xe_ggtt *ggtt, u64 addr)
  {
  	xe_tile_assert(ggtt->tile, !(addr & XE_PTE_MASK));
- 	xe_tile_assert(ggtt->tile, addr < ggtt->size);
+ 	xe_tile_assert(ggtt->tile, addr < ggtt->start + ggtt->size);
  
  	return readq(&ggtt->gsm[addr >> XE_PTE_SHIFT]);
  }
@@@ -299,7 -358,7 +358,7 @@@ static void __xe_ggtt_init_early(struc
  {
  	ggtt->start = start;
  	ggtt->size = size;
- 	drm_mm_init(&ggtt->mm, start, size);
+ 	drm_mm_init(&ggtt->mm, 0, size);
  }
  
  int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size)
@@@ -349,9 -408,15 +408,15 @@@ int xe_ggtt_init_early(struct xe_ggtt *
  		ggtt_start = wopcm;
  		ggtt_size = (gsm_size / 8) * (u64)XE_PAGE_SIZE - ggtt_start;
  	} else {
- 		/* GGTT is expected to be 4GiB */
- 		ggtt_start = wopcm;
- 		ggtt_size = SZ_4G - ggtt_start;
+ 		ggtt_start = xe_tile_sriov_vf_ggtt_base(ggtt->tile);
+ 		ggtt_size = xe_tile_sriov_vf_ggtt(ggtt->tile);
+ 
+ 		if (ggtt_start < wopcm ||
+ 		    ggtt_start + ggtt_size > GUC_GGTT_TOP) {
+ 			xe_tile_err(ggtt->tile, "Invalid GGTT configuration: %#llx-%#llx\n",
+ 				    ggtt_start, ggtt_start + ggtt_size - 1);
+ 			return -ERANGE;
+ 		}
  	}
  
  	ggtt->gsm = ggtt->tile->mmio.regs + SZ_8M;
@@@ -369,7 -434,7 +434,7 @@@
  	else
  		ggtt->pt_ops = &xelp_pt_ops;
  
- 	ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM, 0);
+ 	ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
  	if (!ggtt->wq)
  		return -ENOMEM;
  
@@@ -380,17 -445,7 +445,7 @@@
  		return err;
  
  	ggtt->flags |= XE_GGTT_FLAGS_ONLINE;
- 	err = devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
- 	if (err)
- 		return err;
- 
- 	if (IS_SRIOV_VF(xe)) {
- 		err = xe_tile_sriov_vf_prepare_ggtt(ggtt->tile);
- 		if (err)
- 			return err;
- 	}
- 
- 	return 0;
+ 	return devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
  }
  ALLOW_ERROR_INJECTION(xe_ggtt_init_early, ERRNO); /* See xe_pci_probe() */
  
@@@ -404,12 -459,17 +459,17 @@@ static void xe_ggtt_initial_clear(struc
  	/* Display may have allocated inside ggtt, so be careful with clearing here */
  	mutex_lock(&ggtt->lock);
  	drm_mm_for_each_hole(hole, &ggtt->mm, start, end)
- 		xe_ggtt_clear(ggtt, start, end - start);
+ 		xe_ggtt_clear(ggtt, ggtt->start + start, end - start);
  
  	xe_ggtt_invalidate(ggtt);
  	mutex_unlock(&ggtt->lock);
  }
  
+ static void ggtt_node_fini(struct xe_ggtt_node *node)
+ {
+ 	kfree(node);
+ }
+ 
  static void ggtt_node_remove(struct xe_ggtt_node *node)
  {
  	struct xe_ggtt *ggtt = node->ggtt;
@@@ -418,7 -478,7 +478,7 @@@
  	mutex_lock(&ggtt->lock);
  	bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE;
  	if (bound)
- 		xe_ggtt_clear(ggtt, node->base.start, node->base.size);
+ 		xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));
  	drm_mm_remove_node(&node->base);
  	node->base.size = 0;
  	mutex_unlock(&ggtt->lock);
@@@ -430,7 -490,7 +490,7 @@@
  		xe_ggtt_invalidate(ggtt);
  
  free_node:
- 	xe_ggtt_node_fini(node);
+ 	ggtt_node_fini(node);
  }
  
  static void ggtt_node_remove_work_func(struct work_struct *work)
@@@ -536,169 -596,38 +596,38 @@@ static void xe_ggtt_invalidate(struct x
  	ggtt_invalidate_gt_tlb(ggtt->tile->media_gt);
  }
  
- static void xe_ggtt_dump_node(struct xe_ggtt *ggtt,
- 			      const struct drm_mm_node *node, const char *description)
- {
- 	char buf[10];
- 
- 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) {
- 		string_get_size(node->size, 1, STRING_UNITS_2, buf, sizeof(buf));
- 		xe_tile_dbg(ggtt->tile, "GGTT %#llx-%#llx (%s) %s\n",
- 			    node->start, node->start + node->size, buf, description);
- 	}
- }
- 
  /**
-  * xe_ggtt_node_insert_balloon_locked - prevent allocation of specified GGTT addresses
-  * @node: the &xe_ggtt_node to hold reserved GGTT node
-  * @start: the starting GGTT address of the reserved region
-  * @end: then end GGTT address of the reserved region
-  *
-  * To be used in cases where ggtt->lock is already taken.
-  * Use xe_ggtt_node_remove_balloon_locked() to release a reserved GGTT node.
-  *
-  * Return: 0 on success or a negative error code on failure.
-  */
- int xe_ggtt_node_insert_balloon_locked(struct xe_ggtt_node *node, u64 start, u64 end)
- {
- 	struct xe_ggtt *ggtt = node->ggtt;
- 	int err;
- 
- 	xe_tile_assert(ggtt->tile, start < end);
- 	xe_tile_assert(ggtt->tile, IS_ALIGNED(start, XE_PAGE_SIZE));
- 	xe_tile_assert(ggtt->tile, IS_ALIGNED(end, XE_PAGE_SIZE));
- 	xe_tile_assert(ggtt->tile, !drm_mm_node_allocated(&node->base));
- 	lockdep_assert_held(&ggtt->lock);
- 
- 	node->base.color = 0;
- 	node->base.start = start;
- 	node->base.size = end - start;
- 
- 	err = drm_mm_reserve_node(&ggtt->mm, &node->base);
- 
- 	if (xe_tile_WARN(ggtt->tile, err, "Failed to balloon GGTT %#llx-%#llx (%pe)\n",
- 			 node->base.start, node->base.start + node->base.size, ERR_PTR(err)))
- 		return err;
- 
- 	xe_ggtt_dump_node(ggtt, &node->base, "balloon");
- 	return 0;
- }
- 
- /**
-  * xe_ggtt_node_remove_balloon_locked - release a reserved GGTT region
-  * @node: the &xe_ggtt_node with reserved GGTT region
-  *
-  * To be used in cases where ggtt->lock is already taken.
-  * See xe_ggtt_node_insert_balloon_locked() for details.
-  */
- void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node)
- {
- 	if (!xe_ggtt_node_allocated(node))
- 		return;
- 
- 	lockdep_assert_held(&node->ggtt->lock);
- 
- 	xe_ggtt_dump_node(node->ggtt, &node->base, "remove-balloon");
- 
- 	drm_mm_remove_node(&node->base);
- }
- 
- static void xe_ggtt_assert_fit(struct xe_ggtt *ggtt, u64 start, u64 size)
- {
- 	struct xe_tile *tile = ggtt->tile;
- 
- 	xe_tile_assert(tile, start >= ggtt->start);
- 	xe_tile_assert(tile, start + size <= ggtt->start + ggtt->size);
- }
- 
- /**
-  * xe_ggtt_shift_nodes_locked - Shift GGTT nodes to adjust for a change in usable address range.
+  * xe_ggtt_shift_nodes() - Shift GGTT nodes to adjust for a change in usable address range.
   * @ggtt: the &xe_ggtt struct instance
-  * @shift: change to the location of area provisioned for current VF
+  * @new_start: new location of area provisioned for current VF
   *
-  * This function moves all nodes from the GGTT VM, to a temp list. These nodes are expected
-  * to represent allocations in range formerly assigned to current VF, before the range changed.
-  * When the GGTT VM is completely clear of any nodes, they are re-added with shifted offsets.
+  * Ensure that all struct &xe_ggtt_node are moved to the @new_start base address
+  * by changing the base offset of the GGTT.
   *
-  * The function has no ability of failing - because it shifts existing nodes, without
-  * any additional processing. If the nodes were successfully existing at the old address,
-  * they will do the same at the new one. A fail inside this function would indicate that
-  * the list of nodes was either already damaged, or that the shift brings the address range
-  * outside of valid bounds. Both cases justify an assert rather than error code.
+  * This function may be called multiple times during recovery, but if
+  * @new_start is unchanged from the current base, it's a noop.
+  *
+  * @new_start should be a value between xe_wopcm_size() and #GUC_GGTT_TOP.
   */
- void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift)
+ void xe_ggtt_shift_nodes(struct xe_ggtt *ggtt, u64 new_start)
  {
- 	struct xe_tile *tile __maybe_unused = ggtt->tile;
- 	struct drm_mm_node *node, *tmpn;
- 	LIST_HEAD(temp_list_head);
+ 	guard(mutex)(&ggtt->lock);
  
- 	lockdep_assert_held(&ggtt->lock);
+ 	xe_tile_assert(ggtt->tile, new_start >= xe_wopcm_size(tile_to_xe(ggtt->tile)));
+ 	xe_tile_assert(ggtt->tile, new_start + ggtt->size <= GUC_GGTT_TOP);
  
- 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG))
- 		drm_mm_for_each_node_safe(node, tmpn, &ggtt->mm)
- 			xe_ggtt_assert_fit(ggtt, node->start + shift, node->size);
- 
- 	drm_mm_for_each_node_safe(node, tmpn, &ggtt->mm) {
- 		drm_mm_remove_node(node);
- 		list_add(&node->node_list, &temp_list_head);
- 	}
- 
- 	list_for_each_entry_safe(node, tmpn, &temp_list_head, node_list) {
- 		list_del(&node->node_list);
- 		node->start += shift;
- 		drm_mm_reserve_node(&ggtt->mm, node);
- 		xe_tile_assert(tile, drm_mm_node_allocated(node));
- 	}
+ 	/* pairs with READ_ONCE in xe_ggtt_node_addr() */
+ 	WRITE_ONCE(ggtt->start, new_start);
  }
  
- static int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
+ static int xe_ggtt_insert_node_locked(struct xe_ggtt_node *node,
  				      u32 size, u32 align, u32 mm_flags)
  {
  	return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0,
  					  mm_flags);
  }
  
- /**
-  * xe_ggtt_node_insert - Insert a &xe_ggtt_node into the GGTT
-  * @node: the &xe_ggtt_node to be inserted
-  * @size: size of the node
-  * @align: alignment constrain of the node
-  *
-  * It cannot be called without first having called xe_ggtt_init() once.
-  *
-  * Return: 0 on success or a negative error code on failure.
-  */
- int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align)
- {
- 	int ret;
- 
- 	if (!node || !node->ggtt)
- 		return -ENOENT;
- 
- 	mutex_lock(&node->ggtt->lock);
- 	ret = xe_ggtt_node_insert_locked(node, size, align,
- 					 DRM_MM_INSERT_HIGH);
- 	mutex_unlock(&node->ggtt->lock);
- 
- 	return ret;
- }
- 
- /**
-  * xe_ggtt_node_init - Initialize %xe_ggtt_node struct
-  * @ggtt: the &xe_ggtt where the new node will later be inserted/reserved.
-  *
-  * This function will allocate the struct %xe_ggtt_node and return its pointer.
-  * This struct will then be freed after the node removal upon xe_ggtt_node_remove()
-  * or xe_ggtt_node_remove_balloon_locked().
-  *
-  * Having %xe_ggtt_node struct allocated doesn't mean that the node is already
-  * allocated in GGTT. Only xe_ggtt_node_insert(), allocation through
-  * xe_ggtt_node_insert_transform(), or xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved
-  * in GGTT.
-  *
-  * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
-  **/
- struct xe_ggtt_node *xe_ggtt_node_init(struct xe_ggtt *ggtt)
+ static struct xe_ggtt_node *ggtt_node_init(struct xe_ggtt *ggtt)
  {
  	struct xe_ggtt_node *node = kzalloc_obj(*node, GFP_NOFS);
  
@@@ -712,30 -641,31 +641,31 @@@
  }
  
  /**
-  * xe_ggtt_node_fini - Forcebly finalize %xe_ggtt_node struct
-  * @node: the &xe_ggtt_node to be freed
+  * xe_ggtt_insert_node - Insert a &xe_ggtt_node into the GGTT
+  * @ggtt: the &xe_ggtt into which the node should be inserted.
+  * @size: size of the node
+  * @align: alignment constrain of the node
   *
-  * If anything went wrong with either xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(),
-  * or xe_ggtt_node_insert_balloon_locked(); and this @node is not going to be reused, then,
-  * this function needs to be called to free the %xe_ggtt_node struct
-  **/
- void xe_ggtt_node_fini(struct xe_ggtt_node *node)
- {
- 	kfree(node);
- }
- 
- /**
-  * xe_ggtt_node_allocated - Check if node is allocated in GGTT
-  * @node: the &xe_ggtt_node to be inspected
-  *
-  * Return: True if allocated, False otherwise.
+  * Return: &xe_ggtt_node on success or a ERR_PTR on failure.
   */
- bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node)
+ struct xe_ggtt_node *xe_ggtt_insert_node(struct xe_ggtt *ggtt, u32 size, u32 align)
  {
- 	if (!node || !node->ggtt)
- 		return false;
+ 	struct xe_ggtt_node *node;
+ 	int ret;
  
- 	return drm_mm_node_allocated(&node->base);
+ 	node = ggtt_node_init(ggtt);
+ 	if (IS_ERR(node))
+ 		return node;
+ 
+ 	guard(mutex)(&ggtt->lock);
+ 	ret = xe_ggtt_insert_node_locked(node, size, align,
+ 					 DRM_MM_INSERT_HIGH);
+ 	if (ret) {
+ 		ggtt_node_fini(node);
+ 		return ERR_PTR(ret);
+ 	}
+ 
+ 	return node;
  }
  
  /**
@@@ -768,7 -698,7 +698,7 @@@ static void xe_ggtt_map_bo(struct xe_gg
  	if (XE_WARN_ON(!node))
  		return;
  
- 	start = node->base.start;
+ 	start = xe_ggtt_node_addr(node);
  	end = start + xe_bo_size(bo);
  
  	if (!xe_bo_is_vram(bo) && !xe_bo_is_stolen(bo)) {
@@@ -809,7 -739,7 +739,7 @@@ void xe_ggtt_map_bo_unlocked(struct xe_
  }
  
  /**
-  * xe_ggtt_node_insert_transform - Insert a newly allocated &xe_ggtt_node into the GGTT
+  * xe_ggtt_insert_node_transform - Insert a newly allocated &xe_ggtt_node into the GGTT
   * @ggtt: the &xe_ggtt where the node will inserted/reserved.
   * @bo: The bo to be transformed
   * @pte_flags: The extra GGTT flags to add to mapping.
@@@ -823,7 -753,7 +753,7 @@@
   *
   * Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
   */
- struct xe_ggtt_node *xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt,
+ struct xe_ggtt_node *xe_ggtt_insert_node_transform(struct xe_ggtt *ggtt,
  						   struct xe_bo *bo, u64 pte_flags,
  						   u64 size, u32 align,
  						   xe_ggtt_transform_cb transform, void *arg)
@@@ -831,7 -761,7 +761,7 @@@
  	struct xe_ggtt_node *node;
  	int ret;
  
- 	node = xe_ggtt_node_init(ggtt);
+ 	node = ggtt_node_init(ggtt);
  	if (IS_ERR(node))
  		return ERR_CAST(node);
  
@@@ -840,7 -770,7 +770,7 @@@
  		goto err;
  	}
  
- 	ret = xe_ggtt_node_insert_locked(node, size, align, 0);
+ 	ret = xe_ggtt_insert_node_locked(node, size, align, 0);
  	if (ret)
  		goto err_unlock;
  
@@@ -855,7 -785,7 +785,7 @@@
  err_unlock:
  	mutex_unlock(&ggtt->lock);
  err:
- 	xe_ggtt_node_fini(node);
+ 	ggtt_node_fini(node);
  	return ERR_PTR(ret);
  }
  
@@@ -881,7 -811,7 +811,7 @@@ static int __xe_ggtt_insert_bo_at(struc
  
  	xe_pm_runtime_get_noresume(tile_to_xe(ggtt->tile));
  
- 	bo->ggtt_node[tile_id] = xe_ggtt_node_init(ggtt);
+ 	bo->ggtt_node[tile_id] = ggtt_node_init(ggtt);
  	if (IS_ERR(bo->ggtt_node[tile_id])) {
  		err = PTR_ERR(bo->ggtt_node[tile_id]);
  		bo->ggtt_node[tile_id] = NULL;
@@@ -889,10 -819,30 +819,30 @@@
  	}
  
  	mutex_lock(&ggtt->lock);
+ 	/*
+ 	 * When inheriting the initial framebuffer, the framebuffer is
+ 	 * physically located at VRAM address 0, and usually at GGTT address 0 too.
+ 	 *
+ 	 * The display code will ask for a GGTT allocation between end of BO and
+ 	 * remainder of GGTT, unaware that the start is reserved by WOPCM.
+ 	 */
+ 	if (start >= ggtt->start)
+ 		start -= ggtt->start;
+ 	else
+ 		start = 0;
+ 
+ 	/* Should never happen, but since we handle start, fail graciously for end */
+ 	if (end >= ggtt->start)
+ 		end -= ggtt->start;
+ 	else
+ 		end = 0;
+ 
+ 	xe_tile_assert(ggtt->tile, end >= start + xe_bo_size(bo));
+ 
  	err = drm_mm_insert_node_in_range(&ggtt->mm, &bo->ggtt_node[tile_id]->base,
  					  xe_bo_size(bo), alignment, 0, start, end, 0);
  	if (err) {
- 		xe_ggtt_node_fini(bo->ggtt_node[tile_id]);
+ 		ggtt_node_fini(bo->ggtt_node[tile_id]);
  		bo->ggtt_node[tile_id] = NULL;
  	} else {
  		u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
@@@ -1000,18 -950,16 +950,16 @@@ static u64 xe_encode_vfid_pte(u16 vfid
  	return FIELD_PREP(GGTT_PTE_VFID, vfid) | XE_PAGE_PRESENT;
  }
  
- static void xe_ggtt_assign_locked(struct xe_ggtt *ggtt, const struct drm_mm_node *node, u16 vfid)
+ static void xe_ggtt_assign_locked(const struct xe_ggtt_node *node, u16 vfid)
  {
- 	u64 start = node->start;
- 	u64 size = node->size;
+ 	struct xe_ggtt *ggtt = node->ggtt;
+ 	u64 start = xe_ggtt_node_addr(node);
+ 	u64 size = xe_ggtt_node_size(node);
  	u64 end = start + size - 1;
  	u64 pte = xe_encode_vfid_pte(vfid);
  
  	lockdep_assert_held(&ggtt->lock);
  
- 	if (!drm_mm_node_allocated(node))
- 		return;
- 
  	while (start < end) {
  		ggtt->pt_ops->ggtt_set_pte(ggtt, start, pte);
  		start += XE_PAGE_SIZE;
@@@ -1031,9 -979,8 +979,8 @@@
   */
  void xe_ggtt_assign(const struct xe_ggtt_node *node, u16 vfid)
  {
- 	mutex_lock(&node->ggtt->lock);
- 	xe_ggtt_assign_locked(node->ggtt, &node->base, vfid);
- 	mutex_unlock(&node->ggtt->lock);
+ 	guard(mutex)(&node->ggtt->lock);
+ 	xe_ggtt_assign_locked(node, vfid);
  }
  
  /**
@@@ -1055,14 -1002,14 +1002,14 @@@ int xe_ggtt_node_save(struct xe_ggtt_no
  	if (!node)
  		return -ENOENT;
  
- 	guard(mutex)(&node->ggtt->lock);
+ 	ggtt = node->ggtt;
+ 	guard(mutex)(&ggtt->lock);
  
  	if (xe_ggtt_node_pt_size(node) != size)
  		return -EINVAL;
  
- 	ggtt = node->ggtt;
- 	start = node->base.start;
- 	end = start + node->base.size - 1;
+ 	start = xe_ggtt_node_addr(node);
+ 	end = start + xe_ggtt_node_size(node) - 1;
  
  	while (start < end) {
  		pte = ggtt->pt_ops->ggtt_get_pte(ggtt, start);
@@@ -1095,14 -1042,14 +1042,14 @@@ int xe_ggtt_node_load(struct xe_ggtt_no
  	if (!node)
  		return -ENOENT;
  
- 	guard(mutex)(&node->ggtt->lock);
+ 	ggtt = node->ggtt;
+ 	guard(mutex)(&ggtt->lock);
  
  	if (xe_ggtt_node_pt_size(node) != size)
  		return -EINVAL;
  
- 	ggtt = node->ggtt;
- 	start = node->base.start;
- 	end = start + node->base.size - 1;
+ 	start = xe_ggtt_node_addr(node);
+ 	end = start + xe_ggtt_node_size(node) - 1;
  
  	while (start < end) {
  		vfid_pte = u64_replace_bits(*buf++, vfid, GGTT_PTE_VFID);
@@@ -1209,7 -1156,8 +1156,8 @@@ u64 xe_ggtt_read_pte(struct xe_ggtt *gg
   */
  u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node)
  {
- 	return node->base.start;
+ 	/* pairs with WRITE_ONCE in xe_ggtt_shift_nodes() */
+ 	return node->base.start + READ_ONCE(node->ggtt->start);
  }
  
  /**

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-23 15:55 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-23 15:55 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Matthew Auld,
	Michal Wajdeczko, Nareshkumar Gollakoti, Sanjay Yadav,
	Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 2304 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_gt_ccs_mode.c

between commit:

  65d046b2d8e0d ("drm/xe: Fix missing runtime PM reference in ccs_mode_store")

from the origin tree and commit:

  9b5e995e61290 ("drm/xe: Mutual exclusivity between CCS-mode and PF")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_gt_ccs_mode.c
index 03c1862ba497a,b35be36b0eaa2..0000000000000
--- a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
+++ b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
@@@ -12,8 -12,8 +12,9 @@@
  #include "xe_gt_printk.h"
  #include "xe_gt_sysfs.h"
  #include "xe_mmio.h"
 +#include "xe_pm.h"
  #include "xe_sriov.h"
+ #include "xe_sriov_pf.h"
  
  static void __xe_gt_apply_ccs_mode(struct xe_gt *gt, u32 num_engines)
  {
@@@ -147,15 -145,29 +146,30 @@@ ccs_mode_store(struct device *kdev, str
  		return -EBUSY;
  	}
  
- 	if (gt->ccs_mode != num_engines) {
- 		xe_gt_info(gt, "Setting compute mode to %d\n", num_engines);
- 		gt->ccs_mode = num_engines;
- 		xe_gt_record_user_engines(gt);
- 		guard(xe_pm_runtime)(xe);
- 		xe_gt_reset(gt);
+ 	if (gt->ccs_mode == num_engines)
+ 		return count;
+ 
+ 	/*
+ 	 * Changing default CCS mode is only allowed when there
+ 	 * are no VFs. Try to lockdown PF to find out.
+ 	 */
+ 	if (gt_ccs_mode_default(gt) && IS_SRIOV_PF(xe)) {
+ 		ret = xe_sriov_pf_lockdown(xe);
+ 		if (ret) {
+ 			xe_gt_dbg(gt, "Can't change CCS Mode: VFs are enabled\n");
+ 			return ret;
+ 		}
  	}
  
- 	mutex_unlock(&xe->drm.filelist_mutex);
+ 	xe_gt_info(gt, "Setting compute mode to %d\n", num_engines);
+ 	gt->ccs_mode = num_engines;
+ 	xe_gt_record_user_engines(gt);
++	guard(xe_pm_runtime)(xe);
+ 	xe_gt_reset(gt);
+ 
+ 	/* We may end PF lockdown once CCS mode is default again */
+ 	if (gt_ccs_mode_default(gt) && IS_SRIOV_PF(xe))
+ 		xe_sriov_pf_end_lockdown(xe);
  
  	return count;
  }

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-23 15:55 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-23 15:55 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List,
	Maarten Lankhorst, Matthew Brost, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 2304 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_ggtt.c

between commit:

  01f2557aa684e ("drm/xe: Open-code GGTT MMIO access protection")

from the origin tree and commit:

  e904c56ba6e0d ("drm/xe: Rewrite GGTT VF initialization")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_ggtt.c
index d1561ebe4e56c,0f2e3af499120..0000000000000
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@@ -379,18 -437,7 +439,8 @@@ int xe_ggtt_init_early(struct xe_ggtt *
  	if (err)
  		return err;
  
 +	ggtt->flags |= XE_GGTT_FLAGS_ONLINE;
- 	err = devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
- 	if (err)
- 		return err;
- 
- 	if (IS_SRIOV_VF(xe)) {
- 		err = xe_tile_sriov_vf_prepare_ggtt(ggtt->tile);
- 		if (err)
- 			return err;
- 	}
- 
- 	return 0;
+ 	return devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
  }
  ALLOW_ERROR_INJECTION(xe_ggtt_init_early, ERRNO); /* See xe_pci_probe() */
  
@@@ -413,12 -465,15 +468,12 @@@ static void ggtt_node_fini(struct xe_gg
  static void ggtt_node_remove(struct xe_ggtt_node *node)
  {
  	struct xe_ggtt *ggtt = node->ggtt;
 -	struct xe_device *xe = tile_to_xe(ggtt->tile);
  	bool bound;
 -	int idx;
 -
 -	bound = drm_dev_enter(&xe->drm, &idx);
  
  	mutex_lock(&ggtt->lock);
 +	bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE;
  	if (bound)
- 		xe_ggtt_clear(ggtt, node->base.start, node->base.size);
+ 		xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));
  	drm_mm_remove_node(&node->base);
  	node->base.size = 0;
  	mutex_unlock(&ggtt->lock);
@@@ -429,8 -484,10 +484,8 @@@
  	if (node->invalidate_on_remove)
  		xe_ggtt_invalidate(ggtt);
  
 -	drm_dev_exit(idx);
 -
  free_node:
- 	xe_ggtt_node_fini(node);
+ 	ggtt_node_fini(node);
  }
  
  static void ggtt_node_remove_work_func(struct work_struct *work)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-23 15:49 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-23 15:49 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List,
	Maarten Lankhorst, Matthew Brost, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 2798 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_ggtt_types.h

between commit:

  01f2557aa684e ("drm/xe: Open-code GGTT MMIO access protection")

from the origin tree and commit:

  95f5f9a96dcfb ("drm/xe: Move struct xe_ggtt to xe_ggtt.c")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_ggtt_types.h
index c002857bb7611,cf754e4d502ad..0000000000000
--- a/drivers/gpu/drm/xe/xe_ggtt_types.h
+++ b/drivers/gpu/drm/xe/xe_ggtt_types.h
@@@ -6,57 -6,12 +6,13 @@@
  #ifndef _XE_GGTT_TYPES_H_
  #define _XE_GGTT_TYPES_H_
  
+ #include <linux/types.h>
  #include <drm/drm_mm.h>
  
- #include "xe_pt_types.h"
- 
- struct xe_bo;
+ struct xe_ggtt;
  struct xe_ggtt_node;
 +struct xe_gt;
  
- /**
-  * struct xe_ggtt - Main GGTT struct
-  *
-  * In general, each tile can contains its own Global Graphics Translation Table
-  * (GGTT) instance.
-  */
- struct xe_ggtt {
- 	/** @tile: Back pointer to tile where this GGTT belongs */
- 	struct xe_tile *tile;
- 	/** @start: Start offset of GGTT */
- 	u64 start;
- 	/** @size: Total usable size of this GGTT */
- 	u64 size;
- 
- #define XE_GGTT_FLAGS_64K       BIT(0)
- #define XE_GGTT_FLAGS_ONLINE	BIT(1)
- 	/**
- 	 * @flags: Flags for this GGTT
- 	 * Acceptable flags:
- 	 * - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
- 	 * - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock
- 	 *   after init
- 	 */
- 	unsigned int flags;
- 	/** @scratch: Internal object allocation used as a scratch page */
- 	struct xe_bo *scratch;
- 	/** @lock: Mutex lock to protect GGTT data */
- 	struct mutex lock;
- 	/**
- 	 *  @gsm: The iomem pointer to the actual location of the translation
- 	 * table located in the GSM for easy PTE manipulation
- 	 */
- 	u64 __iomem *gsm;
- 	/** @pt_ops: Page Table operations per platform */
- 	const struct xe_ggtt_pt_ops *pt_ops;
- 	/** @mm: The memory manager used to manage individual GGTT allocations */
- 	struct drm_mm mm;
- 	/** @access_count: counts GGTT writes */
- 	unsigned int access_count;
- 	/** @wq: Dedicated unordered work queue to process node removals */
- 	struct workqueue_struct *wq;
- };
- 
  typedef void (*xe_ggtt_set_pte_fn)(struct xe_ggtt *ggtt, u64 addr, u64 pte);
  typedef void (*xe_ggtt_transform_cb)(struct xe_ggtt *ggtt,
  				     struct xe_ggtt_node *node,

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-03-23 15:01 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-03-23 15:01 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Lijo Lazar, Linux Kernel Mailing List,
	Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 26429 bytes --]

Hi all,

Today's linux-next merge of the drm tree got conflicts in:

  drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
  drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c

between commits:

  f39e1270277f4 ("drm/amdgpu/gmc9.0: add bounds checking for cid")
  9c52f49545478 ("drm/amdgpu/mmhub4.2.0: add bounds checking for cid")
  3cdd405831d8c ("drm/amdgpu/mmhub4.1.0: add bounds checking for cid")
  cdb82ecbeccb5 ("drm/amdgpu/mmhub3.0: add bounds checking for cid")
  e5e6d67b1ce97 ("drm/amdgpu/mmhub3.0.2: add bounds checking for cid")
  5d4e88bcfef29 ("drm/amdgpu/mmhub3.0.1: add bounds checking for cid")
  a54403a534972 ("drm/amdgpu/mmhub2.3: add bounds checking for cid")
  0b26edac4ac55 ("drm/amdgpu/mmhub2.0: add bounds checking for cid")

from the origin tree and commits:

  35362833df056 ("drm/amdgpu: Add client ids for mmhub v2.x")
  642fb9e14c63a ("drm/amdgpu: Add client ids for mmhub v3.x")
  f2eceeef689c8 ("drm/amdgpu: Add client ids for mmhub v4.x")
  e14d468304832 ("drm/amdgpu/gmc9.0: add bounds checking for cid")
  dea5f235baf37 ("drm/amdgpu/mmhub4.2.0: add bounds checking for cid")
  04f063d85090f ("drm/amdgpu/mmhub4.1.0: add bounds checking for cid")
  f14f27bbe2a3e ("drm/amdgpu/mmhub3.0: add bounds checking for cid")
  1441f52c7f6ae ("drm/amdgpu/mmhub3.0.2: add bounds checking for cid")
  5f76083183363 ("drm/amdgpu/mmhub3.0.1: add bounds checking for cid")
  89cd90375c19f ("drm/amdgpu/mmhub2.3: add bounds checking for cid")
  e064cef4b5355 ("drm/amdgpu/mmhub2.0: add bounds checking for cid")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 8eba99aa0f8fa,1ca0202cfdea8..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@@ -660,42 -660,7 +660,7 @@@ static int gmc_v9_0_process_interrupt(s
  			gfxhub_client_ids[cid],
  			cid);
  	} else {
- 		switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 		case IP_VERSION(9, 0, 0):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega10) ?
- 				mmhub_client_ids_vega10[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(9, 3, 0):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega12) ?
- 				mmhub_client_ids_vega12[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(9, 4, 0):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega20) ?
- 				mmhub_client_ids_vega20[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(9, 4, 1):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_arcturus) ?
- 				mmhub_client_ids_arcturus[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(9, 1, 0):
- 		case IP_VERSION(9, 2, 0):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_raven) ?
- 				mmhub_client_ids_raven[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(1, 5, 0):
- 		case IP_VERSION(2, 4, 0):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_renoir) ?
- 				mmhub_client_ids_renoir[cid][rw] : NULL;
- 			break;
- 		case IP_VERSION(1, 8, 0):
- 		case IP_VERSION(9, 4, 2):
- 			mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_aldebaran) ?
- 				mmhub_client_ids_aldebaran[cid][rw] : NULL;
- 			break;
- 		default:
- 			mmhub_cid = NULL;
- 			break;
- 		}
+ 		mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  		dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  			mmhub_cid ? mmhub_cid : "unknown", cid);
  	}
@@@ -1435,6 -1400,52 +1400,52 @@@ static void gmc_v9_0_set_umc_funcs(stru
  	}
  }
  
+ static void gmc_v9_0_init_mmhub_client_info(struct amdgpu_device *adev)
+ {
+ 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
+ 	case IP_VERSION(9, 0, 0):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_vega10,
+ 					     ARRAY_SIZE(mmhub_client_ids_vega10));
+ 		break;
+ 	case IP_VERSION(9, 3, 0):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_vega12,
+ 					     ARRAY_SIZE(mmhub_client_ids_vega12));
+ 		break;
+ 	case IP_VERSION(9, 4, 0):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_vega20,
+ 					     ARRAY_SIZE(mmhub_client_ids_vega20));
+ 		break;
+ 	case IP_VERSION(9, 4, 1):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_arcturus,
+ 					     ARRAY_SIZE(mmhub_client_ids_arcturus));
+ 		break;
+ 	case IP_VERSION(9, 1, 0):
+ 	case IP_VERSION(9, 2, 0):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_raven,
+ 					     ARRAY_SIZE(mmhub_client_ids_raven));
+ 		break;
+ 	case IP_VERSION(1, 5, 0):
+ 	case IP_VERSION(2, 4, 0):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_renoir,
+ 					     ARRAY_SIZE(mmhub_client_ids_renoir));
+ 		break;
+ 	case IP_VERSION(1, 8, 0):
+ 	case IP_VERSION(9, 4, 2):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_aldebaran,
+ 					     ARRAY_SIZE(mmhub_client_ids_aldebaran));
+ 		break;
+ 	default:
+ 		break;
+ 	}
+ }
+ 
  static void gmc_v9_0_set_mmhub_funcs(struct amdgpu_device *adev)
  {
  	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
@@@ -1452,6 -1463,8 +1463,8 @@@
  		adev->mmhub.funcs = &mmhub_v1_0_funcs;
  		break;
  	}
+ 
+ 	gmc_v9_0_init_mmhub_client_info(adev);
  }
  
  static void gmc_v9_0_set_mmhub_ras_funcs(struct amdgpu_device *adev)
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
index 534cb4c544dc4,42a09a277ec3e..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@@ -141,7 -141,7 +141,7 @@@ mmhub_v2_0_print_l2_protection_fault_st
  					     uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS, CID);
@@@ -151,25 -151,7 +151,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
  		status);
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(2, 0, 0):
- 	case IP_VERSION(2, 0, 2):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_navi1x) ?
- 			mmhub_client_ids_navi1x[cid][rw] : NULL;
- 		break;
- 	case IP_VERSION(2, 1, 0):
- 	case IP_VERSION(2, 1, 1):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_sienna_cichlid) ?
- 			mmhub_client_ids_sienna_cichlid[cid][rw] : NULL;
- 		break;
- 	case IP_VERSION(2, 1, 2):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_beige_goby) ?
- 			mmhub_client_ids_beige_goby[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -521,6 -503,31 +503,31 @@@ static const struct amdgpu_vmhub_funcs 
  	.get_invalidate_req = mmhub_v2_0_get_invalidate_req,
  };
  
+ static void mmhub_v2_0_init_client_info(struct amdgpu_device *adev)
+ {
+ 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
+ 	case IP_VERSION(2, 0, 0):
+ 	case IP_VERSION(2, 0, 2):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_navi1x,
+ 					     ARRAY_SIZE(mmhub_client_ids_navi1x));
+ 		break;
+ 	case IP_VERSION(2, 1, 0):
+ 	case IP_VERSION(2, 1, 1):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_sienna_cichlid,
+ 					     ARRAY_SIZE(mmhub_client_ids_sienna_cichlid));
+ 		break;
+ 	case IP_VERSION(2, 1, 2):
+ 		amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 					     mmhub_client_ids_beige_goby,
+ 					     ARRAY_SIZE(mmhub_client_ids_beige_goby));
+ 		break;
+ 	default:
+ 		break;
+ 	}
+ }
+ 
  static void mmhub_v2_0_init(struct amdgpu_device *adev)
  {
  	struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB0(0)];
@@@ -561,6 -568,8 +568,8 @@@
  		MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK;
  
  	hub->vmhub_funcs = &mmhub_v2_0_vmhub_funcs;
+ 
+ 	mmhub_v2_0_init_client_info(adev);
  }
  
  static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
index ceb2f6b46de52,31c479d76c421..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
@@@ -80,7 -80,7 +80,7 @@@ mmhub_v2_3_print_l2_protection_fault_st
  					     uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS, CID);
@@@ -90,17 -90,7 +90,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
  		status);
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(2, 3, 0):
- 	case IP_VERSION(2, 4, 0):
- 	case IP_VERSION(2, 4, 1):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vangogh) ?
- 			mmhub_client_ids_vangogh[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -487,6 -477,10 +477,10 @@@ static void mmhub_v2_3_init(struct amdg
  		MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK;
  
  	hub->vmhub_funcs = &mmhub_v2_3_vmhub_funcs;
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_vangogh,
+ 				     ARRAY_SIZE(mmhub_client_ids_vangogh));
  }
  
  static void
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
index ab966e69a342a,3d82cfa0f1b51..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
@@@ -97,7 -97,7 +97,7 @@@ mmhub_v3_0_print_l2_protection_fault_st
  					     uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS, CID);
@@@ -107,16 -107,7 +107,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
  		status);
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(3, 0, 0):
- 	case IP_VERSION(3, 0, 1):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_0) ?
- 			mmhub_client_ids_v3_0_0[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -521,6 -512,10 +512,10 @@@ static void mmhub_v3_0_init(struct amdg
  		SOC15_REG_OFFSET(MMHUB, 0, regMMVM_CONTEXTS_DISABLE);
  
  	hub->vmhub_funcs = &mmhub_v3_0_vmhub_funcs;
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_v3_0_0,
+ 				     ARRAY_SIZE(mmhub_client_ids_v3_0_0));
  }
  
  static u64 mmhub_v3_0_get_fb_location(struct amdgpu_device *adev)
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
index 14a742d3a99d7,a1b0b7b39a42a..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
@@@ -104,7 -104,7 +104,7 @@@ mmhub_v3_0_1_print_l2_protection_fault_
  					      uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS, CID);
@@@ -114,17 -114,7 +114,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
  		status);
- 
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(3, 0, 1):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_1) ?
- 			mmhub_client_ids_v3_0_1[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
- 
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -504,6 -494,10 +494,10 @@@ static void mmhub_v3_0_1_init(struct am
  		MMVM_CONTEXT1_CNTL__EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK;
  
  	hub->vmhub_funcs = &mmhub_v3_0_1_vmhub_funcs;
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_v3_0_1,
+ 				     ARRAY_SIZE(mmhub_client_ids_v3_0_1));
  }
  
  static u64 mmhub_v3_0_1_get_fb_location(struct amdgpu_device *adev)
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
index e1f07f2a18527,34e8dbd47c0f8..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
@@@ -97,7 -97,7 +97,7 @@@ mmhub_v3_0_2_print_l2_protection_fault_
  					     uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS, CID);
@@@ -107,9 -107,7 +107,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
  		status);
- 
- 	mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_2) ?
- 		mmhub_client_ids_v3_0_2[cid][rw] : NULL;
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -510,6 -508,10 +508,10 @@@ static void mmhub_v3_0_2_init(struct am
  		SOC15_REG_OFFSET(MMHUB, 0, regMMVM_L2_BANK_SELECT_RESERVED_CID2);
  
  	hub->vmhub_funcs = &mmhub_v3_0_2_vmhub_funcs;
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_v3_0_2,
+ 				     ARRAY_SIZE(mmhub_client_ids_v3_0_2));
  }
  
  static u64 mmhub_v3_0_2_get_fb_location(struct amdgpu_device *adev)
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
index 88bfe321f83aa,bef75c4c48d3e..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
@@@ -90,7 -90,7 +90,7 @@@ mmhub_v4_1_0_print_l2_protection_fault_
  					      uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS_LO32, CID);
@@@ -100,15 -100,7 +100,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS_LO32:0x%08X\n",
  		status);
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(4, 1, 0):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v4_1_0) ?
- 			mmhub_client_ids_v4_1_0[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -515,6 -507,10 +507,10 @@@ static void mmhub_v4_1_0_init(struct am
  		SOC15_REG_OFFSET(MMHUB, 0, regMMVM_CONTEXTS_DISABLE);
  
  	hub->vmhub_funcs = &mmhub_v4_1_0_vmhub_funcs;
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_v4_1_0,
+ 				     ARRAY_SIZE(mmhub_client_ids_v4_1_0));
  }
  
  static u64 mmhub_v4_1_0_get_fb_location(struct amdgpu_device *adev)
diff --combined drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
index 2532ca80f7356,29f7ed4668587..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
@@@ -72,6 -72,45 +72,45 @@@ static const char *mmhub_client_ids_v4_
  	[23][1] = "VCN1",
  };
  
+ static int mmhub_v4_2_0_get_xgmi_info(struct amdgpu_device *adev)
+ {
+ 	u32 max_num_physical_nodes;
+ 	u32 max_physical_node_id;
+ 	u32 xgmi_lfb_cntl;
+ 	u32 max_region;
+ 	u64 seg_size;
+ 
+ 	/* limit this callback to A + A configuration only */
+ 	if (!adev->gmc.xgmi.connected_to_cpu)
+ 		return 0;
+ 
+ 	xgmi_lfb_cntl = RREG32_SOC15(MMHUB, GET_INST(MMHUB, 0),
+ 				     regMMMC_VM_XGMI_LFB_CNTL);
+ 	seg_size = REG_GET_FIELD(
+ 		RREG32_SOC15(MMHUB, GET_INST(MMHUB, 0), regMMMC_VM_XGMI_LFB_SIZE),
+ 		MMMC_VM_XGMI_LFB_SIZE, PF_LFB_SIZE) << 24;
+ 	max_region =
+ 		REG_GET_FIELD(xgmi_lfb_cntl, MMMC_VM_XGMI_LFB_CNTL, PF_MAX_REGION);
+ 
+ 	max_num_physical_nodes   = 4;
+ 	max_physical_node_id     = 3;
+ 
+ 	adev->gmc.xgmi.num_physical_nodes = max_region + 1;
+ 
+ 	if (adev->gmc.xgmi.num_physical_nodes > max_num_physical_nodes)
+ 		return -EINVAL;
+ 
+ 	adev->gmc.xgmi.physical_node_id =
+ 		REG_GET_FIELD(xgmi_lfb_cntl, MMMC_VM_XGMI_LFB_CNTL, PF_LFB_REGION);
+ 
+ 	if (adev->gmc.xgmi.physical_node_id > max_physical_node_id)
+ 		return -EINVAL;
+ 
+ 	adev->gmc.xgmi.node_segment_size = seg_size;
+ 
+ 	return 0;
+ }
+ 
  static u64 mmhub_v4_2_0_get_fb_location(struct amdgpu_device *adev)
  {
  	u64 base;
@@@ -131,7 -170,7 +170,7 @@@ static void mmhub_v4_2_0_setup_vm_pt_re
  static void mmhub_v4_2_0_mid_init_gart_aperture_regs(struct amdgpu_device *adev,
  						     uint32_t mid_mask)
  {
- 	uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
+ 	uint64_t pt_base;
  	int i;
  
  	if (adev->gmc.pdb0_bo)
@@@ -152,10 -191,10 +191,10 @@@
  
  			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
  				     regMMVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32,
- 				     (u32)(adev->gmc.fb_end >> 12));
+ 				     (u32)(adev->gmc.gart_end >> 12));
  			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
  				     regMMVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32,
- 				     (u32)(adev->gmc.fb_end >> 44));
+ 				     (u32)(adev->gmc.gart_end >> 44));
  		} else {
  			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
  				     regMMVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
@@@ -190,41 -229,74 +229,74 @@@ static void mmhub_v4_2_0_mid_init_syste
  		return;
  
  	for_each_inst(i, mid_mask) {
- 		/* Program the AGP BAR */
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BASE_LO32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BASE_HI32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BOT_LO32,
- 			     lower_32_bits(adev->gmc.agp_start >> 24));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BOT_HI32,
- 			     upper_32_bits(adev->gmc.agp_start >> 24));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_TOP_LO32,
- 			     lower_32_bits(adev->gmc.agp_end >> 24));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_TOP_HI32,
- 			     upper_32_bits(adev->gmc.agp_end >> 24));
+ 		if (adev->gmc.pdb0_bo) {
+ 			/* Disable agp and system aperture
+ 			 * when vmid0 page table is enabled */
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_FB_LOCATION_TOP_LO32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_FB_LOCATION_TOP_HI32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_FB_LOCATION_BASE_LO32,
+ 				     0xFFFFFFFF);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_FB_LOCATION_BASE_HI32, 1);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_TOP_LO32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_TOP_HI32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BOT_LO32,
+ 				     0xFFFFFFFF);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BOT_HI32, 1);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32,
+ 				     0xFFFFFFFF);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32,
+ 				     0x7F);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, 0);
+ 		} else {
+ 			/* Program the AGP BAR */
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BASE_LO32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BASE_HI32, 0);
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BOT_LO32,
+ 				     lower_32_bits(adev->gmc.agp_start >> 24));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_BOT_HI32,
+ 				     upper_32_bits(adev->gmc.agp_start >> 24));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_TOP_LO32,
+ 				     lower_32_bits(adev->gmc.agp_end >> 24));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_AGP_TOP_HI32,
+ 				     upper_32_bits(adev->gmc.agp_end >> 24));
  
- 		/* Program the system aperture low logical page number. */
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32,
- 			     lower_32_bits(min(adev->gmc.fb_start,
- 					       adev->gmc.agp_start) >> 18));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32,
- 			     upper_32_bits(min(adev->gmc.fb_start,
- 					       adev->gmc.agp_start) >> 18));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32,
- 			     lower_32_bits(max(adev->gmc.fb_end,
- 					       adev->gmc.agp_end) >> 18));
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32,
- 			     upper_32_bits(max(adev->gmc.fb_end,
- 					       adev->gmc.agp_end) >> 18));
+ 			/* Program the system aperture low logical page number. */
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32,
+ 				     lower_32_bits(min(adev->gmc.fb_start,
+ 						   adev->gmc.agp_start) >> 18));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32,
+ 				     upper_32_bits(min(adev->gmc.fb_start,
+ 						   adev->gmc.agp_start) >> 18));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32,
+ 				     lower_32_bits(max(adev->gmc.fb_end,
+ 						   adev->gmc.agp_end) >> 18));
+ 			WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
+ 				     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32,
+ 				     upper_32_bits(max(adev->gmc.fb_end,
+ 						   adev->gmc.agp_end) >> 18));
+ 		}
  
  		/* Set default page address. */
  		value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
@@@ -252,38 -324,6 +324,6 @@@
  		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
  			     regMMVM_L2_PROTECTION_FAULT_CNTL2, tmp);
  	}
- 
- 	/* In the case squeezing vram into GART aperture, we don't use
- 	 * FB aperture and AGP aperture. Disable them.
- 	 */
- 	if (adev->gmc.pdb0_bo) {
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_FB_LOCATION_TOP_LO32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_FB_LOCATION_TOP_HI32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_FB_LOCATION_BASE_LO32, 0xFFFFFFFF);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_FB_LOCATION_BASE_HI32, 1);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_TOP_LO32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_TOP_HI32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BOT_LO32, 0xFFFFFFFF);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_AGP_BOT_HI32, 1);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_LO32,
- 			     0xFFFFFFFF);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR_HI32,
- 			     0x7F);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_LO32, 0);
- 		WREG32_SOC15(MMHUB, GET_INST(MMHUB, i),
- 			     regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR_HI32, 0);
- 	}
  }
  
  static void mmhub_v4_2_0_mid_init_tlb_regs(struct amdgpu_device *adev,
@@@ -676,7 -716,7 +716,7 @@@ mmhub_v4_2_0_print_l2_protection_fault_
  					      uint32_t status)
  {
  	uint32_t cid, rw;
- 	const char *mmhub_cid = NULL;
+ 	const char *mmhub_cid;
  
  	cid = REG_GET_FIELD(status,
  			    MMVM_L2_PROTECTION_FAULT_STATUS_LO32, CID);
@@@ -686,15 -726,7 +726,7 @@@
  	dev_err(adev->dev,
  		"MMVM_L2_PROTECTION_FAULT_STATUS_LO32:0x%08X\n",
  		status);
- 	switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
- 	case IP_VERSION(4, 2, 0):
- 		mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v4_2_0) ?
- 			mmhub_client_ids_v4_2_0[cid][rw] : NULL;
- 		break;
- 	default:
- 		mmhub_cid = NULL;
- 		break;
- 	}
+ 	mmhub_cid = amdgpu_mmhub_client_name(&adev->mmhub, cid, rw);
  	dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
  		mmhub_cid ? mmhub_cid : "unknown", cid);
  	dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
@@@ -785,6 -817,10 +817,10 @@@ static void mmhub_v4_2_0_init(struct am
  
  	mid_mask = adev->aid_mask;
  	mmhub_v4_2_0_mid_init(adev, mid_mask);
+ 
+ 	amdgpu_mmhub_init_client_info(&adev->mmhub,
+ 				     mmhub_client_ids_v4_2_0,
+ 				     ARRAY_SIZE(mmhub_client_ids_v4_2_0));
  }
  
  static void
@@@ -884,6 -920,7 +920,7 @@@ const struct amdgpu_mmhub_funcs mmhub_v
  	.set_fault_enable_default = mmhub_v4_2_0_set_fault_enable_default,
  	.set_clockgating = mmhub_v4_2_0_set_clockgating,
  	.get_clockgating = mmhub_v4_2_0_get_clockgating,
+ 	.get_xgmi_info = mmhub_v4_2_0_get_xgmi_info,
  };
  
  static int mmhub_v4_2_0_xcp_resume(void *handle, uint32_t inst_mask)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-02-08 22:47 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-02-08 22:47 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Ashutosh Dixit, Daniele Ceraolo Spurio, Linux Kernel Mailing List,
	Linux Next Mailing List, Matt Roper, Raag Jadav, Riana Tauro,
	Rodrigo Vivi, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 994 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_guc.c

between commit:

  4cb1b327135ddd ("drm/xe/guc: Fix CFI violation in debugfs access.")

from the origin tree and commits:

  43fb9e113bf11d ("drm/xe/gt: Introduce runtime suspend/resume")
  6e035abf98b05f ("drm/xe/guc: Fix CFI violation in debugfs access.")
  3947e482b5ebb9 ("drm/xe/guc: Use scope-based cleanup")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_guc.c
index edb939f2626851,6df7c3f260e5bd..00000000000000
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-02-08 22:46 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-02-08 22:46 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Matthew Brost,
	Michal Wajdeczko, Rodrigo Vivi, Satyanarayana K V P,
	Shuicheng Lin, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 972 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_migrate.c

between commit:

  e022c16965b834 ("drm/xe: Fix kerneldoc for xe_migrate_exec_queue")

from the origin tree and commits:

  fa18290bf0723b ("drm/xe/vf: Shadow buffer management for CCS read/write operations")
  5d5ef695497950 ("drm/xe: Fix kerneldoc for xe_migrate_exec_queue")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_migrate.c
index 9d7329cef910af,078a9bc2821dd6..00000000000000
--- a/drivers/gpu/drm/xe/xe_migrate.c
+++ b/drivers/gpu/drm/xe/xe_migrate.c

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-02-02 14:29 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-02-02 14:29 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Linux Kernel Mailing List, Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 17876 bytes --]

Hi all,

Today's linux-next merge of the drm tree got conflicts in:

  drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
  drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c

between commits:

  3eb46fbb601f9 ("drm/amdgpu/gfx11: adjust KGQ reset sequence")
  dfd64f6e8cd7b ("drm/amdgpu/gfx12: adjust KGQ reset sequence")

from the origin tree and commits:

  b340ff216fdab ("drm/amdgpu/gfx11: adjust KGQ reset sequence")
  0a6d6ed694d72 ("drm/amdgpu/gfx12: adjust KGQ reset sequence")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
diff --combined drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index e642236ea2c51,427975b5a1d97..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@@ -120,6 -120,10 +120,10 @@@ MODULE_FIRMWARE("amdgpu/gc_11_5_3_pfp.b
  MODULE_FIRMWARE("amdgpu/gc_11_5_3_me.bin");
  MODULE_FIRMWARE("amdgpu/gc_11_5_3_mec.bin");
  MODULE_FIRMWARE("amdgpu/gc_11_5_3_rlc.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_5_4_pfp.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_5_4_me.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_5_4_mec.bin");
+ MODULE_FIRMWARE("amdgpu/gc_11_5_4_rlc.bin");
  
  static const struct amdgpu_hwip_reg_entry gc_reg_list_11_0[] = {
  	SOC15_REG_ENTRY_STR(GC, 0, regGRBM_STATUS),
@@@ -416,7 -420,8 +420,8 @@@ static void gfx11_kiq_unmap_queues(stru
  	uint32_t eng_sel = ring->funcs->type == AMDGPU_RING_TYPE_GFX ? 4 : 0;
  
  	if (adev->enable_mes && !adev->gfx.kiq[0].ring.sched.ready) {
- 		amdgpu_mes_unmap_legacy_queue(adev, ring, action, gpu_addr, seq);
+ 		amdgpu_mes_unmap_legacy_queue(adev, ring, action,
+ 					      gpu_addr, seq, 0);
  		return;
  	}
  
@@@ -566,8 -571,8 +571,8 @@@ static int gfx_v11_0_ring_test_ring(str
  	WREG32(scratch, 0xCAFEDEAD);
  	r = amdgpu_ring_alloc(ring, 5);
  	if (r) {
- 		DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- 			  ring->idx, r);
+ 		drm_err(adev_to_drm(adev), "cp failed to lock ring %d (%d).\n",
+ 			ring->idx, r);
  		return r;
  	}
  
@@@ -623,7 -628,7 +628,7 @@@ static int gfx_v11_0_ring_test_ib(struc
  
  	r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib);
  	if (r) {
- 		DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ 		drm_err(adev_to_drm(adev), "failed to get ib (%ld).\n", r);
  		goto err1;
  	}
  
@@@ -917,7 -922,7 +922,7 @@@ static int gfx_v11_0_rlc_init(struct am
  
  	/* init spm vmid with 0xf */
  	if (adev->gfx.rlc.funcs->update_spm_vmid)
- 		adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf);
+ 		adev->gfx.rlc.funcs->update_spm_vmid(adev, 0, NULL, 0xf);
  
  	return 0;
  }
@@@ -1052,10 -1057,14 +1057,14 @@@ static void gfx_v11_0_select_me_pipe_q(
  static void gfx_v11_0_get_gfx_shadow_info_nocheck(struct amdgpu_device *adev,
  					 struct amdgpu_gfx_shadow_info *shadow_info)
  {
+ 	/* for gfx */
  	shadow_info->shadow_size = MQD_SHADOW_BASE_SIZE;
  	shadow_info->shadow_alignment = MQD_SHADOW_BASE_ALIGNMENT;
  	shadow_info->csa_size = MQD_FWWORKAREA_SIZE;
  	shadow_info->csa_alignment = MQD_FWWORKAREA_ALIGNMENT;
+ 	/* for compute */
+ 	shadow_info->eop_size = GFX11_MEC_HPD_SIZE;
+ 	shadow_info->eop_alignment = 256;
  }
  
  static int gfx_v11_0_get_gfx_shadow_info(struct amdgpu_device *adev,
@@@ -1080,6 -1089,7 +1089,7 @@@ static const struct amdgpu_gfx_funcs gf
  	.select_me_pipe_q = &gfx_v11_0_select_me_pipe_q,
  	.update_perfmon_mgcg = &gfx_v11_0_update_perf_clk,
  	.get_gfx_shadow_info = &gfx_v11_0_get_gfx_shadow_info,
+ 	.get_hdp_flush_mask = &amdgpu_gfx_get_hdp_flush_mask,
  };
  
  static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
@@@ -1107,6 -1117,7 +1117,7 @@@
  	case IP_VERSION(11, 5, 1):
  	case IP_VERSION(11, 5, 2):
  	case IP_VERSION(11, 5, 3):
+ 	case IP_VERSION(11, 5, 4):
  		adev->gfx.config.max_hw_contexts = 8;
  		adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
  		adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
@@@ -1589,6 -1600,7 +1600,7 @@@ static int gfx_v11_0_sw_init(struct amd
  	case IP_VERSION(11, 5, 1):
  	case IP_VERSION(11, 5, 2):
  	case IP_VERSION(11, 5, 3):
+ 	case IP_VERSION(11, 5, 4):
  		adev->gfx.me.num_me = 1;
  		adev->gfx.me.num_pipe_per_me = 1;
  		adev->gfx.me.num_queue_per_pipe = 2;
@@@ -3046,7 -3058,8 +3058,8 @@@ static int gfx_v11_0_wait_for_rlc_autol
  		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 0) ||
  		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 1) ||
  		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 2) ||
- 		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 3))
+ 		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 3) ||
+ 		    amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4))
  			bootload_status = RREG32_SOC15(GC, 0,
  					regRLC_RLCS_BOOTLOAD_STATUS_gc_11_0_1);
  		else
@@@ -3617,7 -3630,7 +3630,7 @@@ static int gfx_v11_0_cp_gfx_start(struc
  	ring = &adev->gfx.gfx_ring[0];
  	r = amdgpu_ring_alloc(ring, gfx_v11_0_get_csb_size(adev));
  	if (r) {
- 		DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+ 		drm_err(&adev->ddev, "cp failed to lock ring (%d).\n", r);
  		return r;
  	}
  
@@@ -3662,7 -3675,7 +3675,7 @@@
  		ring = &adev->gfx.gfx_ring[1];
  		r = amdgpu_ring_alloc(ring, 2);
  		if (r) {
- 			DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+ 			drm_err(adev_to_drm(adev), "cp failed to lock ring (%d).\n", r);
  			return r;
  		}
  
@@@ -4593,7 -4606,7 +4606,7 @@@ static int gfx_v11_0_cp_resume(struct a
  	}
  
  	if (adev->enable_mes_kiq && adev->mes.kiq_hw_init)
- 		r = amdgpu_mes_kiq_hw_init(adev);
+ 		r = amdgpu_mes_kiq_hw_init(adev, 0);
  	else
  		r = gfx_v11_0_kiq_resume(adev);
  	if (r)
@@@ -4783,7 -4796,7 +4796,7 @@@ static int gfx_v11_0_hw_init(struct amd
  	adev->gfx.is_poweron = true;
  
  	if(get_gb_addr_config(adev))
- 		DRM_WARN("Invalid gb_addr_config !\n");
+ 		drm_warn(adev_to_drm(adev), "Invalid gb_addr_config !\n");
  
  	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP &&
  	    adev->gfx.rs64_enable)
@@@ -4901,7 -4914,7 +4914,7 @@@ static int gfx_v11_0_hw_fini(struct amd
  		if (amdgpu_gfx_disable_kcq(adev, 0))
  			DRM_ERROR("KCQ disable failed\n");
  
- 		amdgpu_mes_kiq_hw_fini(adev);
+ 		amdgpu_mes_kiq_hw_fini(adev, 0);
  	}
  
  	if (amdgpu_sriov_vf(adev))
@@@ -5568,7 -5581,8 +5581,8 @@@ static int gfx_v11_0_update_gfx_clock_g
  	return 0;
  }
  
- static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned vmid)
+ static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, int xcc_id,
+ 		struct amdgpu_ring *ring, unsigned vmid)
  {
  	u32 reg, pre_data, data;
  
@@@ -5633,6 -5647,7 +5647,7 @@@ static void gfx_v11_cntl_power_gating(s
  		case IP_VERSION(11, 5, 1):
  		case IP_VERSION(11, 5, 2):
  		case IP_VERSION(11, 5, 3):
+ 	        case IP_VERSION(11, 5, 4):
  			WREG32_SOC15(GC, 0, regRLC_PG_DELAY_3, RLC_PG_DELAY_3_DEFAULT_GC_11_0_1);
  			break;
  		default:
@@@ -5671,6 -5686,7 +5686,7 @@@ static int gfx_v11_0_set_powergating_st
  	case IP_VERSION(11, 5, 1):
  	case IP_VERSION(11, 5, 2):
  	case IP_VERSION(11, 5, 3):
+ 	case IP_VERSION(11, 5, 4):
  		if (!enable)
  			amdgpu_gfx_off_ctrl(adev, false);
  
@@@ -5705,6 -5721,7 +5721,7 @@@ static int gfx_v11_0_set_clockgating_st
  	case IP_VERSION(11, 5, 1):
  	case IP_VERSION(11, 5, 2):
  	case IP_VERSION(11, 5, 3):
+ 	case IP_VERSION(11, 5, 4):
  	        gfx_v11_0_update_gfx_clock_gating(adev,
  	                        state ==  AMD_CG_STATE_GATE);
  	        break;
@@@ -5831,25 -5848,13 +5848,13 @@@ static void gfx_v11_0_ring_emit_hdp_flu
  {
  	struct amdgpu_device *adev = ring->adev;
  	u32 ref_and_mask, reg_mem_engine;
- 	const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio.hdp_flush_reg;
  
- 	if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) {
- 		switch (ring->me) {
- 		case 1:
- 			ref_and_mask = nbio_hf_reg->ref_and_mask_cp2 << ring->pipe;
- 			break;
- 		case 2:
- 			ref_and_mask = nbio_hf_reg->ref_and_mask_cp6 << ring->pipe;
- 			break;
- 		default:
- 			return;
- 		}
- 		reg_mem_engine = 0;
- 	} else {
- 		ref_and_mask = nbio_hf_reg->ref_and_mask_cp0 << ring->pipe;
- 		reg_mem_engine = 1; /* pfp */
+ 	if (!adev->gfx.funcs->get_hdp_flush_mask) {
+ 		dev_err(adev->dev, "%s: gfx hdp flush is not supported.\n", __func__);
+ 		return;
  	}
  
+ 	adev->gfx.funcs->get_hdp_flush_mask(ring, &ref_and_mask, &reg_mem_engine);
  	gfx_v11_0_wait_reg_mem(ring, reg_mem_engine, 0, 1,
  			       adev->nbio.funcs->get_hdp_flush_req_offset(adev),
  			       adev->nbio.funcs->get_hdp_flush_done_offset(adev),
@@@ -6664,7 -6669,7 +6669,7 @@@ static int gfx_v11_0_bad_op_irq(struct 
  				struct amdgpu_irq_src *source,
  				struct amdgpu_iv_entry *entry)
  {
- 	DRM_ERROR("Illegal opcode in command stream \n");
+ 	DRM_ERROR("Illegal opcode in command stream\n");
  	gfx_v11_0_handle_priv_fault(adev, entry);
  	return 0;
  }
@@@ -6828,7 -6833,7 +6833,7 @@@ static int gfx_v11_0_reset_kgq(struct a
  
  	amdgpu_ring_reset_helper_begin(ring, timedout_fence);
  
- 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio);
+ 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
  	if (r) {
  
  		dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r);
@@@ -6844,7 -6849,7 +6849,7 @@@
  			return r;
  		}
  
- 		r = amdgpu_mes_map_legacy_queue(adev, ring);
+ 		r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
  		if (r) {
  			dev_err(adev->dev, "failed to remap kgq\n");
  			return r;
@@@ -6993,7 -6998,7 +6998,7 @@@ static int gfx_v11_0_reset_kcq(struct a
  
  	amdgpu_ring_reset_helper_begin(ring, timedout_fence);
  
- 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true);
+ 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0);
  	if (r) {
  		dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r);
  		r = gfx_v11_0_reset_compute_pipe(ring);
@@@ -7006,7 -7011,7 +7011,7 @@@
  		dev_err(adev->dev, "fail to init kcq\n");
  		return r;
  	}
- 	r = amdgpu_mes_map_legacy_queue(adev, ring);
+ 	r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
  	if (r) {
  		dev_err(adev->dev, "failed to remap kcq\n");
  		return r;
@@@ -7480,7 -7485,7 +7485,7 @@@ static int gfx_v11_0_get_cu_info(struc
  	if (!adev || !cu_info)
  		return -EINVAL;
  
- 	amdgpu_gfx_parse_disable_cu(disable_masks, 8, 2);
+ 	amdgpu_gfx_parse_disable_cu(adev, disable_masks, 8, 2);
  
  	mutex_lock(&adev->grbm_idx_mutex);
  	for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
diff --combined drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index 4aab89a9ab401,79ea1af363a53..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@@ -355,7 -355,8 +355,8 @@@ static void gfx_v12_0_kiq_unmap_queues(
  	uint32_t eng_sel = ring->funcs->type == AMDGPU_RING_TYPE_GFX ? 4 : 0;
  
  	if (adev->enable_mes && !adev->gfx.kiq[0].ring.sched.ready) {
- 		amdgpu_mes_unmap_legacy_queue(adev, ring, action, gpu_addr, seq);
+ 		amdgpu_mes_unmap_legacy_queue(adev, ring, action,
+ 					      gpu_addr, seq, 0);
  		return;
  	}
  
@@@ -458,8 -459,8 +459,8 @@@ static int gfx_v12_0_ring_test_ring(str
  	WREG32(scratch, 0xCAFEDEAD);
  	r = amdgpu_ring_alloc(ring, 5);
  	if (r) {
- 		dev_err(adev->dev,
- 			"amdgpu: cp failed to lock ring %d (%d).\n",
+ 		drm_err(adev_to_drm(adev),
+ 			"cp failed to lock ring %d (%d).\n",
  			ring->idx, r);
  		return r;
  	}
@@@ -516,7 -517,7 +517,7 @@@ static int gfx_v12_0_ring_test_ib(struc
  
  	r = amdgpu_ib_get(adev, NULL, 16, AMDGPU_IB_POOL_DIRECT, &ib);
  	if (r) {
- 		dev_err(adev->dev, "amdgpu: failed to get ib (%ld).\n", r);
+ 		drm_err(adev_to_drm(adev), "failed to get ib (%ld).\n", r);
  		goto err1;
  	}
  
@@@ -760,7 -761,7 +761,7 @@@ static int gfx_v12_0_rlc_init(struct am
  
  	/* init spm vmid with 0xf */
  	if (adev->gfx.rlc.funcs->update_spm_vmid)
- 		adev->gfx.rlc.funcs->update_spm_vmid(adev, NULL, 0xf);
+ 		adev->gfx.rlc.funcs->update_spm_vmid(adev, 0, NULL, 0xf);
  
  	return 0;
  }
@@@ -908,10 -909,14 +909,14 @@@ static void gfx_v12_0_select_me_pipe_q(
  static void gfx_v12_0_get_gfx_shadow_info_nocheck(struct amdgpu_device *adev,
  						  struct amdgpu_gfx_shadow_info *shadow_info)
  {
+ 	/* for gfx */
  	shadow_info->shadow_size = MQD_SHADOW_BASE_SIZE;
  	shadow_info->shadow_alignment = MQD_SHADOW_BASE_ALIGNMENT;
  	shadow_info->csa_size = MQD_FWWORKAREA_SIZE;
  	shadow_info->csa_alignment = MQD_FWWORKAREA_ALIGNMENT;
+ 	/* for compute */
+ 	shadow_info->eop_size = GFX12_MEC_HPD_SIZE;
+ 	shadow_info->eop_alignment = 256;
  }
  
  static int gfx_v12_0_get_gfx_shadow_info(struct amdgpu_device *adev,
@@@ -936,6 -941,7 +941,7 @@@ static const struct amdgpu_gfx_funcs gf
  	.select_me_pipe_q = &gfx_v12_0_select_me_pipe_q,
  	.update_perfmon_mgcg = &gfx_v12_0_update_perf_clk,
  	.get_gfx_shadow_info = &gfx_v12_0_get_gfx_shadow_info,
+ 	.get_hdp_flush_mask = &amdgpu_gfx_get_hdp_flush_mask,
  };
  
  static int gfx_v12_0_gpu_early_init(struct amdgpu_device *adev)
@@@ -3469,7 -3475,7 +3475,7 @@@ static int gfx_v12_0_cp_resume(struct a
  	}
  
  	if (adev->enable_mes_kiq && adev->mes.kiq_hw_init)
- 		r = amdgpu_mes_kiq_hw_init(adev);
+ 		r = amdgpu_mes_kiq_hw_init(adev, 0);
  	else
  		r = gfx_v12_0_kiq_resume(adev);
  	if (r)
@@@ -3650,7 -3656,7 +3656,7 @@@ static int gfx_v12_0_hw_init(struct amd
  	adev->gfx.is_poweron = true;
  
  	if (get_gb_addr_config(adev))
- 		DRM_WARN("Invalid gb_addr_config !\n");
+ 		drm_warn(adev_to_drm(adev), "Invalid gb_addr_config !\n");
  
  	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)
  		gfx_v12_0_config_gfx_rs64(adev);
@@@ -3758,7 -3764,7 +3764,7 @@@ static int gfx_v12_0_hw_fini(struct amd
  		if (amdgpu_gfx_disable_kcq(adev, 0))
  			DRM_ERROR("KCQ disable failed\n");
  
- 		amdgpu_mes_kiq_hw_fini(adev);
+ 		amdgpu_mes_kiq_hw_fini(adev, 0);
  	}
  
  	if (amdgpu_sriov_vf(adev)) {
@@@ -3955,6 -3961,7 +3961,7 @@@ static void gfx_v12_0_update_perf_clk(s
  }
  
  static void gfx_v12_0_update_spm_vmid(struct amdgpu_device *adev,
+ 				      int xcc_id,
  				      struct amdgpu_ring *ring,
  				      unsigned vmid)
  {
@@@ -4386,25 -4393,13 +4393,13 @@@ static void gfx_v12_0_ring_emit_hdp_flu
  {
  	struct amdgpu_device *adev = ring->adev;
  	u32 ref_and_mask, reg_mem_engine;
- 	const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio.hdp_flush_reg;
  
- 	if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) {
- 		switch (ring->me) {
- 		case 1:
- 			ref_and_mask = nbio_hf_reg->ref_and_mask_cp2 << ring->pipe;
- 			break;
- 		case 2:
- 			ref_and_mask = nbio_hf_reg->ref_and_mask_cp6 << ring->pipe;
- 			break;
- 		default:
- 			return;
- 		}
- 		reg_mem_engine = 0;
- 	} else {
- 		ref_and_mask = nbio_hf_reg->ref_and_mask_cp0;
- 		reg_mem_engine = 1; /* pfp */
+ 	if (!adev->gfx.funcs->get_hdp_flush_mask) {
+ 		dev_err(adev->dev, "%s: gfx hdp flush is not supported.\n", __func__);
+ 		return;
  	}
  
+ 	adev->gfx.funcs->get_hdp_flush_mask(ring, &ref_and_mask, &reg_mem_engine);
  	gfx_v12_0_wait_reg_mem(ring, reg_mem_engine, 0, 1,
  			       adev->nbio.funcs->get_hdp_flush_req_offset(adev),
  			       adev->nbio.funcs->get_hdp_flush_done_offset(adev),
@@@ -5040,7 -5035,7 +5035,7 @@@ static int gfx_v12_0_bad_op_irq(struct 
  				struct amdgpu_irq_src *source,
  				struct amdgpu_iv_entry *entry)
  {
- 	DRM_ERROR("Illegal opcode in command stream \n");
+ 	DRM_ERROR("Illegal opcode in command stream\n");
  	gfx_v12_0_handle_priv_fault(adev, entry);
  	return 0;
  }
@@@ -5302,7 -5297,7 +5297,7 @@@ static int gfx_v12_0_reset_kgq(struct a
  
  	amdgpu_ring_reset_helper_begin(ring, timedout_fence);
  
- 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio);
+ 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0);
  	if (r) {
  		dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r);
  		r = gfx_v12_reset_gfx_pipe(ring);
@@@ -5317,7 -5312,7 +5312,7 @@@
  			return r;
  		}
  
- 		r = amdgpu_mes_map_legacy_queue(adev, ring);
+ 		r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
  		if (r) {
  			dev_err(adev->dev, "failed to remap kgq\n");
  			return r;
@@@ -5419,7 -5414,7 +5414,7 @@@ static int gfx_v12_0_reset_kcq(struct a
  
  	amdgpu_ring_reset_helper_begin(ring, timedout_fence);
  
- 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true);
+ 	r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0);
  	if (r) {
  		dev_warn(adev->dev, "fail(%d) to reset kcq  and try pipe reset\n", r);
  		r = gfx_v12_0_reset_compute_pipe(ring);
@@@ -5432,7 -5427,7 +5427,7 @@@
  		dev_err(adev->dev, "failed to init kcq\n");
  		return r;
  	}
- 	r = amdgpu_mes_map_legacy_queue(adev, ring);
+ 	r = amdgpu_mes_map_legacy_queue(adev, ring, 0);
  	if (r) {
  		dev_err(adev->dev, "failed to remap kcq\n");
  		return r;
@@@ -5724,7 -5719,7 +5719,7 @@@ static int gfx_v12_0_get_cu_info(struc
  	if (!adev || !cu_info)
  		return -EINVAL;
  
- 	amdgpu_gfx_parse_disable_cu(disable_masks, 8, 2);
+ 	amdgpu_gfx_parse_disable_cu(adev, disable_masks, 8, 2);
  
  	mutex_lock(&adev->grbm_idx_mutex);
  	for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-01-19 17:03 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-01-19 17:03 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Felix Kuehling, Haoxiang Li,
	Linux Kernel Mailing List, Linux Next Mailing List, Philip Yang

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

between commit:

  80614c509810f ("drm/amdkfd: fix a memory leak in device_queue_manager_init()")

from the origin tree and commit:

  0cba5b27f1924 ("drm/amdkfd: Add domain parameter to alloc kernel BO")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 625ea8ab7a749,b542de9d50d11..0000000000000
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2026-01-19 16:53 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2026-01-19 16:53 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Matthew Brost,
	Thomas Hellström

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/drm_pagemap.c

between commit:

  754c232384386 ("drm/pagemap, drm/xe: Ensure that the devmem allocation is idle before use")

from the origin tree and commits:

  75af93b3f5d0a ("drm/pagemap, drm/xe: Support destination migration over interconnect")
  ec265e1f1cfcc ("drm/pagemap: Support source migration over interconnect")
  3902846af36be ("drm/pagemap Fix error paths in drm_pagemap_migrate_to_devmem")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/drm_pagemap.c
index 06c1bd8fc4d17,03ee39a761a41..0000000000000
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2025-10-02 12:07 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2025-10-02 12:07 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Rob Herring,
	Thomas Zimmermann, Wig Cheng

[-- Attachment #1: Type: text/plain, Size: 1332 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  Documentation/devicetree/bindings/vendor-prefixes.yaml

between commit:

  4ed46073274a5 ("dt-bindings: vendor-prefixes: Add undocumented vendor prefixes")

from the origin tree and commit:

  09b26dce32f0d ("dt-bindings: vendor-prefixes: Add Mayqueen name")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc Documentation/devicetree/bindings/vendor-prefixes.yaml
index 7aa17199ea434,49a5117d2bbb0..0000000000000
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@@ -965,8 -935,8 +967,10 @@@ patternProperties
      description: Maxim Integrated Products
    "^maxlinear,.*":
      description: MaxLinear Inc.
 +  "^maxtor,.*":
 +    description: Maxtor Corporation
+   "^mayqueen,.*":
+     description: Mayqueen Technologies Ltd.
    "^mbvl,.*":
      description: Mobiveil Inc.
    "^mcube,.*":

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2025-10-02 12:05 Mark Brown
  2025-10-02 12:30 ` Danilo Krummrich
  0 siblings, 1 reply; 28+ messages in thread
From: Mark Brown @ 2025-10-02 12:05 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alice Ryhl, Andrew Morton, Danilo Krummrich,
	Linux Kernel Mailing List, Linux Next Mailing List, Vitaly Wool

[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  rust/kernel/alloc/allocator.rs

between commit:

  1b1a946dc2b53 ("rust: alloc: specify the minimum alignment of each allocator")

from the origin tree and commits:

  1738796994a43 ("rust: support large alignments in allocations")
  8e92c9902ff11 ("rust: alloc: vmalloc: implement Vmalloc::to_page()")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc rust/kernel/alloc/allocator.rs
index 6426ba54cf98d,84ee7e9d7b0eb..0000000000000
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@@ -13,11 -13,14 +13,15 @@@ use core::alloc::Layout
  use core::ptr;
  use core::ptr::NonNull;
  
 -use crate::alloc::{AllocError, Allocator};
 +use crate::alloc::{AllocError, Allocator, NumaNode};
  use crate::bindings;
+ use crate::page;
 -use crate::pr_warn;
 +
 +const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
  
+ mod iter;
+ pub use self::iter::VmallocPageIter;
+ 
  /// The contiguous kernel allocator.
  ///
  /// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2025-09-26 12:38 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2025-09-26 12:38 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List,
	Lucas De Marchi, Michal Wajdeczko, Rodrigo Vivi, Zongyao Bai

[-- Attachment #1: Type: text/plain, Size: 1151 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_device_sysfs.c

between commits:

  ff89a4d285c82 ("drm/xe/sysfs: Add cleanup action in xe_device_sysfs_init")
  500dad428e5b0 ("drm/xe/vf: Don't expose sysfs attributes not applicable for VFs")

from the origin tree and commits:

  1a869168d91f1 ("drm/xe/sysfs: Add cleanup action in xe_device_sysfs_init")
  a2d6223d224f3 ("drm/xe/vf: Don't expose sysfs attributes not applicable for VFs")
  fb3c27a69c473 ("drm/xe/sysfs: Simplify sysfs registration")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/xe/xe_device_sysfs.c
index 927ee7991696b,c5151c86a98ae..0000000000000
--- a/drivers/gpu/drm/xe/xe_device_sysfs.c
+++ b/drivers/gpu/drm/xe/xe_device_sysfs.c

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2024-06-28 16:51 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2024-06-28 16:51 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Linux Kernel Mailing List, Linux Next Mailing List, Riana Tauro,
	Rodrigo Vivi, Thomas Hellström

[-- Attachment #1: Type: text/plain, Size: 958 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/xe/xe_gt_idle.c

between commit:

  2470b141bfae2 ("drm/xe: move disable_c6 call")

from the origin tree and commits:

  6800e63cf97ba ("drm/xe: move disable_c6 call")
  38e8c4184ea0e ("drm/xe: Enable Coarse Power Gating")
  ecab82af27873 ("drm/xe/vf: Don't support gtidle if VF")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.


diff --cc drivers/gpu/drm/xe/xe_gt_idle.c
index 944770fb2daff,67aba41405100..0000000000000
--- a/drivers/gpu/drm/xe/xe_gt_idle.c
+++ b/drivers/gpu/drm/xe/xe_gt_idle.c

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread
* linux-next: manual merge of the drm tree with the origin tree
@ 2024-06-27 15:06 Mark Brown
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Brown @ 2024-06-27 15:06 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Dillon Varone, Linux Kernel Mailing List,
	Linux Next Mailing List, Michael Strauss

[-- Attachment #1: Type: text/plain, Size: 1002 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c

between commit:

  c03d770c0b014 ("drm/amd/display: Attempt to avoid empty TUs when endpoint is DPIA")

from the origin tree and commit:

  0127f0445f7c1 ("drm/amd/display: Refactor input mode programming for DIG FIFO")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index 199781233fd5f,428912f371291..0000000000000
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-08-07 14:37 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07 14:37 linux-next: manual merge of the drm tree with the origin tree Mark Brown
  -- strict thread matches above, loose matches on Subject: below --
2026-08-03 14:31 Mark Brown
2026-08-03 14:31 Mark Brown
2026-07-31 14:01 Mark Brown
2026-07-20 14:44 Mark Brown
2026-07-20 14:44 Mark Brown
2026-06-09 17:53 Mark Brown
2026-06-04 14:13 Mark Brown
2026-05-18 12:47 Mark Brown
2026-04-14 13:08 Mark Brown
2026-04-14 13:12 ` Miguel Ojeda
2026-03-30 15:49 Mark Brown
2026-03-27 20:56 Mark Brown
2026-03-23 15:55 Mark Brown
2026-03-23 15:55 Mark Brown
2026-03-23 15:49 Mark Brown
2026-03-23 15:01 Mark Brown
2026-02-08 22:47 Mark Brown
2026-02-08 22:46 Mark Brown
2026-02-02 14:29 Mark Brown
2026-01-19 17:03 Mark Brown
2026-01-19 16:53 Mark Brown
2025-10-02 12:07 Mark Brown
2025-10-02 12:05 Mark Brown
2025-10-02 12:30 ` Danilo Krummrich
2025-09-26 12:38 Mark Brown
2024-06-28 16:51 Mark Brown
2024-06-27 15:06 Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox