diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/4751-drm-amdgpu-Add-parsing-SQ_EDC_INFO-to-SQ-IH-v3.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/4751-drm-amdgpu-Add-parsing-SQ_EDC_INFO-to-SQ-IH-v3.patch | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/4751-drm-amdgpu-Add-parsing-SQ_EDC_INFO-to-SQ-IH-v3.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/4751-drm-amdgpu-Add-parsing-SQ_EDC_INFO-to-SQ-IH-v3.patch new file mode 100644 index 00000000..d437cc68 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/4751-drm-amdgpu-Add-parsing-SQ_EDC_INFO-to-SQ-IH-v3.patch @@ -0,0 +1,199 @@ +From 8bbabd0adfc498df205067032efc08d91df6305b Mon Sep 17 00:00:00 2001 +From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> +Date: Tue, 19 Jun 2018 10:27:53 -0400 +Subject: [PATCH 4751/5725] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH v3. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +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 rest 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. + +v2: +Simplify high IRQ and BH handlers synchronization using work_pending. +Remove {READ,WRITE}_ONCE notations since smp_{r,w}mb are implicit +compiler barriers. + +v3: +Remove exlicit memory barriers as scedule_work has r/w barriers. + +Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> +Acked-by: Christian König <christian.koenig@amd.com> +Acked-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 7 +++ + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 82 +++++++++++++++++++++++++++++------ + 2 files changed, 76 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index c55e675..3b456ce 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -951,6 +951,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; +@@ -991,6 +996,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 ad28dd9..294fa59 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); +@@ -2005,6 +2016,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; +@@ -2068,6 +2081,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); +@@ -6967,14 +6982,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); +@@ -7000,6 +7012,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 +@@ -7007,20 +7037,46 @@ 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); ++ ++ gfx_v8_0_parse_sq_irq(adev, sq_work->ih_data); ++} ++ ++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. ++ */ ++ 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); + } + + return 0; +-- +2.7.4 + |