diff options
author | Jerome Glisse <jglisse@redhat.com> | 2010-03-09 09:45:12 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-04-05 21:21:11 -0400 |
commit | 90aca4d2740255bd130ea71a91530b9920c70abe (patch) | |
tree | acf9b8a4353e6727cd6cba5b71caaf9f067e465d /drivers/gpu/drm/radeon/r300.c | |
parent | a2d07b7438f015a0349bc9af3c96a8164549bbc5 (diff) |
drm/radeon/kms: simplify & improve GPU reset V2
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>
Diffstat (limited to 'drivers/gpu/drm/radeon/r300.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r300.c | 134 |
1 files changed, 59 insertions, 75 deletions
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 7d5de5dbde23..199110ef8df2 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c | |||
@@ -151,6 +151,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) | |||
151 | u32 tmp; | 151 | u32 tmp; |
152 | int r; | 152 | int r; |
153 | 153 | ||
154 | WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); | ||
155 | WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); | ||
156 | WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); | ||
157 | WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); | ||
154 | tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); | 158 | tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); |
155 | tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; | 159 | tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; |
156 | WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); | 160 | WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); |
@@ -323,7 +327,6 @@ void r300_gpu_init(struct radeon_device *rdev) | |||
323 | { | 327 | { |
324 | uint32_t gb_tile_config, tmp; | 328 | uint32_t gb_tile_config, tmp; |
325 | 329 | ||
326 | r100_hdp_reset(rdev); | ||
327 | /* FIXME: rv380 one pipes ? */ | 330 | /* FIXME: rv380 one pipes ? */ |
328 | if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || | 331 | if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || |
329 | (rdev->family == CHIP_R350)) { | 332 | (rdev->family == CHIP_R350)) { |
@@ -376,57 +379,6 @@ void r300_gpu_init(struct radeon_device *rdev) | |||
376 | rdev->num_gb_pipes, rdev->num_z_pipes); | 379 | rdev->num_gb_pipes, rdev->num_z_pipes); |
377 | } | 380 | } |
378 | 381 | ||
379 | int r300_ga_reset(struct radeon_device *rdev) | ||
380 | { | ||
381 | uint32_t tmp; | ||
382 | bool reinit_cp; | ||
383 | int i; | ||
384 | |||
385 | reinit_cp = rdev->cp.ready; | ||
386 | rdev->cp.ready = false; | ||
387 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
388 | WREG32(RADEON_CP_CSQ_MODE, 0); | ||
389 | WREG32(RADEON_CP_CSQ_CNTL, 0); | ||
390 | WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); | ||
391 | (void)RREG32(RADEON_RBBM_SOFT_RESET); | ||
392 | udelay(200); | ||
393 | WREG32(RADEON_RBBM_SOFT_RESET, 0); | ||
394 | /* Wait to prevent race in RBBM_STATUS */ | ||
395 | mdelay(1); | ||
396 | tmp = RREG32(RADEON_RBBM_STATUS); | ||
397 | if (tmp & ((1 << 20) | (1 << 26))) { | ||
398 | DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp); | ||
399 | /* GA still busy soft reset it */ | ||
400 | WREG32(0x429C, 0x200); | ||
401 | WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); | ||
402 | WREG32(R300_RE_SCISSORS_TL, 0); | ||
403 | WREG32(R300_RE_SCISSORS_BR, 0); | ||
404 | WREG32(0x24AC, 0); | ||
405 | } | ||
406 | /* Wait to prevent race in RBBM_STATUS */ | ||
407 | mdelay(1); | ||
408 | tmp = RREG32(RADEON_RBBM_STATUS); | ||
409 | if (!(tmp & ((1 << 20) | (1 << 26)))) { | ||
410 | break; | ||
411 | } | ||
412 | } | ||
413 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
414 | tmp = RREG32(RADEON_RBBM_STATUS); | ||
415 | if (!(tmp & ((1 << 20) | (1 << 26)))) { | ||
416 | DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", | ||
417 | tmp); | ||
418 | if (reinit_cp) { | ||
419 | return r100_cp_init(rdev, rdev->cp.ring_size); | ||
420 | } | ||
421 | return 0; | ||
422 | } | ||
423 | DRM_UDELAY(1); | ||
424 | } | ||
425 | tmp = RREG32(RADEON_RBBM_STATUS); | ||
426 | DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); | ||
427 | return -1; | ||
428 | } | ||
429 | |||
430 | bool r300_gpu_is_lockup(struct radeon_device *rdev) | 382 | bool r300_gpu_is_lockup(struct radeon_device *rdev) |
431 | { | 383 | { |
432 | u32 rbbm_status; | 384 | u32 rbbm_status; |
@@ -451,37 +403,69 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev) | |||
451 | 403 | ||
452 | int r300_asic_reset(struct radeon_device *rdev) | 404 | int r300_asic_reset(struct radeon_device *rdev) |
453 | { | 405 | { |
454 | uint32_t status; | 406 | struct r100_mc_save save; |
407 | u32 status, tmp; | ||
455 | 408 | ||
456 | /* reset order likely matter */ | 409 | r100_mc_stop(rdev, &save); |
457 | status = RREG32(RADEON_RBBM_STATUS); | 410 | status = RREG32(R_000E40_RBBM_STATUS); |
458 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | 411 | if (!G_000E40_GUI_ACTIVE(status)) { |
459 | /* reset HDP */ | 412 | return 0; |
460 | r100_hdp_reset(rdev); | ||
461 | /* reset rb2d */ | ||
462 | if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { | ||
463 | r100_rb2d_reset(rdev); | ||
464 | } | ||
465 | /* reset GA */ | ||
466 | if (status & ((1 << 20) | (1 << 26))) { | ||
467 | r300_ga_reset(rdev); | ||
468 | } | ||
469 | /* reset CP */ | ||
470 | status = RREG32(RADEON_RBBM_STATUS); | ||
471 | if (status & (1 << 16)) { | ||
472 | r100_cp_reset(rdev); | ||
473 | } | 413 | } |
414 | status = RREG32(R_000E40_RBBM_STATUS); | ||
415 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
416 | /* stop CP */ | ||
417 | WREG32(RADEON_CP_CSQ_CNTL, 0); | ||
418 | tmp = RREG32(RADEON_CP_RB_CNTL); | ||
419 | WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); | ||
420 | WREG32(RADEON_CP_RB_RPTR_WR, 0); | ||
421 | WREG32(RADEON_CP_RB_WPTR, 0); | ||
422 | WREG32(RADEON_CP_RB_CNTL, tmp); | ||
423 | /* save PCI state */ | ||
424 | pci_save_state(rdev->pdev); | ||
425 | /* disable bus mastering */ | ||
426 | r100_bm_disable(rdev); | ||
427 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | | ||
428 | S_0000F0_SOFT_RESET_GA(1)); | ||
429 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
430 | mdelay(500); | ||
431 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
432 | mdelay(1); | ||
433 | status = RREG32(R_000E40_RBBM_STATUS); | ||
434 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
435 | /* resetting the CP seems to be problematic sometimes it end up | ||
436 | * hard locking the computer, but it's necessary for successfull | ||
437 | * reset more test & playing is needed on R3XX/R4XX to find a | ||
438 | * reliable (if any solution) | ||
439 | */ | ||
440 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); | ||
441 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
442 | mdelay(500); | ||
443 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
444 | mdelay(1); | ||
445 | status = RREG32(R_000E40_RBBM_STATUS); | ||
446 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
447 | /* reset MC */ | ||
448 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); | ||
449 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
450 | mdelay(500); | ||
451 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
452 | mdelay(1); | ||
453 | status = RREG32(R_000E40_RBBM_STATUS); | ||
454 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
455 | /* restore PCI & busmastering */ | ||
456 | pci_restore_state(rdev->pdev); | ||
457 | r100_enable_bm(rdev); | ||
474 | /* Check if GPU is idle */ | 458 | /* Check if GPU is idle */ |
475 | status = RREG32(RADEON_RBBM_STATUS); | 459 | if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { |
476 | if (status & RADEON_RBBM_ACTIVE) { | 460 | dev_err(rdev->dev, "failed to reset GPU\n"); |
477 | DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); | 461 | rdev->gpu_lockup = true; |
478 | return -1; | 462 | return -1; |
479 | } | 463 | } |
480 | DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); | 464 | r100_mc_resume(rdev, &save); |
465 | dev_info(rdev->dev, "GPU reset succeed\n"); | ||
481 | return 0; | 466 | return 0; |
482 | } | 467 | } |
483 | 468 | ||
484 | |||
485 | /* | 469 | /* |
486 | * r300,r350,rv350,rv380 VRAM info | 470 | * r300,r350,rv350,rv380 VRAM info |
487 | */ | 471 | */ |