All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/amdgpu: Polish SQ IH.
@ 2018-06-19 16:09 Andrey Grodzovsky
       [not found] ` <1529424573-21761-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Andrey Grodzovsky @ 2018-06-19 16:09 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: David.Panariti-5C7GfCeVMHo, nicolai.haehnle-5C7GfCeVMHo,
	Andrey Grodzovsky

Switch to using reg fields defines istead of magic values.
Add SH_ID and PRIV fields reading for instr. and err cases.

Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 36 +++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 15e61e1..93904a7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -6958,10 +6958,11 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
 {
 	u8 enc, se_id;
 	char type[20];
+	unsigned ih_data = entry->src_data[0];
 
-	/* Parse all fields according to SQ_INTERRUPT* registers */
-	enc = (entry->src_data[0] >> 26) & 0x3;
-	se_id = (entry->src_data[0] >> 24) & 0x3;
+
+	enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING);
+	se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID);
 
 	switch (enc) {
 		case 0:
@@ -6971,14 +6972,14 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
 					"reg_timestamp %d, thread_trace_buff_full %d,"
 					"wlt %d, thread_trace %d.\n",
 					se_id,
-					(entry->src_data[0] >> 7) & 0x1,
-					(entry->src_data[0] >> 6) & 0x1,
-					(entry->src_data[0] >> 5) & 0x1,
-					(entry->src_data[0] >> 4) & 0x1,
-					(entry->src_data[0] >> 3) & 0x1,
-					(entry->src_data[0] >> 2) & 0x1,
-					(entry->src_data[0] >> 1) & 0x1,
-					entry->src_data[0] & 0x1
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, IMMED_OVERFLOW),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_REG_OVERFLOW),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_CMD_OVERFLOW),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, CMD_TIMESTAMP),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, REG_TIMESTAMP),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE_BUF_FULL),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, WLT),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE)
 					);
 			break;
 		case 1:
@@ -6991,12 +6992,15 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
 
 			DRM_INFO(
 				"SQ %s detected: "
-					"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n",
+					"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n"
+					"trap %s, sh_id %d. ",
 					type, se_id,
-					(entry->src_data[0] >> 20) & 0xf,
-					(entry->src_data[0] >> 18) & 0x3,
-					(entry->src_data[0] >> 14) & 0xf,
-					(entry->src_data[0] >> 10) & 0xf
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID),
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false",
+					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID)
 					);
 			break;
 		default:
-- 
2.7.4

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

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

* [PATCH 2/2] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH.
       [not found] ` <1529424573-21761-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
@ 2018-06-19 16:09   ` Andrey Grodzovsky
       [not found]     ` <1529424573-21761-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Andrey Grodzovsky @ 2018-06-19 16:09 UTC (permalink / raw)
  To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: David.Panariti-5C7GfCeVMHo, nicolai.haehnle-5C7GfCeVMHo,
	Andrey Grodzovsky

Access to SQ_EDC_INFO requires selecting register instance and
hence mutex lock when accessing GRBM_GFX_INDEX for which a work
is schedueled from IH. But SQ interrupt can be raised on many instances
at once which means queuing work will usually succeed for the first one
but fail for the reset since the work takes time to process. To avoid
losing info about other interrupt instances call the parsing function
directly from high IRQ when current work hasn't finished and avoid
accessing SQ_EDC_INFO in that case.

Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  7 +++
 drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 97 ++++++++++++++++++++++++++++++-----
 2 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index e8c6cc1..a7b9ef5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -930,6 +930,11 @@ struct amdgpu_ngg {
 	bool			init;
 };
 
+struct sq_work {
+	struct work_struct	work;
+	unsigned ih_data;
+};
+
 struct amdgpu_gfx {
 	struct mutex			gpu_clock_mutex;
 	struct amdgpu_gfx_config	config;
@@ -970,6 +975,8 @@ struct amdgpu_gfx {
 	struct amdgpu_irq_src		priv_inst_irq;
 	struct amdgpu_irq_src		cp_ecc_error_irq;
 	struct amdgpu_irq_src		sq_irq;
+	struct sq_work			sq_work;
+
 	/* gfx status */
 	uint32_t			gfx_current_status;
 	/* ce ram size*/
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 93904a7..0add7fc 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -704,6 +704,17 @@ static const u32 stoney_mgcg_cgcg_init[] =
 	mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
 };
 
+
+static const char * const sq_edc_source_names[] = {
+	"SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred",
+	"SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch",
+	"SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data return",
+	"SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR",
+	"SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS",
+	"SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS",
+	"SQ_EDC_INFO_SOURCE_TA: EDC source is TA",
+};
+
 static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev);
 static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev);
 static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev);
@@ -2003,6 +2014,8 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
 	return 0;
 }
 
+static void gfx_v8_0_sq_irq_work_func(struct work_struct *work);
+
 static int gfx_v8_0_sw_init(void *handle)
 {
 	int i, j, k, r, ring_id;
@@ -2066,6 +2079,8 @@ static int gfx_v8_0_sw_init(void *handle)
 		return r;
 	}
 
+	INIT_WORK(&adev->gfx.sq_work.work, gfx_v8_0_sq_irq_work_func);
+
 	adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
 
 	gfx_v8_0_scratch_init(adev);
@@ -6952,14 +6967,11 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev,
 	return 0;
 }
 
-static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
-			   struct amdgpu_irq_src *source,
-			   struct amdgpu_iv_entry *entry)
+static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev, unsigned ih_data)
 {
-	u8 enc, se_id;
+	u32 enc, se_id, sh_id, cu_id;
 	char type[20];
-	unsigned ih_data = entry->src_data[0];
-
+	int sq_edc_source = -1;
 
 	enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING);
 	se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID);
@@ -6985,6 +6997,24 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
 		case 1:
 		case 2:
 
+			cu_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID);
+			sh_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID);
+
+			/*
+			 * This function can be called either directly from ISR
+			 * or from BH in which case we can access SQ_EDC_INFO
+			 * instance
+			 */
+			if (in_task()) {
+				mutex_lock(&adev->grbm_idx_mutex);
+				gfx_v8_0_select_se_sh(adev, se_id, sh_id, cu_id);
+
+				sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE);
+
+				gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+				mutex_unlock(&adev->grbm_idx_mutex);
+			}
+
 			if (enc == 1)
 				sprintf(type, "instruction intr");
 			else
@@ -6992,20 +7022,61 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
 
 			DRM_INFO(
 				"SQ %s detected: "
-					"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n"
-					"trap %s, sh_id %d. ",
-					type, se_id,
-					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID),
+					"se_id %d, sh_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d "
+					"trap %s, sq_ed_info.source %s.\n",
+					type, se_id, sh_id, cu_id,
 					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID),
 					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID),
 					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID),
 					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false",
-					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID)
-					);
+					(sq_edc_source != -1) ? sq_edc_source_names[sq_edc_source] : "unavailable"
+				);
 			break;
 		default:
 			DRM_ERROR("SQ invalid encoding type\n.");
-			return -EINVAL;
+	}
+}
+
+static void gfx_v8_0_sq_irq_work_func(struct work_struct *work)
+{
+
+	struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.sq_work.work);
+	struct sq_work *sq_work = container_of(work, struct sq_work, work);
+
+	smp_rmb();
+
+	gfx_v8_0_parse_sq_irq(adev, READ_ONCE(sq_work->ih_data));
+
+	WRITE_ONCE(sq_work->ih_data, 0);
+	/* Make the value change visible ASAP to IH */
+	smp_wmb();
+}
+
+static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
+			   struct amdgpu_irq_src *source,
+			   struct amdgpu_iv_entry *entry)
+{
+	unsigned ih_data = entry->src_data[0];
+
+	/*
+	 * Try to submit work so SQ_EDC_INFO can be accessed from
+	 * BH. If previous work submission hasn't finished yet
+	 * just print whatever info is possible directly from the ISR.
+	 */
+	smp_rmb();
+	if (READ_ONCE(adev->gfx.sq_work.ih_data))
+		gfx_v8_0_parse_sq_irq(adev, ih_data);
+	else {
+		WRITE_ONCE(adev->gfx.sq_work.ih_data, ih_data);
+		/* Verify the new value visible in BH handler */
+		smp_wmb();
+		if (!schedule_work(&adev->gfx.sq_work.work)) {
+
+			WRITE_ONCE(adev->gfx.sq_work.ih_data, 0);
+			gfx_v8_0_parse_sq_irq(adev, ih_data);
+			/* Verify 0 is visible to next HW IH */
+			smp_wmb();
+		}
 	}
 
 	return 0;
-- 
2.7.4

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

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

* Re: [PATCH 2/2] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH.
       [not found]     ` <1529424573-21761-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
@ 2018-06-20  6:37       ` Christian König
       [not found]         ` <a32b1a8b-da3e-7da4-636f-c8699022961f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Christian König @ 2018-06-20  6:37 UTC (permalink / raw)
  To: Andrey Grodzovsky, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: David.Panariti-5C7GfCeVMHo, nicolai.haehnle-5C7GfCeVMHo

Am 19.06.2018 um 18:09 schrieb Andrey Grodzovsky:
> Access to SQ_EDC_INFO requires selecting register instance and
> hence mutex lock when accessing GRBM_GFX_INDEX for which a work
> is schedueled from IH. But SQ interrupt can be raised on many instances
> at once which means queuing work will usually succeed for the first one
> but fail for the reset since the work takes time to process. To avoid
> losing info about other interrupt instances call the parsing function
> directly from high IRQ when current work hasn't finished and avoid
> accessing SQ_EDC_INFO in that case.
>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  7 +++
>   drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 97 ++++++++++++++++++++++++++++++-----
>   2 files changed, 91 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index e8c6cc1..a7b9ef5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -930,6 +930,11 @@ struct amdgpu_ngg {
>   	bool			init;
>   };
>   
> +struct sq_work {
> +	struct work_struct	work;
> +	unsigned ih_data;
> +};
> +
>   struct amdgpu_gfx {
>   	struct mutex			gpu_clock_mutex;
>   	struct amdgpu_gfx_config	config;
> @@ -970,6 +975,8 @@ struct amdgpu_gfx {
>   	struct amdgpu_irq_src		priv_inst_irq;
>   	struct amdgpu_irq_src		cp_ecc_error_irq;
>   	struct amdgpu_irq_src		sq_irq;
> +	struct sq_work			sq_work;
> +
>   	/* gfx status */
>   	uint32_t			gfx_current_status;
>   	/* ce ram size*/
> diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> index 93904a7..0add7fc 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> @@ -704,6 +704,17 @@ static const u32 stoney_mgcg_cgcg_init[] =
>   	mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
>   };
>   
> +
> +static const char * const sq_edc_source_names[] = {
> +	"SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred",
> +	"SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch",
> +	"SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data return",
> +	"SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR",
> +	"SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS",
> +	"SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS",
> +	"SQ_EDC_INFO_SOURCE_TA: EDC source is TA",
> +};
> +
>   static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev);
>   static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev);
>   static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev);
> @@ -2003,6 +2014,8 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
>   	return 0;
>   }
>   
> +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work);
> +
>   static int gfx_v8_0_sw_init(void *handle)
>   {
>   	int i, j, k, r, ring_id;
> @@ -2066,6 +2079,8 @@ static int gfx_v8_0_sw_init(void *handle)
>   		return r;
>   	}
>   
> +	INIT_WORK(&adev->gfx.sq_work.work, gfx_v8_0_sq_irq_work_func);
> +
>   	adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
>   
>   	gfx_v8_0_scratch_init(adev);
> @@ -6952,14 +6967,11 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev,
>   	return 0;
>   }
>   
> -static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
> -			   struct amdgpu_irq_src *source,
> -			   struct amdgpu_iv_entry *entry)
> +static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev, unsigned ih_data)
>   {
> -	u8 enc, se_id;
> +	u32 enc, se_id, sh_id, cu_id;
>   	char type[20];
> -	unsigned ih_data = entry->src_data[0];
> -
> +	int sq_edc_source = -1;
>   
>   	enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING);
>   	se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID);
> @@ -6985,6 +6997,24 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
>   		case 1:
>   		case 2:
>   
> +			cu_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID);
> +			sh_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID);
> +
> +			/*
> +			 * This function can be called either directly from ISR
> +			 * or from BH in which case we can access SQ_EDC_INFO
> +			 * instance
> +			 */
> +			if (in_task()) {
> +				mutex_lock(&adev->grbm_idx_mutex);
> +				gfx_v8_0_select_se_sh(adev, se_id, sh_id, cu_id);
> +
> +				sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE);
> +
> +				gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
> +				mutex_unlock(&adev->grbm_idx_mutex);
> +			}
> +
>   			if (enc == 1)
>   				sprintf(type, "instruction intr");
>   			else
> @@ -6992,20 +7022,61 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
>   
>   			DRM_INFO(
>   				"SQ %s detected: "
> -					"se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n"
> -					"trap %s, sh_id %d. ",
> -					type, se_id,
> -					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID),
> +					"se_id %d, sh_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d "
> +					"trap %s, sq_ed_info.source %s.\n",
> +					type, se_id, sh_id, cu_id,
>   					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID),
>   					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID),
>   					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID),
>   					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false",
> -					REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID)
> -					);
> +					(sq_edc_source != -1) ? sq_edc_source_names[sq_edc_source] : "unavailable"
> +				);
>   			break;
>   		default:
>   			DRM_ERROR("SQ invalid encoding type\n.");
> -			return -EINVAL;
> +	}
> +}
> +
> +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work)
> +{
> +
> +	struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.sq_work.work);
> +	struct sq_work *sq_work = container_of(work, struct sq_work, work);
> +
> +	smp_rmb();
> +
> +	gfx_v8_0_parse_sq_irq(adev, READ_ONCE(sq_work->ih_data));
> +
> +	WRITE_ONCE(sq_work->ih_data, 0);
> +	/* Make the value change visible ASAP to IH */
> +	smp_wmb();
> +}
> +
> +static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
> +			   struct amdgpu_irq_src *source,
> +			   struct amdgpu_iv_entry *entry)
> +{
> +	unsigned ih_data = entry->src_data[0];
> +
> +	/*
> +	 * Try to submit work so SQ_EDC_INFO can be accessed from
> +	 * BH. If previous work submission hasn't finished yet
> +	 * just print whatever info is possible directly from the ISR.
> +	 */
> +	smp_rmb();
> +	if (READ_ONCE(adev->gfx.sq_work.ih_data))
> +		gfx_v8_0_parse_sq_irq(adev, ih_data);
> +	else {
> +		WRITE_ONCE(adev->gfx.sq_work.ih_data, ih_data);
> +		/* Verify the new value visible in BH handler */
> +		smp_wmb();
> +		if (!schedule_work(&adev->gfx.sq_work.work)) {
> +
> +			WRITE_ONCE(adev->gfx.sq_work.ih_data, 0);
> +			gfx_v8_0_parse_sq_irq(adev, ih_data);
> +			/* Verify 0 is visible to next HW IH */
> +			smp_wmb();
> +		}

At least of hand that looks like it is racy.

You should probably rather use work_pending() like this:

if (work_pending(&adev->gfx.sq_work.work)) {
     gfx_v8_0_parse_sq_irq(adev, ih_data);
} else {
     adev->gfx.sq_work.ih_data = ih_data;
     schedule_work(&adev->gfx.sq_work.work);
}

Regards,
Christian.

>   	}
>   
>   	return 0;

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

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

* RE: [PATCH 2/2] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH.
       [not found]         ` <a32b1a8b-da3e-7da4-636f-c8699022961f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2018-06-20  9:42           ` Grodzovsky, Andrey
  0 siblings, 0 replies; 4+ messages in thread
From: Grodzovsky, Andrey @ 2018-06-20  9:42 UTC (permalink / raw)
  To: Koenig, Christian, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: Panariti, David, Haehnle, Nicolai



> -----Original Message-----
> From: Christian König [mailto:ckoenig.leichtzumerken@gmail.com]
> Sent: Wednesday, June 20, 2018 2:37 AM
> To: Grodzovsky, Andrey <Andrey.Grodzovsky@amd.com>; amd-
> gfx@lists.freedesktop.org
> Cc: Panariti, David <David.Panariti@amd.com>; Haehnle, Nicolai
> <Nicolai.Haehnle@amd.com>
> Subject: Re: [PATCH 2/2] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH.
> 
> Am 19.06.2018 um 18:09 schrieb Andrey Grodzovsky:
> > Access to SQ_EDC_INFO requires selecting register instance and hence
> > mutex lock when accessing GRBM_GFX_INDEX for which a work is
> > schedueled from IH. But SQ interrupt can be raised on many instances
> > at once which means queuing work will usually succeed for the first
> > one but fail for the reset since the work takes time to process. To
> > avoid losing info about other interrupt instances call the parsing
> > function directly from high IRQ when current work hasn't finished and
> > avoid accessing SQ_EDC_INFO in that case.
> >
> > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> > ---
> >   drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  7 +++
> >   drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 97
> ++++++++++++++++++++++++++++++-----
> >   2 files changed, 91 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > index e8c6cc1..a7b9ef5 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > @@ -930,6 +930,11 @@ struct amdgpu_ngg {
> >   	bool			init;
> >   };
> >
> > +struct sq_work {
> > +	struct work_struct	work;
> > +	unsigned ih_data;
> > +};
> > +
> >   struct amdgpu_gfx {
> >   	struct mutex			gpu_clock_mutex;
> >   	struct amdgpu_gfx_config	config;
> > @@ -970,6 +975,8 @@ struct amdgpu_gfx {
> >   	struct amdgpu_irq_src		priv_inst_irq;
> >   	struct amdgpu_irq_src		cp_ecc_error_irq;
> >   	struct amdgpu_irq_src		sq_irq;
> > +	struct sq_work			sq_work;
> > +
> >   	/* gfx status */
> >   	uint32_t			gfx_current_status;
> >   	/* ce ram size*/
> > diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> > b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> > index 93904a7..0add7fc 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
> > @@ -704,6 +704,17 @@ static const u32 stoney_mgcg_cgcg_init[] =
> >   	mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
> >   };
> >
> > +
> > +static const char * const sq_edc_source_names[] = {
> > +	"SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred",
> > +	"SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch",
> > +	"SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data
> return",
> > +	"SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR",
> > +	"SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS",
> > +	"SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS",
> > +	"SQ_EDC_INFO_SOURCE_TA: EDC source is TA", };
> > +
> >   static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev);
> >   static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev);
> >   static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev); @@
> > -2003,6 +2014,8 @@ static int gfx_v8_0_compute_ring_init(struct
> amdgpu_device *adev, int ring_id,
> >   	return 0;
> >   }
> >
> > +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work);
> > +
> >   static int gfx_v8_0_sw_init(void *handle)
> >   {
> >   	int i, j, k, r, ring_id;
> > @@ -2066,6 +2079,8 @@ static int gfx_v8_0_sw_init(void *handle)
> >   		return r;
> >   	}
> >
> > +	INIT_WORK(&adev->gfx.sq_work.work,
> gfx_v8_0_sq_irq_work_func);
> > +
> >   	adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
> >
> >   	gfx_v8_0_scratch_init(adev);
> > @@ -6952,14 +6967,11 @@ static int gfx_v8_0_cp_ecc_error_irq(struct
> amdgpu_device *adev,
> >   	return 0;
> >   }
> >
> > -static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
> > -			   struct amdgpu_irq_src *source,
> > -			   struct amdgpu_iv_entry *entry)
> > +static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev,
> > +unsigned ih_data)
> >   {
> > -	u8 enc, se_id;
> > +	u32 enc, se_id, sh_id, cu_id;
> >   	char type[20];
> > -	unsigned ih_data = entry->src_data[0];
> > -
> > +	int sq_edc_source = -1;
> >
> >   	enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN,
> ENCODING);
> >   	se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN,
> SE_ID); @@
> > -6985,6 +6997,24 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device
> *adev,
> >   		case 1:
> >   		case 2:
> >
> > +			cu_id = REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, CU_ID);
> > +			sh_id = REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, SH_ID);
> > +
> > +			/*
> > +			 * This function can be called either directly from ISR
> > +			 * or from BH in which case we can access
> SQ_EDC_INFO
> > +			 * instance
> > +			 */
> > +			if (in_task()) {
> > +				mutex_lock(&adev->grbm_idx_mutex);
> > +				gfx_v8_0_select_se_sh(adev, se_id, sh_id,
> cu_id);
> > +
> > +				sq_edc_source =
> REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO,
> > +SOURCE);
> > +
> > +				gfx_v8_0_select_se_sh(adev, 0xffffffff,
> 0xffffffff, 0xffffffff);
> > +				mutex_unlock(&adev->grbm_idx_mutex);
> > +			}
> > +
> >   			if (enc == 1)
> >   				sprintf(type, "instruction intr");
> >   			else
> > @@ -6992,20 +7022,61 @@ static int gfx_v8_0_sq_irq(struct
> > amdgpu_device *adev,
> >
> >   			DRM_INFO(
> >   				"SQ %s detected: "
> > -					"se_id %d, cu_id %d, simd_id %d,
> wave_id %d, vm_id %d\n"
> > -					"trap %s, sh_id %d. ",
> > -					type, se_id,
> > -					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, CU_ID),
> > +					"se_id %d, sh_id %d, cu_id %d,
> simd_id %d, wave_id %d, vm_id %d "
> > +					"trap %s, sq_ed_info.source %s.\n",
> > +					type, se_id, sh_id, cu_id,
> >   					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, SIMD_ID),
> >   					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, WAVE_ID),
> >   					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, VM_ID),
> >   					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false",
> > -					REG_GET_FIELD(ih_data,
> SQ_INTERRUPT_WORD_WAVE, SH_ID)
> > -					);
> > +					(sq_edc_source != -1) ?
> sq_edc_source_names[sq_edc_source] : "unavailable"
> > +				);
> >   			break;
> >   		default:
> >   			DRM_ERROR("SQ invalid encoding type\n.");
> > -			return -EINVAL;
> > +	}
> > +}
> > +
> > +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work) {
> > +
> > +	struct amdgpu_device *adev = container_of(work, struct
> amdgpu_device, gfx.sq_work.work);
> > +	struct sq_work *sq_work = container_of(work, struct sq_work,
> work);
> > +
> > +	smp_rmb();
> > +
> > +	gfx_v8_0_parse_sq_irq(adev, READ_ONCE(sq_work->ih_data));
> > +
> > +	WRITE_ONCE(sq_work->ih_data, 0);
> > +	/* Make the value change visible ASAP to IH */
> > +	smp_wmb();
> > +}
> > +
> > +static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
> > +			   struct amdgpu_irq_src *source,
> > +			   struct amdgpu_iv_entry *entry)
> > +{
> > +	unsigned ih_data = entry->src_data[0];
> > +
> > +	/*
> > +	 * Try to submit work so SQ_EDC_INFO can be accessed from
> > +	 * BH. If previous work submission hasn't finished yet
> > +	 * just print whatever info is possible directly from the ISR.
> > +	 */
> > +	smp_rmb();
> > +	if (READ_ONCE(adev->gfx.sq_work.ih_data))
> > +		gfx_v8_0_parse_sq_irq(adev, ih_data);
> > +	else {
> > +		WRITE_ONCE(adev->gfx.sq_work.ih_data, ih_data);
> > +		/* Verify the new value visible in BH handler */
> > +		smp_wmb();
> > +		if (!schedule_work(&adev->gfx.sq_work.work)) {
> > +
> > +			WRITE_ONCE(adev->gfx.sq_work.ih_data, 0);
> > +			gfx_v8_0_parse_sq_irq(adev, ih_data);
> > +			/* Verify 0 is visible to next HW IH */
> > +			smp_wmb();
> > +		}
> 
> At least of hand that looks like it is racy.
> 
> You should probably rather use work_pending() like this:
> 
> if (work_pending(&adev->gfx.sq_work.work)) {
>      gfx_v8_0_parse_sq_irq(adev, ih_data); } else {
>      adev->gfx.sq_work.ih_data = ih_data;
>      schedule_work(&adev->gfx.sq_work.work);
> }
> 
> Regards,
> Christian.

Agree that this way the code more compact and elegant but where is the race ?

Andrey

> 
> >   	}
> >
> >   	return 0;

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

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

end of thread, other threads:[~2018-06-20  9:42 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-19 16:09 [PATCH 1/2] drm/amdgpu: Polish SQ IH Andrey Grodzovsky
     [not found] ` <1529424573-21761-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-06-19 16:09   ` [PATCH 2/2] drm/amdgpu: Add parsing SQ_EDC_INFO to " Andrey Grodzovsky
     [not found]     ` <1529424573-21761-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-06-20  6:37       ` Christian König
     [not found]         ` <a32b1a8b-da3e-7da4-636f-c8699022961f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-06-20  9:42           ` Grodzovsky, Andrey

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.