diff options
author | Dave Airlie <airlied@redhat.com> | 2018-07-10 10:57:02 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-07-10 10:57:08 +1000 |
commit | ba7ca97d73b437eec883eba785495b8c9759b5f2 (patch) | |
tree | 1fa28063ba726d21af566796751805a3a4db21cc /drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | |
parent | 61a3a9d6c9c9a017decadb56669b66066612d728 (diff) | |
parent | 43911fb68b19f7c37ab69eff8e6a3c1370bc0cb5 (diff) |
Merge branch 'drm-next-4.19' of git://people.freedesktop.org/~agd5f/linux into drm-next
More features for 4.19:
- Use core pcie functionality rather than duplicating our own for pcie
gens and lanes
- Scheduler function naming cleanups
- More documentation
- Reworked DC/Powerplay interfaces to improve power savings
- Initial stutter mode support for RV (power feature)
- Vega12 powerplay updates
- GFXOFF fixes
- Misc fixes
Signed-off-by: Dave Airlie <airlied@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180705221447.2807-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 120 |
1 files changed, 87 insertions, 33 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 807ee0dd623ce..551f21bad6d38 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); @@ -2006,6 +2017,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; @@ -2069,6 +2082,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); @@ -5581,24 +5596,18 @@ static int gfx_v8_0_late_init(void *handle) return r; } - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); - return 0; } static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, bool enable) { - if ((adev->asic_type == CHIP_POLARIS11) || + if (((adev->asic_type == CHIP_POLARIS11) || (adev->asic_type == CHIP_POLARIS12) || - (adev->asic_type == CHIP_VEGAM)) + (adev->asic_type == CHIP_VEGAM)) && + adev->powerplay.pp_funcs->set_powergating_by_smu) /* Send msg to SMU via Powerplay */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - enable ? - AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable); WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0); } @@ -6955,16 +6964,14 @@ 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]; + int sq_edc_source = -1; - /* 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: @@ -6974,19 +6981,37 @@ 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: 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 @@ -6994,17 +7019,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", - 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 - ); + "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", + (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; |