From 12e3a350e01d89bd7d84799b0be1673760e393df Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Apr 2013 13:22:17 -0400 Subject: [PATCH] drm/radeon: avoid moving the MC vram location (v2) When setting up the memory controller, avoid moving the vram location if possible. This should avoid problems with hangs and corruption at boot especially on UEFI systems due to invalid reads from the display hardware when try and move the location of vram. May fix: https://bugs.freedesktop.org/show_bug.cgi?id=43655 https://bugs.freedesktop.org/show_bug.cgi?id=62976 https://bugs.freedesktop.org/show_bug.cgi?id=57567 et al. v2: avoid moving crtc addresses as well Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen.c | 41 +++++++++++++---- drivers/gpu/drm/radeon/r600.c | 11 ++-- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_asic.h | 6 ++ drivers/gpu/drm/radeon/radeon_device.c | 15 +++++- drivers/gpu/drm/radeon/rv515.c | 79 ++++++++++++++++++++++++++------ drivers/gpu/drm/radeon/rv770.c | 8 ++- drivers/gpu/drm/radeon/si.c | 50 +++----------------- 8 files changed, 134 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 305a657..f2857a5 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1316,6 +1316,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav /* disable VGA render */ WREG32(VGA_RENDER_CONTROL, 0); + + save->mc_fb_location = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xffff) << 24; /* blank the display controllers */ for (i = 0; i < rdev->num_crtc; i++) { crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN; @@ -1340,6 +1342,14 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } + save->crtc_mc_paddr[i] = + RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i]); + save->crtc_mc_paddr[i] |= + (u64)RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i]) << 32; + save->crtc_mc_saddr[i] = + RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i]); + save->crtc_mc_saddr[i] |= + (u64)RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i]) << 32; /* wait for the next frame */ frame_count = radeon_get_vblank_counter(rdev, i); for (j = 0; j < rdev->usec_timeout; j++) { @@ -1370,17 +1380,28 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s { u32 tmp, frame_count; int i, j; + u64 mc_fb_location = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xffff) << 24; /* update crtc base addresses */ for (i = 0; i < rdev->num_crtc; i++) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], - (u32)rdev->mc.vram_start); + if (save->crtc_enabled[i] && + (save->mc_fb_location != mc_fb_location)) { + if (save->crtc_mc_paddr[i]) + save->crtc_mc_paddr[i] -= save->mc_fb_location; + save->crtc_mc_paddr[i] += mc_fb_location; + if (save->crtc_mc_saddr[i]) + save->crtc_mc_saddr[i] -= save->mc_fb_location; + save->crtc_mc_saddr[i] += mc_fb_location; + + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], + upper_32_bits(save->crtc_mc_paddr[i])); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], + upper_32_bits(save->crtc_mc_saddr[i])); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], + save->crtc_mc_paddr[i]); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], + save->crtc_mc_saddr[i]); + } } WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); @@ -1425,6 +1446,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s void evergreen_mc_program(struct radeon_device *rdev) { struct evergreen_mc_save save; + u32 mc_vm_fb_location = RREG32(MC_VM_FB_LOCATION); u32 tmp; int i, j; @@ -1477,7 +1499,8 @@ void evergreen_mc_program(struct radeon_device *rdev) } tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); - WREG32(MC_VM_FB_LOCATION, tmp); + if (tmp != mc_vm_fb_location) + WREG32(MC_VM_FB_LOCATION, tmp); WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30)); WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0740db3..1edf65f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1049,6 +1049,7 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev) static void r600_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; + u32 mc_vm_fb_location = RREG32(MC_VM_FB_LOCATION); u32 tmp; int i, j; @@ -1090,7 +1091,8 @@ static void r600_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); - WREG32(MC_VM_FB_LOCATION, tmp); + if (tmp != mc_vm_fb_location) + WREG32(MC_VM_FB_LOCATION, tmp); WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); WREG32(HDP_NONSURFACE_INFO, (2 << 7)); WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF); @@ -1166,11 +1168,8 @@ static void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc mc->mc_vram_size >> 20, mc->vram_start, mc->vram_end, mc->real_vram_size >> 20); } else { - u64 base = 0; - if (rdev->flags & RADEON_IS_IGP) { - base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; - base <<= 24; - } + u64 base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; + base <<= 24; radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8263af3..8bd8753 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -517,6 +517,7 @@ struct radeon_mc { bool vram_is_ddr; bool igp_sideport_enabled; u64 gtt_base_align; + u64 mc_mask; }; bool radeon_combios_sideport_present(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3535f73..14615fd 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -264,6 +264,9 @@ struct rv515_mc_save { u32 vga_render_control; u32 vga_hdp_control; bool crtc_enabled[2]; + u64 crtc_mc_paddr[2]; + u64 crtc_mc_saddr[2]; + u64 mc_fb_location; }; int rv515_init(struct radeon_device *rdev); @@ -417,6 +420,9 @@ struct evergreen_mc_save { u32 vga_render_control; u32 vga_hdp_control; bool crtc_enabled[RADEON_MAX_CRTCS]; + u64 crtc_mc_paddr[RADEON_MAX_CRTCS]; + u64 crtc_mc_saddr[RADEON_MAX_CRTCS]; + u64 mc_fb_location; }; void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 44b8034..62d0ba3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -359,7 +359,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 uint64_t limit = (uint64_t)radeon_vram_limit << 20; mc->vram_start = base; - if (mc->mc_vram_size > (0xFFFFFFFF - base + 1)) { + if (mc->mc_vram_size > (rdev->mc.mc_mask - base + 1)) { dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); mc->real_vram_size = mc->aper_size; mc->mc_vram_size = mc->aper_size; @@ -394,7 +394,7 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { u64 size_af, size_bf; - size_af = ((0xFFFFFFFF - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; + size_af = ((rdev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; size_bf = mc->vram_start & ~mc->gtt_base_align; if (size_bf > size_af) { if (mc->gtt_size > size_bf) { @@ -1068,6 +1068,17 @@ int radeon_device_init(struct radeon_device *rdev, radeon_agp_disable(rdev); } + /* Set the internal MC address mask + * This is the max address of the GPU's + * internal address space. + */ + if (rdev->family >= CHIP_CAYMAN) + rdev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ + else if (rdev->family >= CHIP_CEDAR) + rdev->mc.mc_mask = 0xfffffffffULL; /* 36 bit MC */ + else + rdev->mc.mc_mask = 0xffffffffULL; /* 32 bit MC */ + /* set DMA mask + need_dma32 flags. * PCIE - can handle 40-bits. * IGP - can handle 40-bits diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 435ed35..bf68ca3 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -293,6 +293,12 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL); + if (rdev->family >= CHIP_RV770) + save->mc_fb_location = (u64)(RREG32(0x2024) & 0xffff) << 24; + else if (rdev->family >= CHIP_R600) + save->mc_fb_location = (u64)(RREG32(0x2180) & 0xffff) << 24; + else + save->mc_fb_location = 0; /* disable VGA render */ WREG32(R_000300_VGA_RENDER_CONTROL, 0); /* blank the display controllers */ @@ -306,6 +312,25 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); } + if (rdev->family >= CHIP_R600) { + save->crtc_mc_paddr[i] = + RREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i]); + save->crtc_mc_saddr[i] = + RREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i]); + if (rdev->family >= CHIP_RV770) { + if (i == 0) { + save->crtc_mc_paddr[i] |= + (u64)RREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH) << 32; + save->crtc_mc_saddr[i] |= + (u64)RREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH) << 32; + } else { + save->crtc_mc_paddr[i] |= + (u64)RREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH) << 32; + save->crtc_mc_saddr[i] |= + (u64)RREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH) << 32; + } + } + } /* wait for the next frame */ frame_count = radeon_get_vblank_counter(rdev, i); for (j = 0; j < rdev->usec_timeout; j++) { @@ -344,26 +369,50 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) { u32 tmp, frame_count; int i, j; + u64 mc_fb_location; + + if (rdev->family >= CHIP_RV770) + mc_fb_location = (u64)(RREG32(0x2024) & 0xffff) << 24; + else if (rdev->family >= CHIP_R600) + mc_fb_location = (u64)(RREG32(0x2180) & 0xffff) << 24; + else + mc_fb_location = rdev->mc.vram_start; /* update crtc base addresses */ for (i = 0; i < rdev->num_crtc; i++) { - if (rdev->family >= CHIP_RV770) { - if (i == 1) { - WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, - upper_32_bits(rdev->mc.vram_start)); - WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, - upper_32_bits(rdev->mc.vram_start)); - } else { - WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, - upper_32_bits(rdev->mc.vram_start)); - WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, - upper_32_bits(rdev->mc.vram_start)); + if (rdev->family >= CHIP_R600) { + if (save->crtc_enabled[i] && + (save->mc_fb_location != mc_fb_location)) { + if (save->crtc_mc_paddr[i]) + save->crtc_mc_paddr[i] -= save->mc_fb_location; + save->crtc_mc_paddr[i] += mc_fb_location; + if (save->crtc_mc_saddr[i]) + save->crtc_mc_saddr[i] -= save->mc_fb_location; + save->crtc_mc_saddr[i] += mc_fb_location; + if (rdev->family >= CHIP_RV770) { + if (i == 0) { + WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, + upper_32_bits(save->crtc_mc_paddr[i])); + WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, + upper_32_bits(save->crtc_mc_saddr[i])); + } else { + WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, + upper_32_bits(save->crtc_mc_paddr[i])); + WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, + upper_32_bits(save->crtc_mc_saddr[i])); + } + } + WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], + save->crtc_mc_paddr[i]); + WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], + save->crtc_mc_saddr[i]); } + } else { + WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], + rdev->mc.vram_start); + WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], + rdev->mc.vram_start); } - WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], - (u32)rdev->mc.vram_start); - WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], - (u32)rdev->mc.vram_start); } WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index d63fe1d..4b3dc2e 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -264,6 +264,7 @@ static void rv770_agp_enable(struct radeon_device *rdev) static void rv770_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; + u32 mc_vm_fb_location = RREG32(MC_VM_FB_LOCATION); u32 tmp; int i, j; @@ -310,7 +311,8 @@ static void rv770_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); - WREG32(MC_VM_FB_LOCATION, tmp); + if (tmp != mc_vm_fb_location) + WREG32(MC_VM_FB_LOCATION, tmp); WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); WREG32(HDP_NONSURFACE_INFO, (2 << 7)); WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF); @@ -861,7 +863,9 @@ void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->mc_vram_size >> 20, mc->vram_start, mc->vram_end, mc->real_vram_size >> 20); } else { - radeon_vram_location(rdev, &rdev->mc, 0); + u64 base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; + base <<= 24; + radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index bafbe32..a6e0506 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2493,6 +2493,7 @@ bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) static void si_mc_program(struct radeon_device *rdev) { struct evergreen_mc_save save; + u32 mc_vm_fb_location = RREG32(MC_VM_FB_LOCATION); u32 tmp; int i, j; @@ -2521,7 +2522,8 @@ static void si_mc_program(struct radeon_device *rdev) rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); - WREG32(MC_VM_FB_LOCATION, tmp); + if (tmp != mc_vm_fb_location) + WREG32(MC_VM_FB_LOCATION, tmp); /* XXX double check these! */ WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30)); @@ -2538,58 +2540,20 @@ static void si_mc_program(struct radeon_device *rdev) rv515_vga_render_disable(rdev); } -/* SI MC address space is 40 bits */ -static void si_vram_location(struct radeon_device *rdev, - struct radeon_mc *mc, u64 base) -{ - mc->vram_start = base; - if (mc->mc_vram_size > (0xFFFFFFFFFFULL - base + 1)) { - dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); - mc->real_vram_size = mc->aper_size; - mc->mc_vram_size = mc->aper_size; - } - mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", - mc->mc_vram_size >> 20, mc->vram_start, - mc->vram_end, mc->real_vram_size >> 20); -} - -static void si_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) -{ - u64 size_af, size_bf; - - size_af = ((0xFFFFFFFFFFULL - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align; - size_bf = mc->vram_start & ~mc->gtt_base_align; - if (size_bf > size_af) { - if (mc->gtt_size > size_bf) { - dev_warn(rdev->dev, "limiting GTT\n"); - mc->gtt_size = size_bf; - } - mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size; - } else { - if (mc->gtt_size > size_af) { - dev_warn(rdev->dev, "limiting GTT\n"); - mc->gtt_size = size_af; - } - mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; - } - mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; - dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", - mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); -} - static void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { + u64 base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; + base <<= 24; if (mc->mc_vram_size > 0xFFC0000000ULL) { /* leave room for at least 1024M GTT */ dev_warn(rdev->dev, "limiting VRAM\n"); mc->real_vram_size = 0xFFC0000000ULL; mc->mc_vram_size = 0xFFC0000000ULL; } - si_vram_location(rdev, &rdev->mc, 0); + radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; - si_gtt_location(rdev, mc); + radeon_gtt_location(rdev, mc); } static int si_mc_init(struct radeon_device *rdev) -- 1.7.7.5