瀏覽代碼

Merge "disp: msm: sde: increase display kickoff timeout for hw-fences"

qctecmdr 2 年之前
父節點
當前提交
d3d044ec00

+ 13 - 1
msm/sde/sde_crtc.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <[email protected]>
  * Author: Rob Clark <[email protected]>
@@ -4518,6 +4518,18 @@ void sde_crtc_dump_fences(struct drm_crtc *crtc)
 		sde_plane_dump_input_fence(plane);
 		sde_plane_dump_input_fence(plane);
 }
 }
 
 
+bool sde_crtc_is_fence_signaled(struct drm_crtc *crtc)
+{
+	struct drm_plane *plane = NULL;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		if (!sde_plane_is_sw_fence_signaled(plane))
+			return false;
+	}
+
+	return true;
+}
+
 /**
 /**
  * sde_crtc_reset_hw - attempt hardware reset on errors
  * sde_crtc_reset_hw - attempt hardware reset on errors
  * @crtc: Pointer to DRM crtc instance
  * @crtc: Pointer to DRM crtc instance

+ 8 - 1
msm/sde/sde_crtc.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <[email protected]>
  * Author: Rob Clark <[email protected]>
@@ -653,6 +653,13 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
  */
  */
 void sde_crtc_dump_fences(struct drm_crtc *crtc);
 void sde_crtc_dump_fences(struct drm_crtc *crtc);
 
 
+/**
+ * sde_crtc_is_fence_signaled - check if all fences have been signaled
+ * @crtc: Pointer to DRM crtc instance
+ * Returns: true if all fences are signaled, otherwise false.
+ */
+bool sde_crtc_is_fence_signaled(struct drm_crtc *crtc);
+
 /**
 /**
  * sde_crtc_request_frame_reset - requests for next frame reset
  * sde_crtc_request_frame_reset - requests for next frame reset
  * @crtc: Pointer to drm crtc object
  * @crtc: Pointer to drm crtc object

+ 61 - 0
msm/sde/sde_encoder.c

@@ -384,6 +384,55 @@ static int _sde_encoder_wait_timeout(int32_t drm_id, int32_t hw_id,
 	return rc;
 	return rc;
 }
 }
 
 
+int sde_encoder_helper_hw_fence_extended_wait(struct sde_encoder_phys *phys_enc,
+	struct sde_hw_ctl *ctl, struct sde_encoder_wait_info *wait_info, int wait_type)
+{
+	int ret = -ETIMEDOUT;
+	s64 standard_kickoff_timeout_ms = wait_info->timeout_ms;
+	int timeout_iters = EXTENDED_KICKOFF_TIMEOUT_ITERS;
+
+	wait_info->timeout_ms = EXTENDED_KICKOFF_TIMEOUT_MS;
+
+	while (ret == -ETIMEDOUT && timeout_iters--) {
+		ret = sde_encoder_helper_wait_for_irq(phys_enc, wait_type, wait_info);
+		if (ret == -ETIMEDOUT) {
+			/* if dma_fence is not signaled, keep waiting */
+			if (!sde_crtc_is_fence_signaled(phys_enc->parent->crtc))
+				continue;
+
+			/* timed-out waiting and no sw-override support for hw-fences */
+			if (!ctl || !ctl->ops.hw_fence_trigger_sw_override) {
+				SDE_ERROR("invalid argument(s)\n");
+				break;
+			}
+
+			/*
+			 * In case the sw and hw fences were triggered at the same time,
+			 * wait the standard kickoff time one more time. Only override if
+			 * we timeout again.
+			 */
+			wait_info->timeout_ms = standard_kickoff_timeout_ms;
+			ret = sde_encoder_helper_wait_for_irq(phys_enc, wait_type, wait_info);
+			if (ret == -ETIMEDOUT) {
+				sde_encoder_helper_hw_fence_sw_override(phys_enc, ctl);
+
+				/*
+				 * wait the original timeout time again if we
+				 * did sw override due to fence being signaled
+				 */
+				ret = sde_encoder_helper_wait_for_irq(phys_enc, wait_type,
+					wait_info);
+			}
+			break;
+		}
+	}
+
+	/* reset the timeout value */
+	wait_info->timeout_ms = standard_kickoff_timeout_ms;
+
+	return ret;
+}
+
 bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc)
 bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc)
 {
 {
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
@@ -4888,6 +4937,18 @@ int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc,
 	return 0;
 	return 0;
 }
 }
 
 
+void sde_encoder_helper_hw_fence_sw_override(struct sde_encoder_phys *phys_enc,
+		struct sde_hw_ctl *ctl)
+{
+	if (!ctl || !ctl->ops.hw_fence_trigger_sw_override)
+		return;
+
+	SDE_EVT32(DRMID(phys_enc->parent), ctl->idx, ctl->ops.get_hw_fence_status ?
+		ctl->ops.get_hw_fence_status(ctl) : SDE_EVTLOG_ERROR);
+	sde_encoder_helper_reset_mixers(phys_enc, NULL);
+	ctl->ops.hw_fence_trigger_sw_override(ctl);
+}
+
 int sde_encoder_prepare_commit(struct drm_encoder *drm_enc)
 int sde_encoder_prepare_commit(struct drm_encoder *drm_enc)
 {
 {
 	struct sde_encoder_virt *sde_enc;
 	struct sde_encoder_virt *sde_enc;

+ 22 - 0
msm/sde/sde_encoder_phys.h

@@ -26,6 +26,10 @@
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
 /* wait for at most 2 vsync for lowest refresh rate (24hz) */
 #define DEFAULT_KICKOFF_TIMEOUT_MS		84
 #define DEFAULT_KICKOFF_TIMEOUT_MS		84
 
 
+/* if default timeout fails wait additional time in 1s increments */
+#define EXTENDED_KICKOFF_TIMEOUT_MS      1000
+#define EXTENDED_KICKOFF_TIMEOUT_ITERS   10
+
 /* wait 1 sec for the emulated targets */
 /* wait 1 sec for the emulated targets */
 #define MAX_KICKOFF_TIMEOUT_MS                  100000
 #define MAX_KICKOFF_TIMEOUT_MS                  100000
 
 
@@ -726,6 +730,13 @@ void sde_encoder_helper_split_config(
  */
  */
 int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc,
 int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc,
 		struct drm_framebuffer *fb);
 		struct drm_framebuffer *fb);
+/**
+ * sde_encoder_helper_hw_fence_sw_override - reset mixers and do hw-fence sw override
+ * @phys_enc: Pointer to physical encoder structure
+ * @ctl: Pointer to hw_ctl structure
+ */
+void sde_encoder_helper_hw_fence_sw_override(struct sde_encoder_phys *phys_enc,
+		struct sde_hw_ctl *ctl);
 
 
 /**
 /**
  * sde_encoder_helper_report_irq_timeout - utility to report error that irq has
  * sde_encoder_helper_report_irq_timeout - utility to report error that irq has
@@ -839,6 +850,17 @@ static inline bool sde_encoder_phys_needs_single_flush(
 				!_sde_encoder_phys_is_dual_ctl(phys_enc));
 				!_sde_encoder_phys_is_dual_ctl(phys_enc));
 }
 }
 
 
+/**
+ * sde_encoder_helper_hw_fence_extended_wait - extended kickoff wait for hw-fence enabled case
+ * @phys_enc:	Pointer to physical encoder structure
+ * @ctl:	Pointer to hw ctl structure
+ * @wait_info:	Pointer to wait_info structure
+ * @wait_type:	Enum indicating the irq to wait for
+ * Returns:	-ETIMEDOUT in the case that the extended wait times out, 0 otherwise
+ */
+int sde_encoder_helper_hw_fence_extended_wait(struct sde_encoder_phys *phys_enc,
+	struct sde_hw_ctl *ctl, struct sde_encoder_wait_info *wait_info, int wait_type);
+
 /**
 /**
  * sde_encoder_helper_phys_disable - helper function to disable virt encoder
  * sde_encoder_helper_phys_disable - helper function to disable virt encoder
  * @phys_enc: Pointer to physical encoder structure
  * @phys_enc: Pointer to physical encoder structure

+ 13 - 0
msm/sde/sde_encoder_phys_cmd.c

@@ -1725,6 +1725,15 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
 
 
 	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WRPTR,
 	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WRPTR,
 			&wait_info);
 			&wait_info);
+
+	/*
+	 * if hwfencing enabled, try again to wait for up to the extended timeout time in
+	 * increments as long as fence has not been signaled.
+	 */
+	if (ret == -ETIMEDOUT && phys_enc->sde_kms->catalog->hw_fence_rev)
+		ret = sde_encoder_helper_hw_fence_extended_wait(phys_enc, ctl, &wait_info,
+			INTR_IDX_WRPTR);
+
 	if (ret == -ETIMEDOUT) {
 	if (ret == -ETIMEDOUT) {
 		struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
 		struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
 
 
@@ -1754,6 +1763,10 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
 					lock_flags);
 					lock_flags);
 			}
 			}
 		}
 		}
+
+		/* if we timeout after the extended wait, reset mixers and do sw override */
+		if (ret && phys_enc->sde_kms->catalog->hw_fence_rev)
+			sde_encoder_helper_hw_fence_sw_override(phys_enc, ctl);
 	}
 	}
 
 
 	cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;
 	cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;

+ 12 - 0
msm/sde/sde_encoder_phys_vid.c

@@ -913,6 +913,14 @@ static int _sde_encoder_phys_vid_wait_for_vblank(
 	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC,
 	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC,
 			&wait_info);
 			&wait_info);
 
 
+	/*
+	 * if hwfencing enabled, try again to wait for up to the extended timeout time in
+	 * increments as long as fence has not been signaled.
+	 */
+	if (ret == -ETIMEDOUT && phys_enc->sde_kms->catalog->hw_fence_rev)
+		ret = sde_encoder_helper_hw_fence_extended_wait(phys_enc, phys_enc->hw_ctl,
+			&wait_info, INTR_IDX_VSYNC);
+
 	if (ret == -ETIMEDOUT) {
 	if (ret == -ETIMEDOUT) {
 		new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
 		new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
 		timeout = true;
 		timeout = true;
@@ -926,6 +934,10 @@ static int _sde_encoder_phys_vid_wait_for_vblank(
 		if (!flush_register)
 		if (!flush_register)
 			ret = 0;
 			ret = 0;
 
 
+		/* if we timeout after the extended wait, reset mixers and do sw override */
+		if (ret && phys_enc->sde_kms->catalog->hw_fence_rev)
+			sde_encoder_helper_hw_fence_sw_override(phys_enc, hw_ctl);
+
 		SDE_EVT32(DRMID(phys_enc->parent), new_cnt, flush_register, ret,
 		SDE_EVT32(DRMID(phys_enc->parent), new_cnt, flush_register, ret,
 				SDE_EVTLOG_FUNC_CASE1);
 				SDE_EVTLOG_FUNC_CASE1);
 	}
 	}

+ 16 - 1
msm/sde/sde_encoder_phys_wb.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
  */
 
 
@@ -2131,6 +2131,7 @@ static int _sde_encoder_phys_wb_wait_for_ctl_start(struct sde_encoder_phys *phys
 {
 {
 	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
 	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
 	struct sde_encoder_wait_info wait_info = {0};
 	struct sde_encoder_wait_info wait_info = {0};
+	struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
 	int rc = 0;
 	int rc = 0;
 
 
 	if (!atomic_read(&phys_enc->pending_ctl_start_cnt))
 	if (!atomic_read(&phys_enc->pending_ctl_start_cnt))
@@ -2146,8 +2147,22 @@ static int _sde_encoder_phys_wb_wait_for_ctl_start(struct sde_encoder_phys *phys
 	wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, phys_enc->kickoff_timeout_ms);
 	wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, phys_enc->kickoff_timeout_ms);
 
 
 	rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START, &wait_info);
 	rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START, &wait_info);
+
+	/*
+	 * if hwfencing enabled, try again to wait for up to the extended timeout time in
+	 * increments as long as fence has not been signaled.
+	 */
+	if (rc == -ETIMEDOUT && phys_enc->sde_kms->catalog->hw_fence_rev && hw_ctl)
+		rc = sde_encoder_helper_hw_fence_extended_wait(phys_enc, hw_ctl,
+			&wait_info, INTR_IDX_CTL_START);
+
 	if (rc == -ETIMEDOUT) {
 	if (rc == -ETIMEDOUT) {
 		atomic_add_unless(&phys_enc->pending_ctl_start_cnt, -1, 0);
 		atomic_add_unless(&phys_enc->pending_ctl_start_cnt, -1, 0);
+
+		/* if we timeout after the extended wait, reset mixers and do sw override */
+		if (phys_enc->sde_kms->catalog->hw_fence_rev)
+			sde_encoder_helper_hw_fence_sw_override(phys_enc, hw_ctl);
+
 		SDE_ERROR("[enc:%d wb:%d] ctl_start timed out\n",
 		SDE_ERROR("[enc:%d wb:%d] ctl_start timed out\n",
 				DRMID(phys_enc->parent), WBID(wb_enc));
 				DRMID(phys_enc->parent), WBID(wb_enc));
 		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), SDE_EVTLOG_ERROR);
 		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), SDE_EVTLOG_ERROR);

+ 24 - 1
msm/sde/sde_plane.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (C) 2014-2021 The Linux Foundation. All rights reserved.
  * Copyright (C) 2014-2021 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <[email protected]>
  * Author: Rob Clark <[email protected]>
@@ -614,6 +614,29 @@ void sde_plane_dump_input_fence(struct drm_plane *plane)
 	}
 	}
 }
 }
 
 
+bool sde_plane_is_sw_fence_signaled(struct drm_plane *plane)
+{
+	struct sde_plane *psde;
+	struct sde_plane_state *pstate;
+	struct dma_fence *fence;
+
+	if (!plane) {
+		SDE_ERROR("invalid plane\n");
+	} else if (!plane->state) {
+		SDE_ERROR_PLANE(to_sde_plane(plane), "invalid state\n");
+	} else {
+		psde = to_sde_plane(plane);
+		pstate = to_sde_plane_state(plane->state);
+
+		if (pstate->input_fence) {
+			fence = (struct dma_fence *)pstate->input_fence;
+			return dma_fence_is_signaled(fence);
+		}
+	}
+
+	return false;
+}
+
 int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
 int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
 {
 {
 	struct sde_plane *psde;
 	struct sde_plane *psde;

+ 8 - 1
msm/sde/sde_plane.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <[email protected]>
  * Author: Rob Clark <[email protected]>
@@ -431,4 +431,11 @@ void sde_plane_add_data_to_minidump_va(struct drm_plane *plane);
  * @plane: Pointer to drm plane structure with the input fence we want to dump
  * @plane: Pointer to drm plane structure with the input fence we want to dump
  */
  */
 void sde_plane_dump_input_fence(struct drm_plane *plane);
 void sde_plane_dump_input_fence(struct drm_plane *plane);
+
+/**
+ * sde_plane_is_sw_fence_signaled - determine if the sw input dma-fence is signaled
+ * @plane: Pointer to drm plane structure with the input fence to check
+ * Returns: true if the input sw fence is signaled, otherwise false.
+ */
+bool sde_plane_is_sw_fence_signaled(struct drm_plane *plane);
 #endif /* _SDE_PLANE_H_ */
 #endif /* _SDE_PLANE_H_ */