diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/evergreen.c')
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen.c | 366 |
1 files changed, 264 insertions, 102 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index a2d478e8692a..3c38ea46531c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -403,6 +403,19 @@ void evergreen_pm_misc(struct radeon_device *rdev) rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage); } + + /* starting with BTC, there is one state that is used for both + * MH and SH. Difference is that we always use the high clock index for + * mclk and vddci. + */ + if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && + (rdev->family >= CHIP_BARTS) && + rdev->pm.active_crtc_count && + ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || + (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) + voltage = &rdev->pm.power_state[req_ps_idx]. + clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage; + /* 0xff01 is a flag rather then an actual voltage */ if (voltage->vddci == 0xff01) return; @@ -2308,32 +2321,8 @@ int evergreen_mc_init(struct radeon_device *rdev) return 0; } -bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) +void evergreen_print_gpu_status_regs(struct radeon_device *rdev) { - u32 srbm_status; - u32 grbm_status; - u32 grbm_status_se0, grbm_status_se1; - - srbm_status = RREG32(SRBM_STATUS); - grbm_status = RREG32(GRBM_STATUS); - grbm_status_se0 = RREG32(GRBM_STATUS_SE0); - grbm_status_se1 = RREG32(GRBM_STATUS_SE1); - if (!(grbm_status & GUI_ACTIVE)) { - radeon_ring_lockup_update(ring); - return false; - } - /* force CP activities */ - radeon_ring_force_activity(rdev, ring); - return radeon_ring_test_lockup(rdev, ring); -} - -static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev) -{ - u32 grbm_reset = 0; - - if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - return; - dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", RREG32(GRBM_STATUS)); dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", @@ -2342,6 +2331,8 @@ static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev) RREG32(GRBM_STATUS_SE1)); dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", RREG32(SRBM_STATUS)); + dev_info(rdev->dev, " SRBM_STATUS2 = 0x%08X\n", + RREG32(SRBM_STATUS2)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); dev_info(rdev->dev, " R_008678_CP_STALLED_STAT2 = 0x%08X\n", @@ -2350,112 +2341,283 @@ static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + if (rdev->family >= CHIP_CAYMAN) { + dev_info(rdev->dev, " R_00D834_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG + 0x800)); + } +} - /* Disable CP parsing/prefetching */ - WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); +bool evergreen_is_display_hung(struct radeon_device *rdev) +{ + u32 crtc_hung = 0; + u32 crtc_status[6]; + u32 i, j, tmp; - /* reset all the gfx blocks */ - grbm_reset = (SOFT_RESET_CP | - SOFT_RESET_CB | - SOFT_RESET_DB | - SOFT_RESET_PA | - SOFT_RESET_SC | - SOFT_RESET_SPI | - SOFT_RESET_SH | - SOFT_RESET_SX | - SOFT_RESET_TC | - SOFT_RESET_TA | - SOFT_RESET_VC | - SOFT_RESET_VGT); - - dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset); - WREG32(GRBM_SOFT_RESET, grbm_reset); - (void)RREG32(GRBM_SOFT_RESET); - udelay(50); - WREG32(GRBM_SOFT_RESET, 0); - (void)RREG32(GRBM_SOFT_RESET); + for (i = 0; i < rdev->num_crtc; i++) { + if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN) { + crtc_status[i] = RREG32(EVERGREEN_CRTC_STATUS_HV_COUNT + crtc_offsets[i]); + crtc_hung |= (1 << i); + } + } - dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", - RREG32(GRBM_STATUS)); - dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", - RREG32(GRBM_STATUS_SE0)); - dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n", - RREG32(GRBM_STATUS_SE1)); - dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", - RREG32(SRBM_STATUS)); - dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", - RREG32(CP_STALLED_STAT1)); - dev_info(rdev->dev, " R_008678_CP_STALLED_STAT2 = 0x%08X\n", - RREG32(CP_STALLED_STAT2)); - dev_info(rdev->dev, " R_00867C_CP_BUSY_STAT = 0x%08X\n", - RREG32(CP_BUSY_STAT)); - dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", - RREG32(CP_STAT)); + for (j = 0; j < 10; j++) { + for (i = 0; i < rdev->num_crtc; i++) { + if (crtc_hung & (1 << i)) { + tmp = RREG32(EVERGREEN_CRTC_STATUS_HV_COUNT + crtc_offsets[i]); + if (tmp != crtc_status[i]) + crtc_hung &= ~(1 << i); + } + } + if (crtc_hung == 0) + return false; + udelay(100); + } + + return true; } -static void evergreen_gpu_soft_reset_dma(struct radeon_device *rdev) +static u32 evergreen_gpu_check_soft_reset(struct radeon_device *rdev) { + u32 reset_mask = 0; u32 tmp; - if (RREG32(DMA_STATUS_REG) & DMA_IDLE) - return; + /* GRBM_STATUS */ + tmp = RREG32(GRBM_STATUS); + if (tmp & (PA_BUSY | SC_BUSY | + SH_BUSY | SX_BUSY | + TA_BUSY | VGT_BUSY | + DB_BUSY | CB_BUSY | + SPI_BUSY | VGT_BUSY_NO_DMA)) + reset_mask |= RADEON_RESET_GFX; - dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", - RREG32(DMA_STATUS_REG)); + if (tmp & (CF_RQ_PENDING | PF_RQ_PENDING | + CP_BUSY | CP_COHERENCY_BUSY)) + reset_mask |= RADEON_RESET_CP; - /* Disable DMA */ - tmp = RREG32(DMA_RB_CNTL); - tmp &= ~DMA_RB_ENABLE; - WREG32(DMA_RB_CNTL, tmp); + if (tmp & GRBM_EE_BUSY) + reset_mask |= RADEON_RESET_GRBM | RADEON_RESET_GFX | RADEON_RESET_CP; - /* Reset dma */ - WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); - RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); + /* DMA_STATUS_REG */ + tmp = RREG32(DMA_STATUS_REG); + if (!(tmp & DMA_IDLE)) + reset_mask |= RADEON_RESET_DMA; - dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", - RREG32(DMA_STATUS_REG)); + /* SRBM_STATUS2 */ + tmp = RREG32(SRBM_STATUS2); + if (tmp & DMA_BUSY) + reset_mask |= RADEON_RESET_DMA; + + /* SRBM_STATUS */ + tmp = RREG32(SRBM_STATUS); + if (tmp & (RLC_RQ_PENDING | RLC_BUSY)) + reset_mask |= RADEON_RESET_RLC; + + if (tmp & IH_BUSY) + reset_mask |= RADEON_RESET_IH; + + if (tmp & SEM_BUSY) + reset_mask |= RADEON_RESET_SEM; + + if (tmp & GRBM_RQ_PENDING) + reset_mask |= RADEON_RESET_GRBM; + + if (tmp & VMC_BUSY) + reset_mask |= RADEON_RESET_VMC; + + if (tmp & (MCB_BUSY | MCB_NON_DISPLAY_BUSY | + MCC_BUSY | MCD_BUSY)) + reset_mask |= RADEON_RESET_MC; + + if (evergreen_is_display_hung(rdev)) + reset_mask |= RADEON_RESET_DISPLAY; + + /* VM_L2_STATUS */ + tmp = RREG32(VM_L2_STATUS); + if (tmp & L2_BUSY) + reset_mask |= RADEON_RESET_VMC; + + return reset_mask; } -static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) +static void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) { struct evergreen_mc_save save; - - if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); - - if (RREG32(DMA_STATUS_REG) & DMA_IDLE) - reset_mask &= ~RADEON_RESET_DMA; + u32 grbm_soft_reset = 0, srbm_soft_reset = 0; + u32 tmp; if (reset_mask == 0) - return 0; + return; dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); + evergreen_print_gpu_status_regs(rdev); + + /* Disable CP parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); + + if (reset_mask & RADEON_RESET_DMA) { + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + } + + udelay(50); + evergreen_mc_stop(rdev, &save); if (evergreen_mc_wait_for_idle(rdev)) { dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); } - if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) - evergreen_gpu_soft_reset_gfx(rdev); + if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) { + grbm_soft_reset |= SOFT_RESET_DB | + SOFT_RESET_CB | + SOFT_RESET_PA | + SOFT_RESET_SC | + SOFT_RESET_SPI | + SOFT_RESET_SX | + SOFT_RESET_SH | + SOFT_RESET_TC | + SOFT_RESET_TA | + SOFT_RESET_VC | + SOFT_RESET_VGT; + } + + if (reset_mask & RADEON_RESET_CP) { + grbm_soft_reset |= SOFT_RESET_CP | + SOFT_RESET_VGT; + + srbm_soft_reset |= SOFT_RESET_GRBM; + } if (reset_mask & RADEON_RESET_DMA) - evergreen_gpu_soft_reset_dma(rdev); + srbm_soft_reset |= SOFT_RESET_DMA; + + if (reset_mask & RADEON_RESET_DISPLAY) + srbm_soft_reset |= SOFT_RESET_DC; + + if (reset_mask & RADEON_RESET_RLC) + srbm_soft_reset |= SOFT_RESET_RLC; + + if (reset_mask & RADEON_RESET_SEM) + srbm_soft_reset |= SOFT_RESET_SEM; + + if (reset_mask & RADEON_RESET_IH) + srbm_soft_reset |= SOFT_RESET_IH; + + if (reset_mask & RADEON_RESET_GRBM) + srbm_soft_reset |= SOFT_RESET_GRBM; + + if (reset_mask & RADEON_RESET_VMC) + srbm_soft_reset |= SOFT_RESET_VMC; + + if (!(rdev->flags & RADEON_IS_IGP)) { + if (reset_mask & RADEON_RESET_MC) + srbm_soft_reset |= SOFT_RESET_MC; + } + + if (grbm_soft_reset) { + tmp = RREG32(GRBM_SOFT_RESET); + tmp |= grbm_soft_reset; + dev_info(rdev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); + WREG32(GRBM_SOFT_RESET, tmp); + tmp = RREG32(GRBM_SOFT_RESET); + + udelay(50); + + tmp &= ~grbm_soft_reset; + WREG32(GRBM_SOFT_RESET, tmp); + tmp = RREG32(GRBM_SOFT_RESET); + } + + if (srbm_soft_reset) { + tmp = RREG32(SRBM_SOFT_RESET); + tmp |= srbm_soft_reset; + dev_info(rdev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); + WREG32(SRBM_SOFT_RESET, tmp); + tmp = RREG32(SRBM_SOFT_RESET); + + udelay(50); + + tmp &= ~srbm_soft_reset; + WREG32(SRBM_SOFT_RESET, tmp); + tmp = RREG32(SRBM_SOFT_RESET); + } /* Wait a little for things to settle down */ udelay(50); evergreen_mc_resume(rdev, &save); - return 0; + udelay(50); + + evergreen_print_gpu_status_regs(rdev); } int evergreen_asic_reset(struct radeon_device *rdev) { - return evergreen_gpu_soft_reset(rdev, (RADEON_RESET_GFX | - RADEON_RESET_COMPUTE | - RADEON_RESET_DMA)); + u32 reset_mask; + + reset_mask = evergreen_gpu_check_soft_reset(rdev); + + if (reset_mask) + r600_set_bios_scratch_engine_hung(rdev, true); + + evergreen_gpu_soft_reset(rdev, reset_mask); + + reset_mask = evergreen_gpu_check_soft_reset(rdev); + + if (!reset_mask) + r600_set_bios_scratch_engine_hung(rdev, false); + + return 0; +} + +/** + * evergreen_gfx_is_lockup - Check if the GFX engine is locked up + * + * @rdev: radeon_device pointer + * @ring: radeon_ring structure holding ring information + * + * Check if the GFX engine is locked up. + * Returns true if the engine appears to be locked up, false if not. + */ +bool evergreen_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) +{ + u32 reset_mask = evergreen_gpu_check_soft_reset(rdev); + + if (!(reset_mask & (RADEON_RESET_GFX | + RADEON_RESET_COMPUTE | + RADEON_RESET_CP))) { + radeon_ring_lockup_update(ring); + return false; + } + /* force CP activities */ + radeon_ring_force_activity(rdev, ring); + return radeon_ring_test_lockup(rdev, ring); +} + +/** + * evergreen_dma_is_lockup - Check if the DMA engine is locked up + * + * @rdev: radeon_device pointer + * @ring: radeon_ring structure holding ring information + * + * Check if the async DMA engine is locked up. + * Returns true if the engine appears to be locked up, false if not. + */ +bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) +{ + u32 reset_mask = evergreen_gpu_check_soft_reset(rdev); + + if (!(reset_mask & RADEON_RESET_DMA)) { + radeon_ring_lockup_update(ring); + return false; + } + /* force ring activities */ + radeon_ring_force_activity(rdev, ring); + return radeon_ring_test_lockup(rdev, ring); } /* Interrupts */ @@ -3280,14 +3442,14 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[fence->ring]; u64 addr = rdev->fence_drv[fence->ring].gpu_addr; /* write the fence */ - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0)); radeon_ring_write(ring, addr & 0xfffffffc); radeon_ring_write(ring, (upper_32_bits(addr) & 0xff)); radeon_ring_write(ring, fence->seq); /* generate an interrupt */ - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0)); /* flush HDP */ - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); radeon_ring_write(ring, 1); } @@ -3310,7 +3472,7 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, while ((next_rptr & 7) != 5) next_rptr++; next_rptr += 3; - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 1)); radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc); radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff); radeon_ring_write(ring, next_rptr); @@ -3320,8 +3482,8 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, * Pad as necessary with NOPs. */ while ((ring->wptr & 7) != 5) - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0, 0)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0)); radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); @@ -3380,7 +3542,7 @@ int evergreen_copy_dma(struct radeon_device *rdev, if (cur_size_in_dw > 0xFFFFF) cur_size_in_dw = 0xFFFFF; size_in_dw -= cur_size_in_dw; - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, cur_size_in_dw)); radeon_ring_write(ring, dst_offset & 0xfffffffc); radeon_ring_write(ring, src_offset & 0xfffffffc); radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff); @@ -3488,7 +3650,7 @@ static int evergreen_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, DMA_RB_RPTR, DMA_RB_WPTR, - 2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); + 2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); if (r) return r; |