diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/r300.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r300.c | 156 |
1 files changed, 82 insertions, 74 deletions
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index bd75f99bd65e..bb005bff4b08 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c | |||
@@ -27,8 +27,9 @@ | |||
27 | */ | 27 | */ |
28 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include "drmP.h" | 30 | #include <drm/drmP.h> |
31 | #include "drm.h" | 31 | #include <drm/drm.h> |
32 | #include <drm/drm_crtc_helper.h> | ||
32 | #include "radeon_reg.h" | 33 | #include "radeon_reg.h" |
33 | #include "radeon.h" | 34 | #include "radeon.h" |
34 | #include "radeon_asic.h" | 35 | #include "radeon_asic.h" |
@@ -151,6 +152,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) | |||
151 | u32 tmp; | 152 | u32 tmp; |
152 | int r; | 153 | int r; |
153 | 154 | ||
155 | WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); | ||
156 | WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); | ||
157 | WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); | ||
158 | WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); | ||
154 | tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); | 159 | tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); |
155 | tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; | 160 | tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; |
156 | WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); | 161 | WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); |
@@ -323,7 +328,6 @@ void r300_gpu_init(struct radeon_device *rdev) | |||
323 | { | 328 | { |
324 | uint32_t gb_tile_config, tmp; | 329 | uint32_t gb_tile_config, tmp; |
325 | 330 | ||
326 | r100_hdp_reset(rdev); | ||
327 | /* FIXME: rv380 one pipes ? */ | 331 | /* FIXME: rv380 one pipes ? */ |
328 | if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || | 332 | if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || |
329 | (rdev->family == CHIP_R350)) { | 333 | (rdev->family == CHIP_R350)) { |
@@ -376,89 +380,93 @@ void r300_gpu_init(struct radeon_device *rdev) | |||
376 | rdev->num_gb_pipes, rdev->num_z_pipes); | 380 | rdev->num_gb_pipes, rdev->num_z_pipes); |
377 | } | 381 | } |
378 | 382 | ||
379 | int r300_ga_reset(struct radeon_device *rdev) | 383 | bool r300_gpu_is_lockup(struct radeon_device *rdev) |
380 | { | 384 | { |
381 | uint32_t tmp; | 385 | u32 rbbm_status; |
382 | bool reinit_cp; | 386 | int r; |
383 | int i; | ||
384 | 387 | ||
385 | reinit_cp = rdev->cp.ready; | 388 | rbbm_status = RREG32(R_000E40_RBBM_STATUS); |
386 | rdev->cp.ready = false; | 389 | if (!G_000E40_GUI_ACTIVE(rbbm_status)) { |
387 | for (i = 0; i < rdev->usec_timeout; i++) { | 390 | r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); |
388 | WREG32(RADEON_CP_CSQ_MODE, 0); | 391 | return false; |
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 | } | 392 | } |
413 | for (i = 0; i < rdev->usec_timeout; i++) { | 393 | /* force CP activities */ |
414 | tmp = RREG32(RADEON_RBBM_STATUS); | 394 | r = radeon_ring_lock(rdev, 2); |
415 | if (!(tmp & ((1 << 20) | (1 << 26)))) { | 395 | if (!r) { |
416 | DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", | 396 | /* PACKET2 NOP */ |
417 | tmp); | 397 | radeon_ring_write(rdev, 0x80000000); |
418 | if (reinit_cp) { | 398 | radeon_ring_write(rdev, 0x80000000); |
419 | return r100_cp_init(rdev, rdev->cp.ring_size); | 399 | radeon_ring_unlock_commit(rdev); |
420 | } | ||
421 | return 0; | ||
422 | } | ||
423 | DRM_UDELAY(1); | ||
424 | } | 400 | } |
425 | tmp = RREG32(RADEON_RBBM_STATUS); | 401 | rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); |
426 | DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); | 402 | return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); |
427 | return -1; | ||
428 | } | 403 | } |
429 | 404 | ||
430 | int r300_gpu_reset(struct radeon_device *rdev) | 405 | int r300_asic_reset(struct radeon_device *rdev) |
431 | { | 406 | { |
432 | uint32_t status; | 407 | struct r100_mc_save save; |
433 | 408 | u32 status, tmp; | |
434 | /* reset order likely matter */ | 409 | |
435 | status = RREG32(RADEON_RBBM_STATUS); | 410 | r100_mc_stop(rdev, &save); |
436 | /* reset HDP */ | 411 | status = RREG32(R_000E40_RBBM_STATUS); |
437 | r100_hdp_reset(rdev); | 412 | if (!G_000E40_GUI_ACTIVE(status)) { |
438 | /* reset rb2d */ | 413 | return 0; |
439 | if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { | ||
440 | r100_rb2d_reset(rdev); | ||
441 | } | ||
442 | /* reset GA */ | ||
443 | if (status & ((1 << 20) | (1 << 26))) { | ||
444 | r300_ga_reset(rdev); | ||
445 | } | ||
446 | /* reset CP */ | ||
447 | status = RREG32(RADEON_RBBM_STATUS); | ||
448 | if (status & (1 << 16)) { | ||
449 | r100_cp_reset(rdev); | ||
450 | } | 414 | } |
415 | status = RREG32(R_000E40_RBBM_STATUS); | ||
416 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
417 | /* stop CP */ | ||
418 | WREG32(RADEON_CP_CSQ_CNTL, 0); | ||
419 | tmp = RREG32(RADEON_CP_RB_CNTL); | ||
420 | WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); | ||
421 | WREG32(RADEON_CP_RB_RPTR_WR, 0); | ||
422 | WREG32(RADEON_CP_RB_WPTR, 0); | ||
423 | WREG32(RADEON_CP_RB_CNTL, tmp); | ||
424 | /* save PCI state */ | ||
425 | pci_save_state(rdev->pdev); | ||
426 | /* disable bus mastering */ | ||
427 | r100_bm_disable(rdev); | ||
428 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | | ||
429 | S_0000F0_SOFT_RESET_GA(1)); | ||
430 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
431 | mdelay(500); | ||
432 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
433 | mdelay(1); | ||
434 | status = RREG32(R_000E40_RBBM_STATUS); | ||
435 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
436 | /* resetting the CP seems to be problematic sometimes it end up | ||
437 | * hard locking the computer, but it's necessary for successfull | ||
438 | * reset more test & playing is needed on R3XX/R4XX to find a | ||
439 | * reliable (if any solution) | ||
440 | */ | ||
441 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); | ||
442 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
443 | mdelay(500); | ||
444 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
445 | mdelay(1); | ||
446 | status = RREG32(R_000E40_RBBM_STATUS); | ||
447 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
448 | /* reset MC */ | ||
449 | WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); | ||
450 | RREG32(R_0000F0_RBBM_SOFT_RESET); | ||
451 | mdelay(500); | ||
452 | WREG32(R_0000F0_RBBM_SOFT_RESET, 0); | ||
453 | mdelay(1); | ||
454 | status = RREG32(R_000E40_RBBM_STATUS); | ||
455 | dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); | ||
456 | /* restore PCI & busmastering */ | ||
457 | pci_restore_state(rdev->pdev); | ||
458 | r100_enable_bm(rdev); | ||
451 | /* Check if GPU is idle */ | 459 | /* Check if GPU is idle */ |
452 | status = RREG32(RADEON_RBBM_STATUS); | 460 | if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { |
453 | if (status & RADEON_RBBM_ACTIVE) { | 461 | dev_err(rdev->dev, "failed to reset GPU\n"); |
454 | DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); | 462 | rdev->gpu_lockup = true; |
455 | return -1; | 463 | return -1; |
456 | } | 464 | } |
457 | DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); | 465 | r100_mc_resume(rdev, &save); |
466 | dev_info(rdev->dev, "GPU reset succeed\n"); | ||
458 | return 0; | 467 | return 0; |
459 | } | 468 | } |
460 | 469 | ||
461 | |||
462 | /* | 470 | /* |
463 | * r300,r350,rv350,rv380 VRAM info | 471 | * r300,r350,rv350,rv380 VRAM info |
464 | */ | 472 | */ |
@@ -1317,7 +1325,7 @@ int r300_resume(struct radeon_device *rdev) | |||
1317 | /* Resume clock before doing reset */ | 1325 | /* Resume clock before doing reset */ |
1318 | r300_clock_startup(rdev); | 1326 | r300_clock_startup(rdev); |
1319 | /* Reset gpu before posting otherwise ATOM will enter infinite loop */ | 1327 | /* Reset gpu before posting otherwise ATOM will enter infinite loop */ |
1320 | if (radeon_gpu_reset(rdev)) { | 1328 | if (radeon_asic_reset(rdev)) { |
1321 | dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", | 1329 | dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", |
1322 | RREG32(R_000E40_RBBM_STATUS), | 1330 | RREG32(R_000E40_RBBM_STATUS), |
1323 | RREG32(R_0007C0_CP_STAT)); | 1331 | RREG32(R_0007C0_CP_STAT)); |
@@ -1388,7 +1396,7 @@ int r300_init(struct radeon_device *rdev) | |||
1388 | return r; | 1396 | return r; |
1389 | } | 1397 | } |
1390 | /* Reset gpu before posting otherwise ATOM will enter infinite loop */ | 1398 | /* Reset gpu before posting otherwise ATOM will enter infinite loop */ |
1391 | if (radeon_gpu_reset(rdev)) { | 1399 | if (radeon_asic_reset(rdev)) { |
1392 | dev_warn(rdev->dev, | 1400 | dev_warn(rdev->dev, |
1393 | "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", | 1401 | "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", |
1394 | RREG32(R_000E40_RBBM_STATUS), | 1402 | RREG32(R_000E40_RBBM_STATUS), |