diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 82 |
1 files changed, 69 insertions, 13 deletions
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 | |||
708 | static 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 | |||
707 | static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev); | 718 | static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev); |
708 | static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev); | 719 | static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev); |
709 | static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev); | 720 | static 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 | ||
2020 | static void gfx_v8_0_sq_irq_work_func(struct work_struct *work); | ||
2021 | |||
2009 | static int gfx_v8_0_sw_init(void *handle) | 2022 | static 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 | ||
6958 | static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, | 6973 | static 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 | |||
7043 | static 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 | |||
7052 | static 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; |