Skip to content

Commit

Permalink
drm/radeon/kms: simplify & improve GPU reset V2
Browse files Browse the repository at this point in the history
This simplify and improve GPU reset for R1XX-R6XX hw, it's
not 100% reliable here are result:
- R1XX/R2XX works bunch of time in a row, sometimes it
  seems it can work indifinitly
- R3XX/R3XX the most unreliable one, sometimes you will be
  able to reset few times, sometimes not even once
- R5XX more reliable than previous hw, seems to work most
  of the times but once in a while it fails for no obvious
  reasons (same status than previous reset just no same
  happy ending)
- R6XX/R7XX are lot more reliable with this patch, still
  it seems that it can fail after a bunch (reset every
  2sec for 3hour bring down the GPU & computer)

This have been tested on various hw, for some odd reasons
i wasn't able to lockup RS480/RS690 (while they use to
love locking up).

Note that on R1XX-R5XX the cursor will disapear after
lockup haven't checked why, switch to console and back
to X will restore cursor.

Next step is to record the bogus command that leaded to
the lockup.

V2 Fix r6xx resume path to avoid reinitializing blit
module, use the gpu_lockup boolean to avoid entering
inifinite waiting loop on fence while reiniting the GPU

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Jerome Glisse authored and Dave Airlie committed Apr 6, 2010
1 parent a2d07b7 commit 90aca4d
Show file tree
Hide file tree
Showing 20 changed files with 508 additions and 354 deletions.
180 changes: 64 additions & 116 deletions drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,26 +662,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
if (r100_debugfs_cp_init(rdev)) {
DRM_ERROR("Failed to register debugfs file for CP !\n");
}
/* Reset CP */
tmp = RREG32(RADEON_CP_CSQ_STAT);
if ((tmp & (1 << 31))) {
DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp);
WREG32(RADEON_CP_CSQ_MODE, 0);
WREG32(RADEON_CP_CSQ_CNTL, 0);
WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
tmp = RREG32(RADEON_RBBM_SOFT_RESET);
mdelay(2);
WREG32(RADEON_RBBM_SOFT_RESET, 0);
tmp = RREG32(RADEON_RBBM_SOFT_RESET);
mdelay(2);
tmp = RREG32(RADEON_CP_CSQ_STAT);
if ((tmp & (1 << 31))) {
DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp);
}
} else {
DRM_INFO("radeon: cp idle (0x%08X)\n", tmp);
}

if (!rdev->me_fw) {
r = r100_cp_init_microcode(rdev);
if (r) {
Expand Down Expand Up @@ -786,39 +766,6 @@ void r100_cp_disable(struct radeon_device *rdev)
}
}

int r100_cp_reset(struct radeon_device *rdev)
{
uint32_t tmp;
bool reinit_cp;
int i;

reinit_cp = rdev->cp.ready;
rdev->cp.ready = false;
WREG32(RADEON_CP_CSQ_MODE, 0);
WREG32(RADEON_CP_CSQ_CNTL, 0);
WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
(void)RREG32(RADEON_RBBM_SOFT_RESET);
udelay(200);
WREG32(RADEON_RBBM_SOFT_RESET, 0);
/* Wait to prevent race in RBBM_STATUS */
mdelay(1);
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = RREG32(RADEON_RBBM_STATUS);
if (!(tmp & (1 << 16))) {
DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n",
tmp);
if (reinit_cp) {
return r100_cp_init(rdev, rdev->cp.ring_size);
}
return 0;
}
DRM_UDELAY(1);
}
tmp = RREG32(RADEON_RBBM_STATUS);
DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp);
return -1;
}

void r100_cp_commit(struct radeon_device *rdev)
{
WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
Expand Down Expand Up @@ -1732,51 +1679,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)
return -1;
}

void r100_gpu_init(struct radeon_device *rdev)
{
/* TODO: anythings to do here ? pipes ? */
r100_hdp_reset(rdev);
}

void r100_hdp_reset(struct radeon_device *rdev)
{
uint32_t tmp;

tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
tmp |= (7 << 28);
WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
(void)RREG32(RADEON_HOST_PATH_CNTL);
udelay(200);
WREG32(RADEON_RBBM_SOFT_RESET, 0);
WREG32(RADEON_HOST_PATH_CNTL, tmp);
(void)RREG32(RADEON_HOST_PATH_CNTL);
}

int r100_rb2d_reset(struct radeon_device *rdev)
{
uint32_t tmp;
int i;

WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2);
(void)RREG32(RADEON_RBBM_SOFT_RESET);
udelay(200);
WREG32(RADEON_RBBM_SOFT_RESET, 0);
/* Wait to prevent race in RBBM_STATUS */
mdelay(1);
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = RREG32(RADEON_RBBM_STATUS);
if (!(tmp & (1 << 26))) {
DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n",
tmp);
return 0;
}
DRM_UDELAY(1);
}
tmp = RREG32(RADEON_RBBM_STATUS);
DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp);
return -1;
}

void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp)
{
lockup->last_cp_rptr = cp->rptr;
Expand Down Expand Up @@ -1863,31 +1765,77 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev)
return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp);
}

void r100_bm_disable(struct radeon_device *rdev)
{
u32 tmp;

/* disable bus mastering */
tmp = RREG32(R_000030_BUS_CNTL);
WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044);
mdelay(1);
WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042);
mdelay(1);
WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
tmp = RREG32(RADEON_BUS_CNTL);
mdelay(1);
pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp);
pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
mdelay(1);
}

int r100_asic_reset(struct radeon_device *rdev)
{
uint32_t status;
struct r100_mc_save save;
u32 status, tmp;

/* reset order likely matter */
status = RREG32(RADEON_RBBM_STATUS);
/* reset HDP */
r100_hdp_reset(rdev);
/* reset rb2d */
if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
r100_rb2d_reset(rdev);
r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
/* TODO: reset 3D engine */
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
WREG32(RADEON_CP_CSQ_CNTL, 0);
tmp = RREG32(RADEON_CP_RB_CNTL);
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
WREG32(RADEON_CP_RB_RPTR_WR, 0);
WREG32(RADEON_CP_RB_WPTR, 0);
WREG32(RADEON_CP_RB_CNTL, tmp);
/* save PCI state */
pci_save_state(rdev->pdev);
/* disable bus mastering */
r100_bm_disable(rdev);
WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) |
S_0000F0_SOFT_RESET_RE(1) |
S_0000F0_SOFT_RESET_PP(1) |
S_0000F0_SOFT_RESET_RB(1));
RREG32(R_0000F0_RBBM_SOFT_RESET);
mdelay(500);
WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
mdelay(1);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* reset CP */
status = RREG32(RADEON_RBBM_STATUS);
if (status & (1 << 16)) {
r100_cp_reset(rdev);
}
WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
RREG32(R_0000F0_RBBM_SOFT_RESET);
mdelay(500);
WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
mdelay(1);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* restore PCI & busmastering */
pci_restore_state(rdev->pdev);
r100_enable_bm(rdev);
/* Check if GPU is idle */
status = RREG32(RADEON_RBBM_STATUS);
if (status & RADEON_RBBM_ACTIVE) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) ||
G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
return -1;
}
DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
r100_mc_resume(rdev, &save);
dev_info(rdev->dev, "GPU reset succeed\n");
return 0;
}

Expand Down Expand Up @@ -3475,7 +3423,7 @@ static int r100_startup(struct radeon_device *rdev)
/* Resume clock */
r100_clock_startup(rdev);
/* Initialize GPU configuration (# pipes, ...) */
r100_gpu_init(rdev);
// r100_gpu_init(rdev);
/* Initialize GART (initialize after TTM so we can allocate
* memory through TTM but finalize after TTM) */
r100_enable_bm(rdev);
Expand Down
128 changes: 128 additions & 0 deletions drivers/gpu/drm/radeon/r100d.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,134 @@
#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)

/* Registers */
#define R_0000F0_RBBM_SOFT_RESET 0x0000F0
#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0)
#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1)
#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE
#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1)
#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1)
#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD
#define S_0000F0_SOFT_RESET_SE(x) (((x) & 0x1) << 2)
#define G_0000F0_SOFT_RESET_SE(x) (((x) >> 2) & 0x1)
#define C_0000F0_SOFT_RESET_SE 0xFFFFFFFB
#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3)
#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1)
#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7
#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4)
#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1)
#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF
#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5)
#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1)
#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF
#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6)
#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1)
#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF
#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7)
#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1)
#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F
#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8)
#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1)
#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF
#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9)
#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1)
#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF
#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10)
#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1)
#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF
#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11)
#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1)
#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF
#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12)
#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1)
#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF
#define R_000030_BUS_CNTL 0x000030
#define S_000030_BUS_DBL_RESYNC(x) (((x) & 0x1) << 0)
#define G_000030_BUS_DBL_RESYNC(x) (((x) >> 0) & 0x1)
#define C_000030_BUS_DBL_RESYNC 0xFFFFFFFE
#define S_000030_BUS_MSTR_RESET(x) (((x) & 0x1) << 1)
#define G_000030_BUS_MSTR_RESET(x) (((x) >> 1) & 0x1)
#define C_000030_BUS_MSTR_RESET 0xFFFFFFFD
#define S_000030_BUS_FLUSH_BUF(x) (((x) & 0x1) << 2)
#define G_000030_BUS_FLUSH_BUF(x) (((x) >> 2) & 0x1)
#define C_000030_BUS_FLUSH_BUF 0xFFFFFFFB
#define S_000030_BUS_STOP_REQ_DIS(x) (((x) & 0x1) << 3)
#define G_000030_BUS_STOP_REQ_DIS(x) (((x) >> 3) & 0x1)
#define C_000030_BUS_STOP_REQ_DIS 0xFFFFFFF7
#define S_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 4)
#define G_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) >> 4) & 0x1)
#define C_000030_BUS_PM4_READ_COMBINE_EN 0xFFFFFFEF
#define S_000030_BUS_WRT_COMBINE_EN(x) (((x) & 0x1) << 5)
#define G_000030_BUS_WRT_COMBINE_EN(x) (((x) >> 5) & 0x1)
#define C_000030_BUS_WRT_COMBINE_EN 0xFFFFFFDF
#define S_000030_BUS_MASTER_DIS(x) (((x) & 0x1) << 6)
#define G_000030_BUS_MASTER_DIS(x) (((x) >> 6) & 0x1)
#define C_000030_BUS_MASTER_DIS 0xFFFFFFBF
#define S_000030_BIOS_ROM_WRT_EN(x) (((x) & 0x1) << 7)
#define G_000030_BIOS_ROM_WRT_EN(x) (((x) >> 7) & 0x1)
#define C_000030_BIOS_ROM_WRT_EN 0xFFFFFF7F
#define S_000030_BM_DAC_CRIPPLE(x) (((x) & 0x1) << 8)
#define G_000030_BM_DAC_CRIPPLE(x) (((x) >> 8) & 0x1)
#define C_000030_BM_DAC_CRIPPLE 0xFFFFFEFF
#define S_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 9)
#define G_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) >> 9) & 0x1)
#define C_000030_BUS_NON_PM4_READ_COMBINE_EN 0xFFFFFDFF
#define S_000030_BUS_XFERD_DISCARD_EN(x) (((x) & 0x1) << 10)
#define G_000030_BUS_XFERD_DISCARD_EN(x) (((x) >> 10) & 0x1)
#define C_000030_BUS_XFERD_DISCARD_EN 0xFFFFFBFF
#define S_000030_BUS_SGL_READ_DISABLE(x) (((x) & 0x1) << 11)
#define G_000030_BUS_SGL_READ_DISABLE(x) (((x) >> 11) & 0x1)
#define C_000030_BUS_SGL_READ_DISABLE 0xFFFFF7FF
#define S_000030_BIOS_DIS_ROM(x) (((x) & 0x1) << 12)
#define G_000030_BIOS_DIS_ROM(x) (((x) >> 12) & 0x1)
#define C_000030_BIOS_DIS_ROM 0xFFFFEFFF
#define S_000030_BUS_PCI_READ_RETRY_EN(x) (((x) & 0x1) << 13)
#define G_000030_BUS_PCI_READ_RETRY_EN(x) (((x) >> 13) & 0x1)
#define C_000030_BUS_PCI_READ_RETRY_EN 0xFFFFDFFF
#define S_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) & 0x1) << 14)
#define G_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) >> 14) & 0x1)
#define C_000030_BUS_AGP_AD_STEPPING_EN 0xFFFFBFFF
#define S_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) & 0x1) << 15)
#define G_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) >> 15) & 0x1)
#define C_000030_BUS_PCI_WRT_RETRY_EN 0xFFFF7FFF
#define S_000030_BUS_RETRY_WS(x) (((x) & 0xF) << 16)
#define G_000030_BUS_RETRY_WS(x) (((x) >> 16) & 0xF)
#define C_000030_BUS_RETRY_WS 0xFFF0FFFF
#define S_000030_BUS_MSTR_RD_MULT(x) (((x) & 0x1) << 20)
#define G_000030_BUS_MSTR_RD_MULT(x) (((x) >> 20) & 0x1)
#define C_000030_BUS_MSTR_RD_MULT 0xFFEFFFFF
#define S_000030_BUS_MSTR_RD_LINE(x) (((x) & 0x1) << 21)
#define G_000030_BUS_MSTR_RD_LINE(x) (((x) >> 21) & 0x1)
#define C_000030_BUS_MSTR_RD_LINE 0xFFDFFFFF
#define S_000030_BUS_SUSPEND(x) (((x) & 0x1) << 22)
#define G_000030_BUS_SUSPEND(x) (((x) >> 22) & 0x1)
#define C_000030_BUS_SUSPEND 0xFFBFFFFF
#define S_000030_LAT_16X(x) (((x) & 0x1) << 23)
#define G_000030_LAT_16X(x) (((x) >> 23) & 0x1)
#define C_000030_LAT_16X 0xFF7FFFFF
#define S_000030_BUS_RD_DISCARD_EN(x) (((x) & 0x1) << 24)
#define G_000030_BUS_RD_DISCARD_EN(x) (((x) >> 24) & 0x1)
#define C_000030_BUS_RD_DISCARD_EN 0xFEFFFFFF
#define S_000030_ENFRCWRDY(x) (((x) & 0x1) << 25)
#define G_000030_ENFRCWRDY(x) (((x) >> 25) & 0x1)
#define C_000030_ENFRCWRDY 0xFDFFFFFF
#define S_000030_BUS_MSTR_WS(x) (((x) & 0x1) << 26)
#define G_000030_BUS_MSTR_WS(x) (((x) >> 26) & 0x1)
#define C_000030_BUS_MSTR_WS 0xFBFFFFFF
#define S_000030_BUS_PARKING_DIS(x) (((x) & 0x1) << 27)
#define G_000030_BUS_PARKING_DIS(x) (((x) >> 27) & 0x1)
#define C_000030_BUS_PARKING_DIS 0xF7FFFFFF
#define S_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) & 0x1) << 28)
#define G_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) >> 28) & 0x1)
#define C_000030_BUS_MSTR_DISCONNECT_EN 0xEFFFFFFF
#define S_000030_SERR_EN(x) (((x) & 0x1) << 29)
#define G_000030_SERR_EN(x) (((x) >> 29) & 0x1)
#define C_000030_SERR_EN 0xDFFFFFFF
#define S_000030_BUS_READ_BURST(x) (((x) & 0x1) << 30)
#define G_000030_BUS_READ_BURST(x) (((x) >> 30) & 0x1)
#define C_000030_BUS_READ_BURST 0xBFFFFFFF
#define S_000030_BUS_RDY_READ_DLY(x) (((x) & 0x1) << 31)
#define G_000030_BUS_RDY_READ_DLY(x) (((x) >> 31) & 0x1)
#define C_000030_BUS_RDY_READ_DLY 0x7FFFFFFF
#define R_000040_GEN_INT_CNTL 0x000040
#define S_000040_CRTC_VBLANK(x) (((x) & 0x1) << 0)
#define G_000040_CRTC_VBLANK(x) (((x) >> 0) & 0x1)
Expand Down
Loading

0 comments on commit 90aca4d

Please sign in to comment.