Skip to content

Commit

Permalink
drm/radeon: use status regs to determine what to reset (cayman)
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 a65a436 commit 168757e
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 32 deletions.
6 changes: 5 additions & 1 deletion drivers/gpu/drm/radeon/evergreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -2349,9 +2349,13 @@ void evergreen_print_gpu_status_regs(struct radeon_device *rdev)
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));
}
}

static bool evergreen_is_display_hung(struct radeon_device *rdev)
bool evergreen_is_display_hung(struct radeon_device *rdev)
{
u32 crtc_hung = 0;
u32 crtc_status[6];
Expand Down
148 changes: 117 additions & 31 deletions drivers/gpu/drm/radeon/ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "ni_reg.h"
#include "cayman_blit_shaders.h"

extern bool evergreen_is_display_hung(struct radeon_device *rdev);
extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
Expand Down Expand Up @@ -1311,21 +1312,86 @@ void cayman_dma_fini(struct radeon_device *rdev)
radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
}

static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
static u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
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 |
GDS_BUSY | SPI_BUSY |
IA_BUSY | IA_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;

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

/* DMA_STATUS_REG 1 */
tmp = RREG32(DMA_STATUS_REG + DMA1_REGISTER_OFFSET);
if (!(tmp & DMA_IDLE))
reset_mask |= RADEON_RESET_DMA1;

/* SRBM_STATUS2 */
tmp = RREG32(SRBM_STATUS2);
if (tmp & DMA_BUSY)
reset_mask |= RADEON_RESET_DMA;

if (tmp & DMA1_BUSY)
reset_mask |= RADEON_RESET_DMA1;

/* 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 (RREG32(DMA_STATUS_REG) & DMA_IDLE)
reset_mask &= ~RADEON_RESET_DMA;
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 cayman_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);

Expand Down Expand Up @@ -1354,7 +1420,9 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
}

if (reset_mask & RADEON_RESET_DMA1) {
/* dma1 */
tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
Expand Down Expand Up @@ -1383,7 +1451,31 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
}

if (reset_mask & RADEON_RESET_DMA)
srbm_soft_reset |= SOFT_RESET_DMA | SOFT_RESET_DMA1;
srbm_soft_reset |= SOFT_RESET_DMA;

if (reset_mask & RADEON_RESET_DMA1)
srbm_soft_reset |= SOFT_RESET_DMA1;

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);
Expand Down Expand Up @@ -1419,32 +1511,26 @@ static int cayman_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 cayman_asic_reset(struct radeon_device *rdev)
{
return cayman_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
RADEON_RESET_COMPUTE |
RADEON_RESET_DMA |
RADEON_RESET_CP));
u32 reset_mask;

reset_mask = cayman_gpu_check_soft_reset(rdev);

if (reset_mask)
r600_set_bios_scratch_engine_hung(rdev, true);

cayman_gpu_soft_reset(rdev, reset_mask);

reset_mask = cayman_gpu_check_soft_reset(rdev);

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

return 0;
}

/**
Expand Down
14 changes: 14 additions & 0 deletions drivers/gpu/drm/radeon/nid.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@
#define RINGID(x) (((x) & 0x3) << 0)
#define VMID(x) (((x) & 0x7) << 0)
#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_SOFT_RESET 0x0E60
#define SOFT_RESET_BIF (1 << 1)
Expand All @@ -68,6 +78,10 @@
#define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23)

#define SRBM_STATUS2 0x0EC4
#define DMA_BUSY (1 << 5)
#define DMA1_BUSY (1 << 6)

#define VM_CONTEXT0_REQUEST_RESPONSE 0x1470
#define REQUEST_TYPE(x) (((x) & 0xf) << 0)
#define RESPONSE_TYPE_MASK 0x000000F0
Expand Down

0 comments on commit 168757e

Please sign in to comment.