aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Grodzovsky <andrey.grodzovsky@amd.com>2018-06-19 10:27:53 -0400
committerAlex Deucher <alexander.deucher@amd.com>2018-07-05 17:38:26 -0400
commit9bdc2092b488bc81aa5409b4d6fc931c5bea1094 (patch)
tree64eac39b78749bf2e5da4680cb9bd2163eadffb1
parentd9e222b460b195a47b30fd9057fbb131fcbd7bac (diff)
drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH v3.
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>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c82
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 71b9b861f60e..fb17838114c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -930,6 +930,11 @@ struct amdgpu_ngg {
930 bool init; 930 bool init;
931}; 931};
932 932
933struct sq_work {
934 struct work_struct work;
935 unsigned ih_data;
936};
937
933struct amdgpu_gfx { 938struct amdgpu_gfx {
934 struct mutex gpu_clock_mutex; 939 struct mutex gpu_clock_mutex;
935 struct amdgpu_gfx_config config; 940 struct amdgpu_gfx_config config;
@@ -970,6 +975,8 @@ struct amdgpu_gfx {
970 struct amdgpu_irq_src priv_inst_irq; 975 struct amdgpu_irq_src priv_inst_irq;
971 struct amdgpu_irq_src cp_ecc_error_irq; 976 struct amdgpu_irq_src cp_ecc_error_irq;
972 struct amdgpu_irq_src sq_irq; 977 struct amdgpu_irq_src sq_irq;
978 struct sq_work sq_work;
979
973 /* gfx status */ 980 /* gfx status */
974 uint32_t gfx_current_status; 981 uint32_t gfx_current_status;
975 /* ce ram size*/ 982 /* 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 1d99a4205958..4201f3dfaece 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[] =
704 mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200, 704 mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
705}; 705};
706 706
707
708static const char * const sq_edc_source_names[] = {
709 "SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred",
710 "SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch",
711 "SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data return",
712 "SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR",
713 "SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS",
714 "SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS",
715 "SQ_EDC_INFO_SOURCE_TA: EDC source is TA",
716};
717
707static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev); 718static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev);
708static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev); 719static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev);
709static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev); 720static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev);
@@ -2006,6 +2017,8 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id,
2006 return 0; 2017 return 0;
2007} 2018}
2008 2019
2020static void gfx_v8_0_sq_irq_work_func(struct work_struct *work);
2021
2009static int gfx_v8_0_sw_init(void *handle) 2022static int gfx_v8_0_sw_init(void *handle)
2010{ 2023{
2011 int i, j, k, r, ring_id; 2024 int i, j, k, r, ring_id;
@@ -2069,6 +2082,8 @@ static int gfx_v8_0_sw_init(void *handle)
2069 return r; 2082 return r;
2070 } 2083 }
2071 2084
2085 INIT_WORK(&adev->gfx.sq_work.work, gfx_v8_0_sq_irq_work_func);
2086
2072 adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; 2087 adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
2073 2088
2074 gfx_v8_0_scratch_init(adev); 2089 gfx_v8_0_scratch_init(adev);
@@ -6955,14 +6970,11 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev,
6955 return 0; 6970 return 0;
6956} 6971}
6957 6972
6958static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, 6973static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev, unsigned ih_data)
6959 struct amdgpu_irq_src *source,
6960 struct amdgpu_iv_entry *entry)
6961{ 6974{
6962 u8 enc, se_id; 6975 u32 enc, se_id, sh_id, cu_id;
6963 char type[20]; 6976 char type[20];
6964 unsigned ih_data = entry->src_data[0]; 6977 int sq_edc_source = -1;
6965
6966 6978
6967 enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING); 6979 enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING);
6968 se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID); 6980 se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID);
@@ -6988,6 +7000,24 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
6988 case 1: 7000 case 1:
6989 case 2: 7001 case 2:
6990 7002
7003 cu_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID);
7004 sh_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID);
7005
7006 /*
7007 * This function can be called either directly from ISR
7008 * or from BH in which case we can access SQ_EDC_INFO
7009 * instance
7010 */
7011 if (in_task()) {
7012 mutex_lock(&adev->grbm_idx_mutex);
7013 gfx_v8_0_select_se_sh(adev, se_id, sh_id, cu_id);
7014
7015 sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE);
7016
7017 gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
7018 mutex_unlock(&adev->grbm_idx_mutex);
7019 }
7020
6991 if (enc == 1) 7021 if (enc == 1)
6992 sprintf(type, "instruction intr"); 7022 sprintf(type, "instruction intr");
6993 else 7023 else
@@ -6995,20 +7025,46 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
6995 7025
6996 DRM_INFO( 7026 DRM_INFO(
6997 "SQ %s detected: " 7027 "SQ %s detected: "
6998 "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n" 7028 "se_id %d, sh_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d "
6999 "trap %s, sh_id %d. ", 7029 "trap %s, sq_ed_info.source %s.\n",
7000 type, se_id, 7030 type, se_id, sh_id, cu_id,
7001 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID),
7002 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID), 7031 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID),
7003 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID), 7032 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID),
7004 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID), 7033 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID),
7005 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false", 7034 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false",
7006 REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID) 7035 (sq_edc_source != -1) ? sq_edc_source_names[sq_edc_source] : "unavailable"
7007 ); 7036 );
7008 break; 7037 break;
7009 default: 7038 default:
7010 DRM_ERROR("SQ invalid encoding type\n."); 7039 DRM_ERROR("SQ invalid encoding type\n.");
7011 return -EINVAL; 7040 }
7041}
7042
7043static void gfx_v8_0_sq_irq_work_func(struct work_struct *work)
7044{
7045
7046 struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.sq_work.work);
7047 struct sq_work *sq_work = container_of(work, struct sq_work, work);
7048
7049 gfx_v8_0_parse_sq_irq(adev, sq_work->ih_data);
7050}
7051
7052static int gfx_v8_0_sq_irq(struct amdgpu_device *adev,
7053 struct amdgpu_irq_src *source,
7054 struct amdgpu_iv_entry *entry)
7055{
7056 unsigned ih_data = entry->src_data[0];
7057
7058 /*
7059 * Try to submit work so SQ_EDC_INFO can be accessed from
7060 * BH. If previous work submission hasn't finished yet
7061 * just print whatever info is possible directly from the ISR.
7062 */
7063 if (work_pending(&adev->gfx.sq_work.work)) {
7064 gfx_v8_0_parse_sq_irq(adev, ih_data);
7065 } else {
7066 adev->gfx.sq_work.ih_data = ih_data;
7067 schedule_work(&adev->gfx.sq_work.work);
7012 } 7068 }
7013 7069
7014 return 0; 7070 return 0;