From 1294d4a36d1e0dacfc37c1f269d78ff58f0cd8bc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Jul 2013 15:58:50 -0400 Subject: [PATCH 1/6] drm/radeon: add a module parameter to disable aspm Can cause hangs when enabled in certain motherboards. Set radeon.aspm=0 to disable aspm. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 3 +++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/rv6xx_dpm.c | 14 ++++++++------ drivers/gpu/drm/radeon/rv770_dpm.c | 14 ++++++++------ drivers/gpu/drm/radeon/si.c | 3 +++ 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 526e428cb4d0..038dcac7670c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -5515,6 +5515,9 @@ void evergreen_program_aspm(struct radeon_device *rdev) */ bool fusion_platform = false; + if (radeon_aspm == 0) + return; + if (!(rdev->flags & RADEON_IS_PCIE)) return; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 001081757895..2f08219c39b6 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -97,6 +97,7 @@ extern int radeon_msi; extern int radeon_lockup_timeout; extern int radeon_fastfb; extern int radeon_dpm; +extern int radeon_aspm; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e5419b350170..29876b1be8ec 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -167,6 +167,7 @@ int radeon_msi = -1; int radeon_lockup_timeout = 10000; int radeon_fastfb = 0; int radeon_dpm = -1; +int radeon_aspm = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -225,6 +226,9 @@ module_param_named(fastfb, radeon_fastfb, int, 0444); MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(dpm, radeon_dpm, int, 0444); +MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(aspm, radeon_aspm, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 8303de267ee5..65e33f387341 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1763,12 +1763,14 @@ void rv6xx_setup_asic(struct radeon_device *rdev) { r600_enable_acpi_pm(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) - rv6xx_enable_l0s(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) - rv6xx_enable_l1(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) - rv6xx_enable_pll_sleep_in_l1(rdev); + if (radeon_aspm != 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) + rv6xx_enable_l0s(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) + rv6xx_enable_l1(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) + rv6xx_enable_pll_sleep_in_l1(rdev); + } } void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index d914e04ea39a..2d347925f77d 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2099,12 +2099,14 @@ void rv770_dpm_setup_asic(struct radeon_device *rdev) rv770_enable_acpi_pm(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) - rv770_enable_l0s(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) - rv770_enable_l1(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) - rv770_enable_pll_sleep_in_l1(rdev); + if (radeon_aspm != 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) + rv770_enable_l0s(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) + rv770_enable_l1(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) + rv770_enable_pll_sleep_in_l1(rdev); + } } void rv770_dpm_display_configuration_changed(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index d3f05076f385..d325280e2f9f 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -7053,6 +7053,9 @@ static void si_program_aspm(struct radeon_device *rdev) bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; bool disable_clkreq = false; + if (radeon_aspm == 0) + return; + if (!(rdev->flags & RADEON_IS_PCIE)) return; From 1fa4252af760560f77ca3d5d360fd62df3292c7f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Jul 2013 10:18:52 -0400 Subject: [PATCH 2/6] drm/radeon: fix an endian bug in atom table parsing Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index fbdaff55556b..0c3455a73992 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3638,7 +3638,7 @@ int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, p += le16_to_cpu(vram_module->usModuleSize); } mclk_range_table->num_entries = (u8) - ((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / + ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / mem_timing_size); p = (u8 *)vram_module->asMemTiming; for (i = 0; i < mclk_range_table->num_entries; i++) { From 77c7d50a4a9f1fa3aa42adad00e7b44aa70ec910 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Jul 2013 10:52:43 -0400 Subject: [PATCH 3/6] drm/radeon/dpm: fix atom vram table parsing Parsing the table in incorrectly led to problems with certain asics with mclk switching. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 26 +++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 0c3455a73992..a2e324188bc9 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3513,7 +3513,6 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, u8 frev, crev, i; u16 data_offset, size; union vram_info *vram_info; - u8 *p; memset(mem_info, 0, sizeof(struct atom_memory_info)); @@ -3529,13 +3528,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_3.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V3 *vram_module = (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo; - p = (u8 *)vram_info->v1_3.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V3 *)p; if (le16_to_cpu(vram_module->usSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usSize); + vram_module = (ATOM_VRAM_MODULE_V3 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usSize)); } mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0; @@ -3547,13 +3545,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3572,13 +3569,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V7 *vram_module = (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo; - p = (u8 *)vram_info->v2_1.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V7 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V7 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3628,21 +3624,19 @@ int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; - ATOM_MEMORY_TIMING_FORMAT *format; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mclk_range_table->num_entries = (u8) ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / mem_timing_size); - p = (u8 *)vram_module->asMemTiming; + p = (u8 *)&vram_module->asMemTiming[0]; for (i = 0; i < mclk_range_table->num_entries; i++) { - format = (ATOM_MEMORY_TIMING_FORMAT *)p; + ATOM_MEMORY_TIMING_FORMAT *format = (ATOM_MEMORY_TIMING_FORMAT *)p; mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange); p += mem_timing_size; } From 48fa04c3fcdb4f6ac041976bedaf19ca5bee20c0 Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Wed, 17 Jul 2013 14:02:23 -0400 Subject: [PATCH 4/6] drm/radeon/dpm/atom: restructure logic to work around a compiler bug It seems gcc 4.8.1 generates bogus code for the old logic causing part of the function to get skipped. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66932 https://bugs.freedesktop.org/show_bug.cgi?id=66972 https://bugs.freedesktop.org/show_bug.cgi?id=66945 Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index a2e324188bc9..2606ec680ae3 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3703,8 +3703,9 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) return -EINVAL; - while (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) && - (i < num_entries)) { + while (i < num_entries) { + if (reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) + break; reg_table->mc_reg_address[i].s1 = (u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex)); reg_table->mc_reg_address[i].pre_reg_data = From f90555cbe629e14c6af1dcec1933a3833ecd321f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Jul 2013 16:34:12 -0400 Subject: [PATCH 5/6] drm/radeon/dpm/atom: fix broken gcc harder See bugs: https://bugs.freedesktop.org/show_bug.cgi?id=66932 https://bugs.freedesktop.org/show_bug.cgi?id=66972 https://bugs.freedesktop.org/show_bug.cgi?id=66945 Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 2606ec680ae3..e3f3e8841789 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -3699,18 +3699,21 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, (ATOM_MEMORY_SETTING_DATA_BLOCK *) ((u8 *)reg_block + (2 * sizeof(u16)) + le16_to_cpu(reg_block->usRegIndexTblSize)); + ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) return -EINVAL; while (i < num_entries) { - if (reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) + if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) break; reg_table->mc_reg_address[i].s1 = - (u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex)); + (u16)(le16_to_cpu(format->usRegIndex)); reg_table->mc_reg_address[i].pre_reg_data = - (u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength); + (u8)(format->ucPreRegDataLength); i++; + format = (ATOM_INIT_REG_INDEX_FORMAT *) + ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); } reg_table->last = i; while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) && From 444bddc4b9b3313a562cd3ba40f780fb82570f7d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Jul 2013 13:05:23 -0400 Subject: [PATCH 6/6] drm/radeon/dpm: add debugfs support for RS780/RS880 (v3) This allows you to look at the current DPM state via debugfs. Due to the way the hardware works on these asics, there's no way to look up exactly what power state we are in, so we make the best guess we can based on the current sclk. v2: Anthoine's version v3: fix ref div Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_asic.c | 1 + drivers/gpu/drm/radeon/radeon_asic.h | 2 ++ drivers/gpu/drm/radeon/rs780_dpm.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs780d.h | 3 +++ 4 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index fea997e247ba..78bec1a58ed1 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1270,6 +1270,7 @@ static struct radeon_asic rs780_asic = { .get_sclk = &rs780_dpm_get_sclk, .get_mclk = &rs780_dpm_get_mclk, .print_power_state = &rs780_dpm_print_power_state, + .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level, }, .pflip = { .pre_page_flip = &rs600_pre_page_flip, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index b04b5789f4a8..ca1895709908 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -433,6 +433,8 @@ u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low); u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low); void rs780_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *ps); +void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m); /* uvd */ int r600_uvd_init(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index bef832a62fee..d1a1ce73bd45 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -28,6 +28,7 @@ #include "r600_dpm.h" #include "rs780_dpm.h" #include "atom.h" +#include static struct igp_ps *rs780_get_ps(struct radeon_ps *rps) { @@ -961,3 +962,27 @@ u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low) return pi->bootup_uma_clk; } + +void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct igp_ps *ps = rs780_get_ps(rps); + u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK; + u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL); + u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1; + u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 + + ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1; + u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) / + (post_div * ref_div); + + seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + + /* guess based on the current sclk */ + if (sclk < (ps->sclk_low + 500)) + seq_printf(m, "power level 0 sclk: %u vddc_index: %d\n", + ps->sclk_low, ps->min_voltage); + else + seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n", + ps->sclk_high, ps->max_voltage); +} diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h index b1142ed1c628..cfbe9a43d97b 100644 --- a/drivers/gpu/drm/radeon/rs780d.h +++ b/drivers/gpu/drm/radeon/rs780d.h @@ -28,6 +28,7 @@ # define SPLL_SLEEP (1 << 1) # define SPLL_REF_DIV(x) ((x) << 2) # define SPLL_REF_DIV_MASK (7 << 2) +# define SPLL_REF_DIV_SHIFT 2 # define SPLL_FB_DIV(x) ((x) << 5) # define SPLL_FB_DIV_MASK (0xff << 2) # define SPLL_FB_DIV_SHIFT 2 @@ -36,8 +37,10 @@ # define SPLL_PULSENUM_MASK (3 << 14) # define SPLL_SW_HILEN(x) ((x) << 16) # define SPLL_SW_HILEN_MASK (0xf << 16) +# define SPLL_SW_HILEN_SHIFT 16 # define SPLL_SW_LOLEN(x) ((x) << 20) # define SPLL_SW_LOLEN_MASK (0xf << 20) +# define SPLL_SW_LOLEN_SHIFT 20 # define SPLL_DIVEN (1 << 24) # define SPLL_BYPASS_EN (1 << 25) # define SPLL_CHG_STATUS (1 << 29)