From 0279ed19bd962434d334f5eeb16d14fdd9459a00 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 2 Oct 2013 15:18:14 -0400 Subject: [PATCH] drm/radeon: implement pci config reset for CIK (v3) pci config reset is a low level reset that resets the entire chip from the bus interface. It can be more reliable if soft reset fails. v2: fix rebase v3: hide behind module parameter Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 161 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/cikd.h | 11 +++ 2 files changed, 172 insertions(+) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index e66eb4745347..9e50dd5d0e42 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4880,6 +4880,160 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) cik_print_gpu_status_regs(rdev); } +struct kv_reset_save_regs { + u32 gmcon_reng_execute; + u32 gmcon_misc; + u32 gmcon_misc3; +}; + +static void kv_save_regs_for_reset(struct radeon_device *rdev, + struct kv_reset_save_regs *save) +{ + save->gmcon_reng_execute = RREG32(GMCON_RENG_EXECUTE); + save->gmcon_misc = RREG32(GMCON_MISC); + save->gmcon_misc3 = RREG32(GMCON_MISC3); + + WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute & ~RENG_EXECUTE_ON_PWR_UP); + WREG32(GMCON_MISC, save->gmcon_misc & ~(RENG_EXECUTE_ON_REG_UPDATE | + STCTRL_STUTTER_EN)); +} + +static void kv_restore_regs_for_reset(struct radeon_device *rdev, + struct kv_reset_save_regs *save) +{ + int i; + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0x200010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0x300010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x210000); + WREG32(GMCON_PGFSM_CONFIG, 0xa00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x21003); + WREG32(GMCON_PGFSM_CONFIG, 0xb00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x2b00); + WREG32(GMCON_PGFSM_CONFIG, 0xc00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0xd00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x420000); + WREG32(GMCON_PGFSM_CONFIG, 0x100010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x120202); + WREG32(GMCON_PGFSM_CONFIG, 0x500010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x3e3e36); + WREG32(GMCON_PGFSM_CONFIG, 0x600010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x373f3e); + WREG32(GMCON_PGFSM_CONFIG, 0x700010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x3e1332); + WREG32(GMCON_PGFSM_CONFIG, 0xe00010ff); + + WREG32(GMCON_MISC3, save->gmcon_misc3); + WREG32(GMCON_MISC, save->gmcon_misc); + WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute); +} + +static void cik_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct evergreen_mc_save save; + struct kv_reset_save_regs kv_save = { 0 }; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* disable cg/pg */ + cik_fini_pg(rdev); + cik_fini_cg(rdev); + + /* Disable GFX parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); + + /* Disable MEC parsing/prefetching */ + WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT); + + /* sdma0 */ + tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET); + tmp |= SDMA_HALT; + WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp); + /* sdma1 */ + tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET); + tmp |= SDMA_HALT; + WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp); + /* XXX other engines? */ + + /* halt the rlc, disable cp internal ints */ + cik_rlc_stop(rdev); + + udelay(50); + + /* disable mem access */ + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); + } + + if (rdev->flags & RADEON_IS_IGP) + kv_save_regs_for_reset(rdev, &kv_save); + + /* disable BM */ + pci_clear_master(rdev->pdev); + /* reset */ + radeon_pci_config_reset(rdev); + + udelay(100); + + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } + + /* does asic init need to be run first??? */ + if (rdev->flags & RADEON_IS_IGP) + kv_restore_regs_for_reset(rdev, &kv_save); +} + /** * cik_asic_reset - soft reset GPU * @@ -4898,10 +5052,17 @@ int cik_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ cik_gpu_soft_reset(rdev, reset_mask); reset_mask = cik_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + cik_gpu_pci_config_reset(rdev); + + reset_mask = cik_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 5964af5e5b2d..98bae9d7b74d 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -724,6 +724,17 @@ #define ATC_MISC_CG 0x3350 +#define GMCON_RENG_EXECUTE 0x3508 +#define RENG_EXECUTE_ON_PWR_UP (1 << 0) +#define GMCON_MISC 0x350c +#define RENG_EXECUTE_ON_REG_UPDATE (1 << 11) +#define STCTRL_STUTTER_EN (1 << 16) + +#define GMCON_PGFSM_CONFIG 0x3538 +#define GMCON_PGFSM_WRITE 0x353c +#define GMCON_PGFSM_READ 0x3540 +#define GMCON_MISC3 0x3544 + #define MC_SEQ_CNTL_3 0x3600 # define CAC_EN (1 << 31) #define MC_SEQ_G5PDX_CTRL 0x3604 -- 2.20.1