Skip to content

Commit

Permalink
drm/radeon: use status regs to determine what to reset (evergreen)
Browse files Browse the repository at this point in the history
When we attempt the reset the GPU, look at the status registers
to determine what blocks need to be reset.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Alex Deucher committed Jan 31, 2013
1 parent f13f773 commit a65a436
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 32 deletions.
164 changes: 132 additions & 32 deletions drivers/gpu/drm/radeon/evergreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -2337,6 +2337,8 @@ void evergreen_print_gpu_status_regs(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",
Expand All @@ -2349,28 +2351,111 @@ void evergreen_print_gpu_status_regs(struct radeon_device *rdev)
RREG32(DMA_STATUS_REG));
}

static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
static bool evergreen_is_display_hung(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
u32 crtc_hung = 0;
u32 crtc_status[6];
u32 i, j, tmp;

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);
}
}

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 u32 evergreen_gpu_check_soft_reset(struct radeon_device *rdev)
{
u32 reset_mask = 0;
u32 tmp;
int ret = 0;

if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP);
/* 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;

if (tmp & (CF_RQ_PENDING | PF_RQ_PENDING |
CP_BUSY | CP_COHERENCY_BUSY))
reset_mask |= RADEON_RESET_CP;

if (tmp & GRBM_EE_BUSY)
reset_mask |= RADEON_RESET_GRBM | RADEON_RESET_GFX | RADEON_RESET_CP;

if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
reset_mask &= ~RADEON_RESET_DMA;
/* DMA_STATUS_REG */
tmp = RREG32(DMA_STATUS_REG);
if (!(tmp & DMA_IDLE))
reset_mask |= RADEON_RESET_DMA;

/* 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 void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
{
struct evergreen_mc_save save;
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);

r600_set_bios_scratch_engine_hung(rdev, true);

evergreen_mc_stop(rdev, &save);
if (evergreen_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
Expand Down Expand Up @@ -2410,6 +2495,27 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
if (reset_mask & RADEON_RESET_DMA)
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 (reset_mask & RADEON_RESET_MC)
srbm_soft_reset |= SOFT_RESET_MC;

if (grbm_soft_reset) {
tmp = RREG32(GRBM_SOFT_RESET);
tmp |= grbm_soft_reset;
Expand Down Expand Up @@ -2444,32 +2550,26 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
evergreen_mc_resume(rdev, &save);
udelay(50);

#if 0
if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP)) {
if (RREG32(GRBM_STATUS) & GUI_ACTIVE)
ret = -EAGAIN;
}

if (reset_mask & RADEON_RESET_DMA) {
if (!(RREG32(DMA_STATUS_REG) & DMA_IDLE))
ret = -EAGAIN;
}
#endif

if (!ret)
r600_set_bios_scratch_engine_hung(rdev, false);

evergreen_print_gpu_status_regs(rdev);

return 0;
}

int evergreen_asic_reset(struct radeon_device *rdev)
{
return evergreen_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
RADEON_RESET_COMPUTE |
RADEON_RESET_DMA |
RADEON_RESET_CP));
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;
}

/* Interrupts */
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/evergreen_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
#define EVERGREEN_CRTC_STATUS 0x6e8c
# define EVERGREEN_CRTC_V_BLANK (1 << 0)
#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90
#define EVERGREEN_CRTC_STATUS_HV_COUNT 0x6ea0
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4

Expand Down
12 changes: 12 additions & 0 deletions drivers/gpu/drm/radeon/evergreend.h
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,18 @@
#define WAIT_UNTIL 0x8040

#define SRBM_STATUS 0x0E50
#define RLC_RQ_PENDING (1 << 3)
#define GRBM_RQ_PENDING (1 << 5)
#define VMC_BUSY (1 << 8)
#define MCB_BUSY (1 << 9)
#define MCB_NON_DISPLAY_BUSY (1 << 10)
#define MCC_BUSY (1 << 11)
#define MCD_BUSY (1 << 12)
#define SEM_BUSY (1 << 14)
#define RLC_BUSY (1 << 15)
#define IH_BUSY (1 << 17)
#define SRBM_STATUS2 0x0EC4
#define DMA_BUSY (1 << 5)
#define SRBM_SOFT_RESET 0x0E60
#define SRBM_SOFT_RESET_ALL_MASK 0x00FEEFA6
#define SOFT_RESET_BIF (1 << 1)
Expand Down

0 comments on commit a65a436

Please sign in to comment.