From 4a15903db02026728d0cf2755c6fabae16b8db6a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:13:53 -0400 Subject: [PATCH 01/79] drm/radeon/dce4+: don't use radeon_crtc for vblank callback This might be called before we've allocated the radeon_crtcs Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e93b80a6d4e9..0c79d9eb2ce4 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -37,6 +37,16 @@ #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 +static const u32 crtc_offsets[6] = +{ + EVERGREEN_CRTC0_REGISTER_OFFSET, + EVERGREEN_CRTC1_REGISTER_OFFSET, + EVERGREEN_CRTC2_REGISTER_OFFSET, + EVERGREEN_CRTC3_REGISTER_OFFSET, + EVERGREEN_CRTC4_REGISTER_OFFSET, + EVERGREEN_CRTC5_REGISTER_OFFSET +}; + static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); void evergreen_pcie_gen2_enable(struct radeon_device *rdev); @@ -109,17 +119,19 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) */ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; int i; - if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) { + if (crtc >= rdev->num_crtc) + return; + + if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) { for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)) + if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)) break; udelay(1); } for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK) + if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) break; udelay(1); } From 46437057bd2a178b12d3a55bac06cbbd46eea4be Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:10:32 -0400 Subject: [PATCH 02/79] drm/radeon: clean up evergreen_get_vblank_counter Use the new offset array rather than open coding it. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0c79d9eb2ce4..585c11741d02 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2345,22 +2345,10 @@ int evergreen_asic_reset(struct radeon_device *rdev) u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc) { - switch (crtc) { - case 0: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC0_REGISTER_OFFSET); - case 1: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC1_REGISTER_OFFSET); - case 2: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC2_REGISTER_OFFSET); - case 3: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC3_REGISTER_OFFSET); - case 4: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC4_REGISTER_OFFSET); - case 5: - return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC5_REGISTER_OFFSET); - default: + if (crtc >= rdev->num_crtc) return 0; - } + else + return RREG32(CRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]); } void evergreen_disable_interrupt_state(struct radeon_device *rdev) From 94f768fd7458e5e8372b8b7565b594284afb6b89 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 16:58:30 -0400 Subject: [PATCH 03/79] drm/radeon/r1xx-r4xx: don't use radeon_crtc for vblank callback This might be called before we've allocated the radeon_crtcs Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8d7e33a0b243..163c33e1a1d6 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -80,10 +80,12 @@ MODULE_FIRMWARE(FIRMWARE_R520); */ void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; int i; - if (radeon_crtc->crtc_id == 0) { + if (crtc >= rdev->num_crtc) + return; + + if (crtc == 0) { if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) { for (i = 0; i < rdev->usec_timeout; i++) { if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)) From 75104fa4f98cdac5e97be5cb59463d49eb08da85 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:06:28 -0400 Subject: [PATCH 04/79] drm/radeon/r5xx-r7xx: don't use radeon_crtc for vblank callback (v2) This might be called before we've allocated the radeon_crtcs v2: fix typo in array size Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/rs600.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 5301b3df8466..31b84b6672b7 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -46,19 +46,27 @@ void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); +static const u32 crtc_offsets[2] = +{ + 0, + AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL +}; + void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; int i; - if (RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset) & AVIVO_CRTC_EN) { + if (crtc >= rdev->num_crtc) + return; + + if (RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN) { for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK)) + if (!(RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)) break; udelay(1); } for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK) + if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) break; udelay(1); } From 62444b7462a2b98bc78d68736c03a7c4e66ba7e2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Aug 2012 17:18:42 -0400 Subject: [PATCH 05/79] drm/radeon: properly handle mc_stop/mc_resume on evergreen+ (v2) - Stop the displays from accessing the FB - Block CPU access - Turn off MC client access This should fix issues some users have seen, especially with UEFI, when changing the MC FB location that result in hangs or display corruption. v2: fix crtc enabled check noticed by Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 169 ++++++++++++------------- drivers/gpu/drm/radeon/evergreen_reg.h | 2 + drivers/gpu/drm/radeon/evergreend.h | 7 + drivers/gpu/drm/radeon/radeon_asic.h | 1 + 4 files changed, 88 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 585c11741d02..bea39e7d9a51 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1241,116 +1241,103 @@ void evergreen_agp_enable(struct radeon_device *rdev) void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) { + u32 crtc_enabled, tmp, frame_count, blackout; + int i, j; + save->vga_render_control = RREG32(VGA_RENDER_CONTROL); save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); - /* Stop all video */ + /* disable VGA render */ WREG32(VGA_RENDER_CONTROL, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); - } - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); - } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + /* 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; + if (crtc_enabled) { + save->crtc_enabled[i] = true; + if (ASIC_IS_DCE6(rdev)) { + tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { + radeon_wait_for_vblank(rdev, i); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + } + } else { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { + radeon_wait_for_vblank(rdev, i); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + } + } + /* wait for the next frame */ + frame_count = radeon_get_vblank_counter(rdev, i); + for (j = 0; j < rdev->usec_timeout; j++) { + if (radeon_get_vblank_counter(rdev, i) != frame_count) + break; + udelay(1); + } + } } - WREG32(D1VGA_CONTROL, 0); - WREG32(D2VGA_CONTROL, 0); - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_D3VGA_CONTROL, 0); - WREG32(EVERGREEN_D4VGA_CONTROL, 0); - } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_D5VGA_CONTROL, 0); - WREG32(EVERGREEN_D6VGA_CONTROL, 0); + radeon_mc_wait_for_idle(rdev); + + blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); + if ((blackout & BLACKOUT_MODE_MASK) != 1) { + /* Block CPU access */ + WREG32(BIF_FB_EN, 0); + /* blackout the MC */ + blackout &= ~BLACKOUT_MODE_MASK; + WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); } } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); + u32 tmp, frame_count; + int i, j; - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - if (rdev->num_crtc >= 4) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, + /* 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 + EVERGREEN_CRTC2_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i], upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i], (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], (u32)rdev->mc.vram_start); } - if (rdev->num_crtc >= 6) { - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - } - 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); - /* Unlock host access */ + + /* unblackout the MC */ + tmp = RREG32(MC_SHARED_BLACKOUT_CNTL); + tmp &= ~BLACKOUT_MODE_MASK; + WREG32(MC_SHARED_BLACKOUT_CNTL, tmp); + /* allow CPU access */ + WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN); + + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled) { + if (ASIC_IS_DCE6(rdev)) { + tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + } else { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + } + /* wait for the next frame */ + frame_count = radeon_get_vblank_counter(rdev, i); + for (j = 0; j < rdev->usec_timeout; j++) { + if (radeon_get_vblank_counter(rdev, i) != frame_count) + break; + udelay(1); + } + } + } + /* Unlock vga access */ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); mdelay(1); WREG32(VGA_RENDER_CONTROL, save->vga_render_control); diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 8beac1065025..034f4c22e5db 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -218,6 +218,8 @@ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) +#define EVERGREEN_CRTC_BLANK_CONTROL 0x6e74 +# define EVERGREEN_CRTC_BLANK_DATA_EN (1 << 8) #define EVERGREEN_CRTC_STATUS 0x6e8c # define EVERGREEN_CRTC_V_BLANK (1 << 0) #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 79347855d9bf..df542f1a5dfb 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -87,6 +87,10 @@ #define CONFIG_MEMSIZE 0x5428 +#define BIF_FB_EN 0x5490 +#define FB_READ_EN (1 << 0) +#define FB_WRITE_EN (1 << 1) + #define CP_COHER_BASE 0x85F8 #define CP_STALLED_STAT1 0x8674 #define CP_STALLED_STAT2 0x8678 @@ -430,6 +434,9 @@ #define NOOFCHAN_MASK 0x00003000 #define MC_SHARED_CHREMAP 0x2008 +#define MC_SHARED_BLACKOUT_CNTL 0x20ac +#define BLACKOUT_MODE_MASK 0x00000007 + #define MC_ARB_RAMCFG 0x2760 #define NOOFBANK_SHIFT 0 #define NOOFBANK_MASK 0x00000003 diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 18c38d14c8cd..132429e0cccd 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -389,6 +389,7 @@ void r700_cp_fini(struct radeon_device *rdev); struct evergreen_mc_save { u32 vga_render_control; u32 vga_hdp_control; + bool crtc_enabled[RADEON_MAX_CRTCS]; }; void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); From 95f5a3acfaf6f5672420398e01ca32220b36bb90 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 10 Aug 2012 13:12:08 -0400 Subject: [PATCH 06/79] drm/radeon/dynpm: wait for fences on all rings when reclocking 1. Drop gui idle stuff, it's not as reliable as fences and only covers the 3D engine. 2. Wait for fences on all rings. This makes sure all rings are idle when reclocking. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_pm.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 7ae606600107..2c2c901226f4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -253,18 +253,13 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) down_write(&rdev->pm.mclk_lock); mutex_lock(&rdev->ring_lock); - /* gui idle int has issues on older chips it seems */ - if (rdev->family >= CHIP_R600) { - if (rdev->irq.installed) { - /* wait for GPU to become idle */ - radeon_irq_kms_wait_gui_idle(rdev); - } - } else { - struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; - if (ring->ready) { - radeon_fence_wait_empty_locked(rdev, RADEON_RING_TYPE_GFX_INDEX); - } + /* wait for the rings to drain */ + for (i = 0; i < RADEON_NUM_RINGS; i++) { + struct radeon_ring *ring = &rdev->ring[i]; + if (ring->ready) + radeon_fence_wait_empty_locked(rdev, i); } + radeon_unmap_vram_bos(rdev); if (rdev->irq.installed) { From ee93b86be118dcdec1a8e29983ed1d010c71bfee Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 10 Aug 2012 13:26:24 -0400 Subject: [PATCH 07/79] drm/radeon: remove gui_idle interrupt infrastructure It was only used for dynpm, but has been replaced with a better implementation using fences. Remove it. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 5 ---- drivers/gpu/drm/radeon/r100.c | 19 -------------- drivers/gpu/drm/radeon/r600.c | 5 ---- drivers/gpu/drm/radeon/radeon.h | 4 --- drivers/gpu/drm/radeon/radeon_device.c | 1 - drivers/gpu/drm/radeon/radeon_irq_kms.c | 33 ------------------------- drivers/gpu/drm/radeon/rs600.c | 19 -------------- drivers/gpu/drm/radeon/si.c | 5 ---- 8 files changed, 91 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index bea39e7d9a51..90366e309495 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2528,10 +2528,6 @@ int evergreen_irq_set(struct radeon_device *rdev) DRM_DEBUG("evergreen_irq_set: hdmi 5\n"); afmt6 |= AFMT_AZ_FORMAT_WTRIG_MASK; } - if (rdev->irq.gui_idle) { - DRM_DEBUG("gui idle\n"); - grbm_int_cntl |= GUI_IDLE_INT_ENABLE; - } if (rdev->family >= CHIP_CAYMAN) { cayman_cp_int_cntl_setup(rdev, 0, cp_int_cntl); @@ -3066,7 +3062,6 @@ restart_ih: break; case 233: /* GUI IDLE */ DRM_DEBUG("IH: GUI idle\n"); - wake_up(&rdev->irq.idle_queue); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 163c33e1a1d6..ff3a444836d4 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -700,9 +700,6 @@ int r100_irq_set(struct radeon_device *rdev) if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { tmp |= RADEON_SW_INT_ENABLE; } - if (rdev->irq.gui_idle) { - tmp |= RADEON_GUI_IDLE_MASK; - } if (rdev->irq.crtc_vblank_int[0] || atomic_read(&rdev->irq.pflip[0])) { tmp |= RADEON_CRTC_VBLANK_MASK; @@ -739,12 +736,6 @@ static uint32_t r100_irq_ack(struct radeon_device *rdev) RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; - /* the interrupt works, but the status bit is permanently asserted */ - if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { - if (!rdev->irq.gui_idle_acked) - irq_mask |= RADEON_GUI_IDLE_STAT; - } - if (irqs) { WREG32(RADEON_GEN_INT_STATUS, irqs); } @@ -756,9 +747,6 @@ int r100_irq_process(struct radeon_device *rdev) uint32_t status, msi_rearm; bool queue_hotplug = false; - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; - status = r100_irq_ack(rdev); if (!status) { return IRQ_NONE; @@ -771,11 +759,6 @@ int r100_irq_process(struct radeon_device *rdev) if (status & RADEON_SW_INT_TEST) { radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); } - /* gui idle interrupt */ - if (status & RADEON_GUI_IDLE_STAT) { - rdev->irq.gui_idle_acked = true; - wake_up(&rdev->irq.idle_queue); - } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { if (rdev->irq.crtc_vblank_int[0]) { @@ -805,8 +788,6 @@ int r100_irq_process(struct radeon_device *rdev) } status = r100_irq_ack(rdev); } - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; if (queue_hotplug) schedule_work(&rdev->hotplug_work); if (rdev->msi_enabled) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d79c639ae739..459c251991c1 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3088,10 +3088,6 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hdmi 0\n"); hdmi1 |= HDMI0_AZ_FORMAT_WTRIG_MASK; } - if (rdev->irq.gui_idle) { - DRM_DEBUG("gui idle\n"); - grbm_int_cntl |= GUI_IDLE_INT_ENABLE; - } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); @@ -3475,7 +3471,6 @@ restart_ih: break; case 233: /* GUI IDLE */ DRM_DEBUG("IH: GUI idle\n"); - wake_up(&rdev->irq.idle_queue); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 59a15315ae9f..5dbd591818fe 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -566,9 +566,6 @@ struct radeon_irq { atomic_t pflip[RADEON_MAX_CRTCS]; wait_queue_head_t vblank_queue; bool hpd[RADEON_MAX_HPD_PINS]; - bool gui_idle; - bool gui_idle_acked; - wait_queue_head_t idle_queue; bool afmt[RADEON_MAX_AFMT_BLOCKS]; union radeon_irq_stat_regs stat_regs; }; @@ -583,7 +580,6 @@ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block); void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block); void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask); void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask); -int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev); /* * CP & rings. diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7a3daebd732d..c78f0346dfe4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1013,7 +1013,6 @@ int radeon_device_init(struct radeon_device *rdev, init_rwsem(&rdev->pm.mclk_lock); init_rwsem(&rdev->exclusive_lock); init_waitqueue_head(&rdev->irq.vblank_queue); - init_waitqueue_head(&rdev->irq.idle_queue); r = radeon_gem_init(rdev); if (r) return r; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index afaa1727abd2..c4e638d6f8af 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -99,7 +99,6 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); - rdev->irq.gui_idle = false; for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; for (i = 0; i < RADEON_MAX_CRTCS; i++) { @@ -147,7 +146,6 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); - rdev->irq.gui_idle = false; for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; for (i = 0; i < RADEON_MAX_CRTCS; i++) { @@ -457,34 +455,3 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask) spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } -/** - * radeon_irq_kms_wait_gui_idle - waits for drawing engine to be idle - * - * @rdev: radeon device pointer - * - * Enabled the GUI idle interrupt and waits for it to fire (r6xx+). - * This is currently used to make sure the 3D engine is idle for power - * management, but should be replaces with proper fence waits. - * GUI idle interrupts don't work very well on pre-r6xx hw and it also - * does not take into account other aspects of the chip that may be busy. - * DO NOT USE GOING FORWARD. - */ -int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev) -{ - unsigned long irqflags; - int r; - - spin_lock_irqsave(&rdev->irq.lock, irqflags); - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - spin_unlock_irqrestore(&rdev->irq.lock, irqflags); - - r = wait_event_timeout(rdev->irq.idle_queue, radeon_gui_idle(rdev), - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - - spin_lock_irqsave(&rdev->irq.lock, irqflags); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); - spin_unlock_irqrestore(&rdev->irq.lock, irqflags); - return r; -} diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 31b84b6672b7..8f7064492e4b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -575,9 +575,6 @@ int rs600_irq_set(struct radeon_device *rdev) if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { tmp |= S_000040_SW_INT_EN(1); } - if (rdev->irq.gui_idle) { - tmp |= S_000040_GUI_IDLE(1); - } if (rdev->irq.crtc_vblank_int[0] || atomic_read(&rdev->irq.pflip[0])) { mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1); @@ -610,12 +607,6 @@ static inline u32 rs600_irq_ack(struct radeon_device *rdev) uint32_t irq_mask = S_000044_SW_INT(1); u32 tmp; - /* the interrupt works, but the status bit is permanently asserted */ - if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { - if (!rdev->irq.gui_idle_acked) - irq_mask |= S_000044_GUI_IDLE_STAT(1); - } - if (G_000044_DISPLAY_INT_STAT(irqs)) { rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { @@ -675,9 +666,6 @@ int rs600_irq_process(struct radeon_device *rdev) bool queue_hotplug = false; bool queue_hdmi = false; - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; - status = rs600_irq_ack(rdev); if (!status && !rdev->irq.stat_regs.r500.disp_int && @@ -691,11 +679,6 @@ int rs600_irq_process(struct radeon_device *rdev) if (G_000044_SW_INT(status)) { radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); } - /* GUI idle */ - if (G_000040_GUI_IDLE(status)) { - rdev->irq.gui_idle_acked = true; - wake_up(&rdev->irq.idle_queue); - } /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { if (rdev->irq.crtc_vblank_int[0]) { @@ -729,8 +712,6 @@ int rs600_irq_process(struct radeon_device *rdev) } status = rs600_irq_ack(rdev); } - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; if (queue_hotplug) schedule_work(&rdev->hotplug_work); if (queue_hdmi) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 0139e227e3c7..3feff33e9d7f 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -3199,10 +3199,6 @@ int si_irq_set(struct radeon_device *rdev) DRM_DEBUG("si_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } - if (rdev->irq.gui_idle) { - DRM_DEBUG("gui idle\n"); - grbm_int_cntl |= GUI_IDLE_INT_ENABLE; - } WREG32(CP_INT_CNTL_RING0, cp_int_cntl); WREG32(CP_INT_CNTL_RING1, cp_int_cntl1); @@ -3658,7 +3654,6 @@ restart_ih: break; case 233: /* GUI IDLE */ DRM_DEBUG("IH: GUI idle\n"); - wake_up(&rdev->irq.idle_queue); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); From 7ff64fcaa7b7ba62d12758e49643f31dd9e90ece Mon Sep 17 00:00:00 2001 From: Steven Fuerst Date: Wed, 15 Aug 2012 15:07:14 -0700 Subject: [PATCH 08/79] Rename i2f() to int2float(), and make it global so one copy can be removed. Remove the copy of i2f() in r600_blit_kms.c We rename the function to something longer now that it is a global symbol. This reduces the likelyhood of unintended clashes later. This might be a candidate for inclusion inside general drm infrastructure. However, at the moment only the radeon driver uses it. Signed-off-by: Steven Fuerst --- drivers/gpu/drm/radeon/r600_blit.c | 66 +++++++++++----------- drivers/gpu/drm/radeon/r600_blit_kms.c | 52 ++--------------- drivers/gpu/drm/radeon/r600_blit_shaders.h | 1 + 3 files changed, 40 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index 3c031a48205d..ee1b815b5689 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -489,7 +489,7 @@ set_default_state(drm_radeon_private_t *dev_priv) ADVANCE_RING(); } -static uint32_t i2f(uint32_t input) +uint32_t int2float(uint32_t input) { u32 result, i, exponent, fraction; @@ -632,20 +632,20 @@ r600_blit_copy(struct drm_device *dev, vb = r600_nomm_get_vb_ptr(dev); } - vb[0] = i2f(dst_x); + vb[0] = int2float(dst_x); vb[1] = 0; - vb[2] = i2f(src_x); + vb[2] = int2float(src_x); vb[3] = 0; - vb[4] = i2f(dst_x); - vb[5] = i2f(h); - vb[6] = i2f(src_x); - vb[7] = i2f(h); + vb[4] = int2float(dst_x); + vb[5] = int2float(h); + vb[6] = int2float(src_x); + vb[7] = int2float(h); - vb[8] = i2f(dst_x + cur_size); - vb[9] = i2f(h); - vb[10] = i2f(src_x + cur_size); - vb[11] = i2f(h); + vb[8] = int2float(dst_x + cur_size); + vb[9] = int2float(h); + vb[10] = int2float(src_x + cur_size); + vb[11] = int2float(h); /* src */ set_tex_resource(dev_priv, FMT_8, @@ -721,20 +721,20 @@ r600_blit_copy(struct drm_device *dev, vb = r600_nomm_get_vb_ptr(dev); } - vb[0] = i2f(dst_x / 4); + vb[0] = int2float(dst_x / 4); vb[1] = 0; - vb[2] = i2f(src_x / 4); + vb[2] = int2float(src_x / 4); vb[3] = 0; - vb[4] = i2f(dst_x / 4); - vb[5] = i2f(h); - vb[6] = i2f(src_x / 4); - vb[7] = i2f(h); + vb[4] = int2float(dst_x / 4); + vb[5] = int2float(h); + vb[6] = int2float(src_x / 4); + vb[7] = int2float(h); - vb[8] = i2f((dst_x + cur_size) / 4); - vb[9] = i2f(h); - vb[10] = i2f((src_x + cur_size) / 4); - vb[11] = i2f(h); + vb[8] = int2float((dst_x + cur_size) / 4); + vb[9] = int2float(h); + vb[10] = int2float((src_x + cur_size) / 4); + vb[11] = int2float(h); /* src */ set_tex_resource(dev_priv, FMT_8_8_8_8, @@ -804,20 +804,20 @@ r600_blit_swap(struct drm_device *dev, dx2 = dx + w; dy2 = dy + h; - vb[0] = i2f(dx); - vb[1] = i2f(dy); - vb[2] = i2f(sx); - vb[3] = i2f(sy); + vb[0] = int2float(dx); + vb[1] = int2float(dy); + vb[2] = int2float(sx); + vb[3] = int2float(sy); - vb[4] = i2f(dx); - vb[5] = i2f(dy2); - vb[6] = i2f(sx); - vb[7] = i2f(sy2); + vb[4] = int2float(dx); + vb[5] = int2float(dy2); + vb[6] = int2float(sx); + vb[7] = int2float(sy2); - vb[8] = i2f(dx2); - vb[9] = i2f(dy2); - vb[10] = i2f(sx2); - vb[11] = i2f(sy2); + vb[8] = int2float(dx2); + vb[9] = int2float(dy2); + vb[10] = int2float(sx2); + vb[11] = int2float(sy2); switch(cpp) { case 4: diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 2bef8549ddfe..1c7ed3a5d045 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -455,46 +455,6 @@ set_default_state(struct radeon_device *rdev) radeon_ring_write(ring, sq_stack_resource_mgmt_2); } -#define I2F_MAX_BITS 15 -#define I2F_MAX_INPUT ((1 << I2F_MAX_BITS) - 1) -#define I2F_SHIFT (24 - I2F_MAX_BITS) - -/* - * Converts unsigned integer into 32-bit IEEE floating point representation. - * Conversion is not universal and only works for the range from 0 - * to 2^I2F_MAX_BITS-1. Currently we only use it with inputs between - * 0 and 16384 (inclusive), so I2F_MAX_BITS=15 is enough. If necessary, - * I2F_MAX_BITS can be increased, but that will add to the loop iterations - * and slow us down. Conversion is done by shifting the input and counting - * down until the first 1 reaches bit position 23. The resulting counter - * and the shifted input are, respectively, the exponent and the fraction. - * The sign is always zero. - */ -static uint32_t i2f(uint32_t input) -{ - u32 result, i, exponent, fraction; - - WARN_ON_ONCE(input > I2F_MAX_INPUT); - - if ((input & I2F_MAX_INPUT) == 0) - result = 0; - else { - exponent = 126 + I2F_MAX_BITS; - fraction = (input & I2F_MAX_INPUT) << I2F_SHIFT; - - for (i = 0; i < I2F_MAX_BITS; i++) { - if (fraction & 0x800000) - break; - else { - fraction = fraction << 1; - exponent = exponent - 1; - } - } - result = exponent << 23 | (fraction & 0x7fffff); - } - return result; -} - int r600_blit_init(struct radeon_device *rdev) { u32 obj_size; @@ -766,14 +726,14 @@ void r600_kms_blit_copy(struct radeon_device *rdev, vb_cpu_addr[3] = 0; vb_cpu_addr[4] = 0; - vb_cpu_addr[5] = i2f(h); + vb_cpu_addr[5] = int2float(h); vb_cpu_addr[6] = 0; - vb_cpu_addr[7] = i2f(h); + vb_cpu_addr[7] = int2float(h); - vb_cpu_addr[8] = i2f(w); - vb_cpu_addr[9] = i2f(h); - vb_cpu_addr[10] = i2f(w); - vb_cpu_addr[11] = i2f(h); + vb_cpu_addr[8] = int2float(w); + vb_cpu_addr[9] = int2float(h); + vb_cpu_addr[10] = int2float(w); + vb_cpu_addr[11] = int2float(h); rdev->r600_blit.primitives.set_tex_resource(rdev, FMT_8_8_8_8, w, h, w, src_gpu_addr, size_in_bytes); diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.h b/drivers/gpu/drm/radeon/r600_blit_shaders.h index f437d36dd98c..e17c2cbc6627 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.h +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.h @@ -35,4 +35,5 @@ extern const u32 r6xx_default_state[]; extern const u32 r6xx_ps_size, r6xx_vs_size; extern const u32 r6xx_default_size, r7xx_default_size; +uint32_t int2float(uint32_t x); #endif From 747f49ba67b8895a5831ab539de551b916f3738c Mon Sep 17 00:00:00 2001 From: Steven Fuerst Date: Wed, 15 Aug 2012 15:07:15 -0700 Subject: [PATCH 09/79] Replace int2float() with an optimized version. We use __fls() to find the most significant bit. Using that, the loop can be avoided. A second trick is to use the behaviour of the rotate instructions to expand the range of the unsigned int to float conversion to the full 32 bits in a branchless way. The routine is now exact up to 2^24. Above that, we truncate which is equivalent to rounding towards zero. Signed-off-by: Steven Fuerst --- drivers/gpu/drm/radeon/r600_blit.c | 49 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index ee1b815b5689..7d8ac42e3846 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -489,32 +489,37 @@ set_default_state(drm_radeon_private_t *dev_priv) ADVANCE_RING(); } -uint32_t int2float(uint32_t input) +/* 23 bits of float fractional data */ +#define I2F_FRAC_BITS 23 +#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1) + +/* + * Converts unsigned integer into 32-bit IEEE floating point representation. + * Will be exact from 0 to 2^24. Above that, we round towards zero + * as the fractional bits will not fit in a float. (It would be better to + * round towards even as the fpu does, but that is slower.) + */ +uint32_t int2float(uint32_t x) { - u32 result, i, exponent, fraction; + uint32_t msb, exponent, fraction; - if ((input & 0x3fff) == 0) - result = 0; /* 0 is a special case */ - else { - exponent = 140; /* exponent biased by 127; */ - fraction = (input & 0x3fff) << 10; /* cheat and only - handle numbers below 2^^15 */ - for (i = 0; i < 14; i++) { - if (fraction & 0x800000) - break; - else { - fraction = fraction << 1; /* keep - shifting left until top bit = 1 */ - exponent = exponent - 1; - } - } - result = exponent << 23 | (fraction & 0x7fffff); /* mask - off top bit; assumed 1 */ - } - return result; + /* Zero is special */ + if (!x) return 0; + + /* Get location of the most significant bit */ + msb = __fls(x); + + /* + * Use a rotate instead of a shift because that works both leftwards + * and rightwards due to the mod(32) behaviour. This means we don't + * need to check to see if we are above 2^24 or not. + */ + fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK; + exponent = (127 + msb) << I2F_FRAC_BITS; + + return fraction + exponent; } - static int r600_nomm_get_vb(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; From 9e9eb7c60d57620bfe46b2a489e7f56a5925115a Mon Sep 17 00:00:00 2001 From: Steven Fuerst Date: Wed, 15 Aug 2012 15:07:16 -0700 Subject: [PATCH 10/79] Annotate int2float() as being a pure function. This allows gcc to fold duplicate calls into a single call. Since the current users do actually call it multiple times with the same arguments, this is an obvious win. Signed-off-by: Steven Fuerst --- drivers/gpu/drm/radeon/r600_blit.c | 2 +- drivers/gpu/drm/radeon/r600_blit_shaders.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index 7d8ac42e3846..661fec2a2cc1 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -499,7 +499,7 @@ set_default_state(drm_radeon_private_t *dev_priv) * as the fractional bits will not fit in a float. (It would be better to * round towards even as the fpu does, but that is slower.) */ -uint32_t int2float(uint32_t x) +__pure uint32_t int2float(uint32_t x) { uint32_t msb, exponent, fraction; diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.h b/drivers/gpu/drm/radeon/r600_blit_shaders.h index e17c2cbc6627..2f3ce7a75976 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.h +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.h @@ -35,5 +35,5 @@ extern const u32 r6xx_default_state[]; extern const u32 r6xx_ps_size, r6xx_vs_size; extern const u32 r6xx_default_size, r7xx_default_size; -uint32_t int2float(uint32_t x); +__pure uint32_t int2float(uint32_t x); #endif From 9e05b2f49eb9484e857e9b6c70dea3bbbe564290 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 18 Jul 2012 13:28:52 -0400 Subject: [PATCH 11/79] drm/radeon: add new AMD ACPI header and update relevant code (v2) Add a new header that defines the AMD ACPI interface used for laptops, PowerXpress, and chipset specific functionality and update the current code to use it. Todo: - properly verify the ACPI interfaces - hook up and handle ACPI notifications - make PX code more robust - implement PCIe Gen and width switching using ACPI v2: fix typo in header Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 3 +- drivers/gpu/drm/radeon/radeon_acpi.h | 439 +++++++++++++++++++ drivers/gpu/drm/radeon/radeon_atpx_handler.c | 35 +- 3 files changed, 455 insertions(+), 22 deletions(-) create mode 100644 drivers/gpu/drm/radeon/radeon_acpi.h diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 3516a6081dcf..5b32e499903b 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -9,6 +9,7 @@ #include "drm_sarea.h" #include "drm_crtc_helper.h" #include "radeon.h" +#include "radeon_acpi.h" #include @@ -27,7 +28,7 @@ static int radeon_atif_call(acpi_handle handle) atif_arg.pointer = &atif_arg_elements[0]; atif_arg_elements[0].type = ACPI_TYPE_INTEGER; - atif_arg_elements[0].integer.value = 0; + atif_arg_elements[0].integer.value = ATIF_FUNCTION_VERIFY_INTERFACE; atif_arg_elements[1].type = ACPI_TYPE_INTEGER; atif_arg_elements[1].integer.value = 0; diff --git a/drivers/gpu/drm/radeon/radeon_acpi.h b/drivers/gpu/drm/radeon/radeon_acpi.h new file mode 100644 index 000000000000..642aa4719454 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_acpi.h @@ -0,0 +1,439 @@ +/* + * Copyright 2012 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef RADEON_ACPI_H +#define RADEON_ACPI_H + +/* AMD hw uses four ACPI control methods: + * 1. ATIF + * ARG0: (ACPI_INTEGER) function code + * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes + * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes + * ATIF provides an entry point for the gfx driver to interact with the sbios. + * The AMD ACPI notification mechanism uses Notify (VGA, 0x81) or a custom + * notification. Which notification is used as indicated by the ATIF Control + * Method GET_SYSTEM_PARAMETERS. When the driver receives Notify (VGA, 0x81) or + * a custom notification it invokes ATIF Control Method GET_SYSTEM_BIOS_REQUESTS + * to identify pending System BIOS requests and associated parameters. For + * example, if one of the pending requests is DISPLAY_SWITCH_REQUEST, the driver + * will perform display device detection and invoke ATIF Control Method + * SELECT_ACTIVE_DISPLAYS. + * + * 2. ATPX + * ARG0: (ACPI_INTEGER) function code + * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes + * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes + * ATPX methods are used on PowerXpress systems to handle mux switching and + * discrete GPU power control. + * + * 3. ATRM + * ARG0: (ACPI_INTEGER) offset of vbios rom data + * ARG1: (ACPI_BUFFER) size of the buffer to fill (up to 4K). + * OUTPUT: (ACPI_BUFFER) output buffer + * ATRM provides an interfacess to access the discrete GPU vbios image on + * PowerXpress systems with multiple GPUs. + * + * 4. ATCS + * ARG0: (ACPI_INTEGER) function code + * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes + * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes + * ATCS provides an interface to AMD chipset specific functionality. + * + */ +/* ATIF */ +#define ATIF_FUNCTION_VERIFY_INTERFACE 0x0 +/* ARG0: ATIF_FUNCTION_VERIFY_INTERFACE + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * WORD - version + * DWORD - supported notifications mask + * DWORD - supported functions bit vector + */ +/* Notifications mask */ +# define ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED (1 << 0) +# define ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED (1 << 1) +# define ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED (1 << 2) +# define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED (1 << 3) +# define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED (1 << 4) +# define ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED (1 << 5) +# define ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED (1 << 6) +# define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED (1 << 7) +# define ATIF_DGPU_DISPLAY_EVENT_SUPPORTED (1 << 8) +/* supported functions vector */ +# define ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED (1 << 0) +# define ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED (1 << 1) +# define ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED (1 << 2) +# define ATIF_GET_LID_STATE_SUPPORTED (1 << 3) +# define ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED (1 << 4) +# define ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED (1 << 5) +# define ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED (1 << 6) +# define ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED (1 << 7) +# define ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED (1 << 12) +# define ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED (1 << 14) +#define ATIF_FUNCTION_GET_SYSTEM_PARAMETERS 0x1 +/* ARG0: ATIF_FUNCTION_GET_SYSTEM_PARAMETERS + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * DWORD - valid flags mask + * DWORD - flags + * + * OR + * + * WORD - structure size in bytes (includes size field) + * DWORD - valid flags mask + * DWORD - flags + * BYTE - notify command code + * + * flags + * bits 1:0: + * 0 - Notify(VGA, 0x81) is not used for notification + * 1 - Notify(VGA, 0x81) is used for notification + * 2 - Notify(VGA, n) is used for notification where + * n (0xd0-0xd9) is specified in notify command code. + * bit 2: + * 1 - lid changes not reported though int10 + */ +#define ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS 0x2 +/* ARG0: ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * DWORD - pending sbios requests + * BYTE - panel expansion mode + * BYTE - thermal state: target gfx controller + * BYTE - thermal state: state id (0: exit state, non-0: state) + * BYTE - forced power state: target gfx controller + * BYTE - forced power state: state id + * BYTE - system power source + * BYTE - panel backlight level (0-255) + */ +/* pending sbios requests */ +# define ATIF_DISPLAY_SWITCH_REQUEST (1 << 0) +# define ATIF_EXPANSION_MODE_CHANGE_REQUEST (1 << 1) +# define ATIF_THERMAL_STATE_CHANGE_REQUEST (1 << 2) +# define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST (1 << 3) +# define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST (1 << 4) +# define ATIF_DISPLAY_CONF_CHANGE_REQUEST (1 << 5) +# define ATIF_PX_GFX_SWITCH_REQUEST (1 << 6) +# define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST (1 << 7) +# define ATIF_DGPU_DISPLAY_EVENT (1 << 8) +/* panel expansion mode */ +# define ATIF_PANEL_EXPANSION_DISABLE 0 +# define ATIF_PANEL_EXPANSION_FULL 1 +# define ATIF_PANEL_EXPANSION_ASPECT 2 +/* target gfx controller */ +# define ATIF_TARGET_GFX_SINGLE 0 +# define ATIF_TARGET_GFX_PX_IGPU 1 +# define ATIF_TARGET_GFX_PX_DGPU 2 +/* system power source */ +# define ATIF_POWER_SOURCE_AC 1 +# define ATIF_POWER_SOURCE_DC 2 +# define ATIF_POWER_SOURCE_RESTRICTED_AC_1 3 +# define ATIF_POWER_SOURCE_RESTRICTED_AC_2 4 +#define ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS 0x3 +/* ARG0: ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - selected displays + * WORD - connected displays + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * WORD - selected displays + */ +# define ATIF_LCD1 (1 << 0) +# define ATIF_CRT1 (1 << 1) +# define ATIF_TV (1 << 2) +# define ATIF_DFP1 (1 << 3) +# define ATIF_CRT2 (1 << 4) +# define ATIF_LCD2 (1 << 5) +# define ATIF_DFP2 (1 << 7) +# define ATIF_CV (1 << 8) +# define ATIF_DFP3 (1 << 9) +# define ATIF_DFP4 (1 << 10) +# define ATIF_DFP5 (1 << 11) +# define ATIF_DFP6 (1 << 12) +#define ATIF_FUNCTION_GET_LID_STATE 0x4 +/* ARG0: ATIF_FUNCTION_GET_LID_STATE + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * BYTE - lid state (0: open, 1: closed) + * + * GET_LID_STATE only works at boot and resume, for general lid + * status, use the kernel provided status + */ +#define ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS 0x5 +/* ARG0: ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * BYTE - 0 + * BYTE - TV standard + */ +# define ATIF_TV_STD_NTSC 0 +# define ATIF_TV_STD_PAL 1 +# define ATIF_TV_STD_PALM 2 +# define ATIF_TV_STD_PAL60 3 +# define ATIF_TV_STD_NTSCJ 4 +# define ATIF_TV_STD_PALCN 5 +# define ATIF_TV_STD_PALN 6 +# define ATIF_TV_STD_SCART_RGB 9 +#define ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS 0x6 +/* ARG0: ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS + * ARG1: + * WORD - structure size in bytes (includes size field) + * BYTE - 0 + * BYTE - TV standard + * OUTPUT: none + */ +#define ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS 0x7 +/* ARG0: ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * BYTE - panel expansion mode + */ +#define ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS 0x8 +/* ARG0: ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS + * ARG1: + * WORD - structure size in bytes (includes size field) + * BYTE - panel expansion mode + * OUTPUT: none + */ +#define ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION 0xD +/* ARG0: ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - gfx controller id + * BYTE - current temperature (degress Celsius) + * OUTPUT: none + */ +#define ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES 0xF +/* ARG0: ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES + * ARG1: none + * OUTPUT: + * WORD - number of gfx devices + * WORD - device structure size in bytes (excludes device size field) + * DWORD - flags \ + * WORD - bus number } repeated structure + * WORD - device number / + */ +/* flags */ +# define ATIF_PX_REMOVABLE_GRAPHICS_DEVICE (1 << 0) +# define ATIF_XGP_PORT (1 << 1) +# define ATIF_VGA_ENABLED_GRAPHICS_DEVICE (1 << 2) +# define ATIF_XGP_PORT_IN_DOCK (1 << 3) + +/* ATPX */ +#define ATPX_FUNCTION_VERIFY_INTERFACE 0x0 +/* ARG0: ATPX_FUNCTION_VERIFY_INTERFACE + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * WORD - version + * DWORD - supported functions bit vector + */ +/* supported functions vector */ +# define ATPX_GET_PX_PARAMETERS_SUPPORTED (1 << 0) +# define ATPX_POWER_CONTROL_SUPPORTED (1 << 1) +# define ATPX_DISPLAY_MUX_CONTROL_SUPPORTED (1 << 2) +# define ATPX_I2C_MUX_CONTROL_SUPPORTED (1 << 3) +# define ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED (1 << 4) +# define ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED (1 << 5) +# define ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED (1 << 7) +# define ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED (1 << 8) +#define ATPX_FUNCTION_GET_PX_PARAMETERS 0x1 +/* ARG0: ATPX_FUNCTION_GET_PX_PARAMETERS + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * DWORD - valid flags mask + * DWORD - flags + */ +/* flags */ +# define ATPX_LVDS_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 0) +# define ATPX_CRT1_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 1) +# define ATPX_DVI1_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 2) +# define ATPX_CRT1_RGB_SIGNAL_MUXED (1 << 3) +# define ATPX_TV_SIGNAL_MUXED (1 << 4) +# define ATPX_DFP_SIGNAL_MUXED (1 << 5) +# define ATPX_SEPARATE_MUX_FOR_I2C (1 << 6) +# define ATPX_DYNAMIC_PX_SUPPORTED (1 << 7) +# define ATPX_ACF_NOT_SUPPORTED (1 << 8) +# define ATPX_FIXED_NOT_SUPPORTED (1 << 9) +# define ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED (1 << 10) +# define ATPX_DGPU_REQ_POWER_FOR_DISPLAYS (1 << 11) +#define ATPX_FUNCTION_POWER_CONTROL 0x2 +/* ARG0: ATPX_FUNCTION_POWER_CONTROL + * ARG1: + * WORD - structure size in bytes (includes size field) + * BYTE - dGPU power state (0: power off, 1: power on) + * OUTPUT: none + */ +#define ATPX_FUNCTION_DISPLAY_MUX_CONTROL 0x3 +/* ARG0: ATPX_FUNCTION_DISPLAY_MUX_CONTROL + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - display mux control (0: iGPU, 1: dGPU) + * OUTPUT: none + */ +# define ATPX_INTEGRATED_GPU 0 +# define ATPX_DISCRETE_GPU 1 +#define ATPX_FUNCTION_I2C_MUX_CONTROL 0x4 +/* ARG0: ATPX_FUNCTION_I2C_MUX_CONTROL + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - i2c/aux/hpd mux control (0: iGPU, 1: dGPU) + * OUTPUT: none + */ +#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION 0x5 +/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - target gpu (0: iGPU, 1: dGPU) + * OUTPUT: none + */ +#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION 0x6 +/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - target gpu (0: iGPU, 1: dGPU) + * OUTPUT: none + */ +#define ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING 0x8 +/* ARG0: ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING + * ARG1: none + * OUTPUT: + * WORD - number of display connectors + * WORD - connector structure size in bytes (excludes connector size field) + * BYTE - flags \ + * BYTE - ATIF display vector bit position } repeated + * BYTE - adapter id (0: iGPU, 1-n: dGPU ordered by pcie bus number) } structure + * WORD - connector ACPI id / + */ +/* flags */ +# define ATPX_DISPLAY_OUTPUT_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 0) +# define ATPX_DISPLAY_HPD_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 1) +# define ATPX_DISPLAY_I2C_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 2) +#define ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS 0x9 +/* ARG0: ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS + * ARG1: none + * OUTPUT: + * WORD - number of HPD/DDC ports + * WORD - port structure size in bytes (excludes port size field) + * BYTE - ATIF display vector bit position \ + * BYTE - hpd id } reapeated structure + * BYTE - ddc id / + * + * available on A+A systems only + */ +/* hpd id */ +# define ATPX_HPD_NONE 0 +# define ATPX_HPD1 1 +# define ATPX_HPD2 2 +# define ATPX_HPD3 3 +# define ATPX_HPD4 4 +# define ATPX_HPD5 5 +# define ATPX_HPD6 6 +/* ddc id */ +# define ATPX_DDC_NONE 0 +# define ATPX_DDC1 1 +# define ATPX_DDC2 2 +# define ATPX_DDC3 3 +# define ATPX_DDC4 4 +# define ATPX_DDC5 5 +# define ATPX_DDC6 6 +# define ATPX_DDC7 7 +# define ATPX_DDC8 8 + +/* ATCS */ +#define ATCS_FUNCTION_VERIFY_INTERFACE 0x0 +/* ARG0: ATCS_FUNCTION_VERIFY_INTERFACE + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * WORD - version + * DWORD - supported functions bit vector + */ +/* supported functions vector */ +# define ATCS_GET_EXTERNAL_STATE_SUPPORTED (1 << 0) +# define ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED (1 << 1) +# define ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED (1 << 2) +# define ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED (1 << 3) +#define ATCS_FUNCTION_GET_EXTERNAL_STATE 0x1 +/* ARG0: ATCS_FUNCTION_GET_EXTERNAL_STATE + * ARG1: none + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * DWORD - valid flags mask + * DWORD - flags (0: undocked, 1: docked) + */ +/* flags */ +# define ATCS_DOCKED (1 << 0) +#define ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST 0x2 +/* ARG0: ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) + * WORD - valid flags mask + * WORD - flags + * BYTE - request type + * BYTE - performance request + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * BYTE - return value + */ +/* flags */ +# define ATCS_ADVERTISE_CAPS (1 << 0) +# define ATCS_WAIT_FOR_COMPLETION (1 << 1) +/* request type */ +# define ATCS_PCIE_LINK_SPEED 1 +/* performance request */ +# define ATCS_REMOVE 0 +# define ATCS_FORCE_LOW_POWER 1 +# define ATCS_PERF_LEVEL_1 2 /* PCIE Gen 1 */ +# define ATCS_PERF_LEVEL_2 3 /* PCIE Gen 2 */ +# define ATCS_PERF_LEVEL_3 4 /* PCIE Gen 3 */ +/* return value */ +# define ATCS_REQUEST_REFUSED 1 +# define ATCS_REQUEST_COMPLETE 2 +# define ATCS_REQUEST_IN_PROGRESS 3 +#define ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION 0x3 +/* ARG0: ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION + * ARG1: none + * OUTPUT: none + */ +#define ATCS_FUNCTION_SET_PCIE_BUS_WIDTH 0x4 +/* ARG0: ATCS_FUNCTION_SET_PCIE_BUS_WIDTH + * ARG1: + * WORD - structure size in bytes (includes size field) + * WORD - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) + * BYTE - number of active lanes + * OUTPUT: + * WORD - structure size in bytes (includes size field) + * BYTE - number of active lanes + */ + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 2a2cf0b88a28..950a1ac95d6a 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -12,18 +12,7 @@ #include #include -#define ATPX_VERSION 0 -#define ATPX_GPU_PWR 2 -#define ATPX_MUX_SELECT 3 -#define ATPX_I2C_MUX_SELECT 4 -#define ATPX_SWITCH_START 5 -#define ATPX_SWITCH_END 6 - -#define ATPX_INTEGRATED 0 -#define ATPX_DISCRETE 1 - -#define ATPX_MUX_IGD 0 -#define ATPX_MUX_DISCRETE 1 +#include "radeon_acpi.h" static struct radeon_atpx_priv { bool atpx_detected; @@ -43,10 +32,10 @@ static int radeon_atpx_get_version(acpi_handle handle) atpx_arg.pointer = &atpx_arg_elements[0]; atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[0].integer.value = ATPX_VERSION; + atpx_arg_elements[0].integer.value = ATPX_FUNCTION_VERIFY_INTERFACE; atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[1].integer.value = ATPX_VERSION; + atpx_arg_elements[1].integer.value = 0; status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); if (ACPI_FAILURE(status)) { @@ -96,27 +85,31 @@ static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value) static int radeon_atpx_set_discrete_state(acpi_handle handle, int state) { - return radeon_atpx_execute(handle, ATPX_GPU_PWR, state); + return radeon_atpx_execute(handle, ATPX_FUNCTION_POWER_CONTROL, state); } static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) { - return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id); + return radeon_atpx_execute(handle, ATPX_FUNCTION_DISPLAY_MUX_CONTROL, mux_id); } static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id) { - return radeon_atpx_execute(handle, ATPX_I2C_MUX_SELECT, mux_id); + return radeon_atpx_execute(handle, ATPX_FUNCTION_I2C_MUX_CONTROL, mux_id); } static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id) { - return radeon_atpx_execute(handle, ATPX_SWITCH_START, gpu_id); + return radeon_atpx_execute(handle, + ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION, + gpu_id); } static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id) { - return radeon_atpx_execute(handle, ATPX_SWITCH_END, gpu_id); + return radeon_atpx_execute(handle, + ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION, + gpu_id); } static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) @@ -124,9 +117,9 @@ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) int gpu_id; if (id == VGA_SWITCHEROO_IGD) - gpu_id = ATPX_INTEGRATED; + gpu_id = ATPX_INTEGRATED_GPU; else - gpu_id = ATPX_DISCRETE; + gpu_id = ATPX_DISCRETE_GPU; radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id); radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id); From efd4e418f2bb8a8b21f96fd44e775eaf6dd55905 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 17:18:17 -0400 Subject: [PATCH 12/79] drm/radeon: add a license header to radeon_apci.c Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 5b32e499903b..e94929c69245 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -1,3 +1,26 @@ +/* + * Copyright 2012 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + #include #include #include From af7912e57316caa1b705f06b03592cec0737cb36 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Jul 2012 09:50:57 -0400 Subject: [PATCH 13/79] drm/radeon: track whether the GPU controls the backlight (v2) A table in the vbios tells us whether the GPU backlight controller is used or not. If the bit is set, the GPU backlight controller is used; if it is not set, an off-chip backlight controller is used. v2: store all the firmware flags, not just BL control Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 4 ++++ drivers/gpu/drm/radeon/radeon_mode.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index d67d4f3eb6f4..e368b3027cba 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1254,6 +1254,10 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) if (rdev->clock.max_pixel_clock == 0) rdev->clock.max_pixel_clock = 40000; + /* not technically a clock, but... */ + rdev->mode_info.firmware_flags = + le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); + return true; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index d56978949f34..806140d32b5d 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -252,6 +252,8 @@ struct radeon_mode_info { /* pointer to fbdev info structure */ struct radeon_fbdev *rfbdev; + /* firmware flags */ + u16 firmware_flags; }; #define MAX_H_CODE_TIMING_LEN 32 From 910308802c528f8afe864b694d5456fedd0bb18f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Jul 2012 11:05:22 -0400 Subject: [PATCH 14/79] drm/radeon: rework legacy backlight control To better enable sharing with atom backlight control. Signed-off-by: Alex Deucher --- .../gpu/drm/radeon/radeon_legacy_encoders.c | 19 ++++++------------- drivers/gpu/drm/radeon/radeon_mode.h | 11 +++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 670e9910f869..9910fe494744 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -271,13 +271,6 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) -#define MAX_RADEON_LEVEL 0xFF - -struct radeon_backlight_privdata { - struct radeon_encoder *encoder; - uint8_t negative; -}; - static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) { struct radeon_backlight_privdata *pdata = bl_get_data(bd); @@ -286,13 +279,13 @@ static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) /* Convert brightness to hardware level */ if (bd->props.brightness < 0) level = 0; - else if (bd->props.brightness > MAX_RADEON_LEVEL) - level = MAX_RADEON_LEVEL; + else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) + level = RADEON_MAX_BL_LEVEL; else level = bd->props.brightness; if (pdata->negative) - level = MAX_RADEON_LEVEL - level; + level = RADEON_MAX_BL_LEVEL - level; return level; } @@ -336,7 +329,7 @@ static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd) backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; - return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level; + return pdata->negative ? RADEON_MAX_BL_LEVEL - backlight_level : backlight_level; } static const struct backlight_ops radeon_backlight_ops = { @@ -370,7 +363,7 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, } memset(&props, 0, sizeof(props)); - props.max_brightness = MAX_RADEON_LEVEL; + props.max_brightness = RADEON_MAX_BL_LEVEL; props.type = BACKLIGHT_RAW; bd = backlight_device_register("radeon_bl", &drm_connector->kdev, pdata, &radeon_backlight_ops, &props); @@ -449,7 +442,7 @@ static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder) } if (bd) { - struct radeon_legacy_backlight_privdata *pdata; + struct radeon_backlight_privdata *pdata; pdata = bl_get_data(bd); backlight_device_unregister(bd); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 806140d32b5d..5005057974b1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -256,6 +256,17 @@ struct radeon_mode_info { u16 firmware_flags; }; +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) + +#define RADEON_MAX_BL_LEVEL 0xFF + +struct radeon_backlight_privdata { + struct radeon_encoder *encoder; + uint8_t negative; +}; + +#endif + #define MAX_H_CODE_TIMING_LEN 32 #define MAX_V_CODE_TIMING_LEN 32 From f3728734ba78310525bf4a361c7787c7c6fa5d40 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Jul 2012 11:32:03 -0400 Subject: [PATCH 15/79] drm/radeon: add backlight control for atom devices (v2) On systems that use the build in GPU backlight controller, we can use atom tables to change the brightness level. v2: use firmware flags Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 231 +++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_connectors.c | 15 -- drivers/gpu/drm/radeon/radeon_encoders.c | 18 +- 3 files changed, 248 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 6e8803a1170c..f3645e15ef11 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -28,9 +28,238 @@ #include "radeon_drm.h" #include "radeon.h" #include "atom.h" +#include extern int atom_debug; +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) + +static u8 +radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev) +{ + u8 backlight_level; + u32 bios_2_scratch; + + if (rdev->family >= CHIP_R600) + bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); + else + bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); + + backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >> + ATOM_S2_CURRENT_BL_LEVEL_SHIFT); + + return backlight_level; +} + +static void +radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, + u8 backlight_level) +{ + u32 bios_2_scratch; + + if (rdev->family >= CHIP_R600) + bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); + else + bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); + + bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; + bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) & + ATOM_S2_CURRENT_BL_LEVEL_MASK); + + if (rdev->family >= CHIP_R600) + WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); + else + WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); +} + +static void +atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) +{ + struct drm_encoder *encoder = &radeon_encoder->base; + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder_atom_dig *dig; + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + int index; + + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + dig = radeon_encoder->enc_priv; + radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + if (dig->backlight_level == 0) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } else { + args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->backlight_level == 0) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); + else { + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + } + break; + default: + break; + } + } +} + +static u8 radeon_atom_bl_level(struct backlight_device *bd) +{ + u8 level; + + /* Convert brightness to hardware level */ + if (bd->props.brightness < 0) + level = 0; + else if (bd->props.brightness > RADEON_MAX_BL_LEVEL) + level = RADEON_MAX_BL_LEVEL; + else + level = bd->props.brightness; + + return level; +} + +static int radeon_atom_backlight_update_status(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + dig->backlight_level = radeon_atom_bl_level(bd); + atombios_set_panel_brightness(radeon_encoder); + } + + return 0; +} + +static int radeon_atom_backlight_get_brightness(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + + return radeon_atom_get_backlight_level_from_reg(rdev); +} + +static const struct backlight_ops radeon_atom_backlight_ops = { + .get_brightness = radeon_atom_backlight_get_brightness, + .update_status = radeon_atom_backlight_update_status, +}; + +void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, + struct drm_connector *drm_connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct backlight_device *bd; + struct backlight_properties props; + struct radeon_backlight_privdata *pdata; + struct radeon_encoder_atom_dig *dig; + u8 backlight_level; + + if (!radeon_encoder->enc_priv) + return; + + if (!rdev->is_atom_bios) + return; + + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) + return; + + pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); + if (!pdata) { + DRM_ERROR("Memory allocation failed\n"); + goto error; + } + + memset(&props, 0, sizeof(props)); + props.max_brightness = RADEON_MAX_BL_LEVEL; + props.type = BACKLIGHT_RAW; + bd = backlight_device_register("radeon_bl", &drm_connector->kdev, + pdata, &radeon_atom_backlight_ops, &props); + if (IS_ERR(bd)) { + DRM_ERROR("Backlight registration failed\n"); + goto error; + } + + pdata->encoder = radeon_encoder; + + backlight_level = radeon_atom_get_backlight_level_from_reg(rdev); + + dig = radeon_encoder->enc_priv; + dig->bl_dev = bd; + + bd->props.brightness = radeon_atom_backlight_get_brightness(bd); + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + + DRM_INFO("radeon atom DIG backlight initialized\n"); + + return; + +error: + kfree(pdata); + return; +} + +static void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct backlight_device *bd = NULL; + struct radeon_encoder_atom_dig *dig; + + if (!radeon_encoder->enc_priv) + return; + + if (!rdev->is_atom_bios) + return; + + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) + return; + + dig = radeon_encoder->enc_priv; + bd = dig->bl_dev; + dig->bl_dev = NULL; + + if (bd) { + struct radeon_legacy_backlight_privdata *pdata; + + pdata = bl_get_data(bd); + backlight_device_unregister(bd); + kfree(pdata); + + DRM_INFO("radeon atom LVDS backlight unloaded\n"); + } +} + +#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */ + +void radeon_atom_backlight_init(struct radeon_encoder *encoder) +{ +} + +static void radeon_atom_backlight_exit(struct radeon_encoder *encoder) +{ +} + +#endif + /* evil but including atombios.h is much worse */ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, struct drm_display_mode *mode); @@ -2286,6 +2515,8 @@ static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { void radeon_enc_destroy(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_atom_backlight_exit(radeon_encoder); kfree(radeon_encoder->enc_priv); drm_encoder_cleanup(encoder); kfree(radeon_encoder); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 895e628b60f8..748c5f229c28 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -40,10 +40,6 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, struct drm_encoder *encoder, bool connected); -extern void -radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, - struct drm_connector *drm_connector); - void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -2008,15 +2004,4 @@ radeon_add_legacy_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); - if (connector_type == DRM_MODE_CONNECTOR_LVDS) { - struct drm_encoder *drm_encoder; - - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_encoder; - - radeon_encoder = to_radeon_encoder(drm_encoder); - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS) - radeon_legacy_backlight_init(radeon_encoder, connector); - } - } } diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 74670696277d..93b0d64b3f6d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -29,6 +29,14 @@ #include "radeon.h" #include "atom.h" +extern void +radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, + struct drm_connector *drm_connector); +extern void +radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, + struct drm_connector *drm_connector); + + static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -153,6 +161,7 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 void radeon_link_encoder_connector(struct drm_device *dev) { + struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct drm_encoder *encoder; @@ -163,8 +172,15 @@ radeon_link_encoder_connector(struct drm_device *dev) radeon_connector = to_radeon_connector(connector); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->devices & radeon_connector->devices) + if (radeon_encoder->devices & radeon_connector->devices) { drm_mode_connector_attach_encoder(connector, encoder); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (rdev->is_atom_bios) + radeon_atom_backlight_init(radeon_encoder, connector); + else + radeon_legacy_backlight_init(radeon_encoder, connector); + } + } } } } From 86504672f7d79986a8ef618fb120044220e3d1eb Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Sun, 29 Jul 2012 17:04:43 +0200 Subject: [PATCH 16/79] drm/radeon: refactor radeon_atif_call Don't hard-code function number, this will allow to reuse the function. v2: add support for the 2nd parameter (from Lee, Chun-Yi ). Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 38 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index e94929c69245..f7b511dcba30 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -37,23 +37,30 @@ #include /* Call the ATIF method - * - * Note: currently we discard the output */ -static int radeon_atif_call(acpi_handle handle) +static union acpi_object *radeon_atif_call(acpi_handle handle, int function, + struct acpi_buffer *params) { acpi_status status; union acpi_object atif_arg_elements[2]; struct acpi_object_list atif_arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; atif_arg.count = 2; atif_arg.pointer = &atif_arg_elements[0]; atif_arg_elements[0].type = ACPI_TYPE_INTEGER; - atif_arg_elements[0].integer.value = ATIF_FUNCTION_VERIFY_INTERFACE; - atif_arg_elements[1].type = ACPI_TYPE_INTEGER; - atif_arg_elements[1].integer.value = 0; + atif_arg_elements[0].integer.value = function; + + if (params) { + atif_arg_elements[1].type = ACPI_TYPE_BUFFER; + atif_arg_elements[1].buffer.length = params->length; + atif_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atif_arg_elements[1].type = ACPI_TYPE_INTEGER; + atif_arg_elements[1].integer.value = 0; + } status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); @@ -62,18 +69,18 @@ static int radeon_atif_call(acpi_handle handle) DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", acpi_format_exception(status)); kfree(buffer.pointer); - return 1; + return NULL; } - kfree(buffer.pointer); - return 0; + return buffer.pointer; } /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; - int ret; + union acpi_object *info; + int ret = 0; /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); @@ -83,10 +90,11 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - ret = radeon_atif_call(handle); - if (ret) - return ret; + info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + ret = -EIO; - return 0; + kfree(info); + return ret; } From fd64ca8a9d9d7e92fc81fe0b23dcf324246fd356 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Thu, 16 Aug 2012 11:11:18 -0400 Subject: [PATCH 17/79] drm/radeon: implement radeon_atif_verify_interface Wrap the call to VERIFY_INTERFACE and add the parsing of the support vectors. v2: use a packed struct for handling the output of ACPI calls, hides ugly pointer arithmetics (Lee, Chun-Yi ). v3: fix radeon_atif_parse_functions handling (Alex Deucher) Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 40 ++++++++++++++ drivers/gpu/drm/radeon/radeon_acpi.c | 79 +++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5dbd591818fe..763f3333776e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1424,6 +1424,44 @@ struct r600_vram_scratch { u64 gpu_addr; }; +/* + * ACPI + */ +struct radeon_atif_notification_cfg { + bool enabled; + int command_code; +}; + +struct radeon_atif_notifications { + bool display_switch; + bool expansion_mode_change; + bool thermal_state; + bool forced_power_state; + bool system_power_state; + bool display_conf_change; + bool px_gfx_switch; + bool brightness_change; + bool dgpu_display_event; +}; + +struct radeon_atif_functions { + bool system_params; + bool sbios_requests; + bool select_active_disp; + bool lid_state; + bool get_tv_standard; + bool set_tv_standard; + bool get_panel_expansion_mode; + bool set_panel_expansion_mode; + bool temperature_change; + bool graphics_device_types; +}; + +struct radeon_atif { + struct radeon_atif_notifications notifications; + struct radeon_atif_functions functions; + struct radeon_atif_notification_cfg notification_cfg; +}; /* * Core structure, functions and helpers. @@ -1516,6 +1554,8 @@ struct radeon_device { /* virtual memory */ struct radeon_vm_manager vm_manager; struct mutex gpu_clock_mutex; + /* ACPI interface */ + struct radeon_atif atif; }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index f7b511dcba30..2f6cef2acadc 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -36,6 +36,13 @@ #include +struct atif_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 notification_mask; /* supported notifications mask */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + /* Call the ATIF method */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, @@ -75,12 +82,73 @@ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, return buffer.pointer; } +static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) +{ + n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; + n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; + n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; + n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; + n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; + n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; + n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; + n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; + n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; +} + +static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) +{ + f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; + f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; + f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; + f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; + f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; + f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; + f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; + f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; + f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; + f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; +} + +static int radeon_atif_verify_interface(acpi_handle handle, + struct radeon_atif *atif) +{ + union acpi_object *info; + struct atif_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 12) { + DRM_INFO("ATIF buffer is too small: %lu\n", size); + err = -EINVAL; + goto out; + } + size = min(sizeof(output), size); + + memcpy(&output, info->buffer.pointer, size); + + /* TODO: check version? */ + DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); + + radeon_atif_parse_notification(&atif->notifications, output.notification_mask); + radeon_atif_parse_functions(&atif->functions, output.function_bits); + +out: + kfree(info); + return err; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; - union acpi_object *info; - int ret = 0; + int ret; /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); @@ -90,11 +158,10 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); - if (!info) - ret = -EIO; + ret = radeon_atif_verify_interface(handle, &rdev->atif); + if (ret) + DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); - kfree(info); return ret; } From ce3cf821a31f9824eda788cbd3e710d8047e82df Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Mon, 30 Jul 2012 21:16:06 +0200 Subject: [PATCH 18/79] drm/radeon: implement wrapper for GET_SYSTEM_PARAMS Use GET_SYSTEM_PARAMS for retrieving the configuration for the system BIOS notifications. v2: packed struct (Lee, Chun-Yi ) v3: fix enable with device specific command code Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 85 +++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 2f6cef2acadc..0454eccc9c03 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -43,6 +43,18 @@ struct atif_verify_interface { u32 function_bits; /* supported functions bit vector */ } __packed; +struct atif_system_params { + u16 size; + u32 valid_mask; + u32 flags; + u8 command_code; +} __packed; + +#define ATIF_NOTIFY_MASK 0x3 +#define ATIF_NOTIFY_NONE 0 +#define ATIF_NOTIFY_81 1 +#define ATIF_NOTIFY_N 2 + /* Call the ATIF method */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, @@ -144,10 +156,57 @@ out: return err; } +static int radeon_atif_get_notification_params(acpi_handle handle, + struct radeon_atif_notification_cfg *n) +{ + union acpi_object *info; + struct atif_system_params params; + size_t size; + int err = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); + if (!info) { + err = -EIO; + goto out; + } + + size = *(u16 *) info->buffer.pointer; + if (size < 10) { + err = -EINVAL; + goto out; + } + + memset(¶ms, 0, sizeof(params)); + size = min(sizeof(params), size); + memcpy(¶ms, info->buffer.pointer, size); + + params.flags = params.flags & params.valid_mask; + + if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { + n->enabled = false; + n->command_code = 0; + } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { + n->enabled = true; + n->command_code = 0x81; + } else { + if (size < 11) { + err = -EINVAL; + goto out; + } + n->enabled = true; + n->command_code = params.command_code; + } + +out: + kfree(info); + return err; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; + struct radeon_atif *atif = &rdev->atif; int ret; /* Get the device handle */ @@ -158,10 +217,32 @@ int radeon_acpi_init(struct radeon_device *rdev) return 0; /* Call the ATIF method */ - ret = radeon_atif_verify_interface(handle, &rdev->atif); - if (ret) + ret = radeon_atif_verify_interface(handle, atif); + if (ret) { DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); + goto out; + } + if (atif->functions.sbios_requests && !atif->functions.system_params) { + /* XXX check this workraround, if sbios request function is + * present we have to see how it's configured in the system + * params + */ + atif->functions.system_params = true; + } + + if (atif->functions.system_params) { + ret = radeon_atif_get_notification_params(handle, + &atif->notification_cfg); + if (ret) { + DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", + ret); + /* Disable notification */ + atif->notification_cfg.enabled = false; + } + } + +out: return ret; } From fda4b25c55a59ba12378e4b9e4553f6ea57d802d Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Mon, 30 Jul 2012 21:20:35 +0200 Subject: [PATCH 19/79] drm/radeon: implement handler for ACPI event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set up an handler for ACPI events and respond to brightness change requests from the system BIOS. v2: fix notification when using device-specific command codes (tested by Pali Rohár ); cache the encoder controlling the backlight during the initialization to avoid searching it every time (suggested by Alex Deucher). v3: whitespace fixes (Alex Deucher). Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_acpi.c | 132 ++++++++++++++++++++- drivers/gpu/drm/radeon/radeon_acpi.h | 6 + drivers/gpu/drm/radeon/radeon_kms.c | 16 ++- drivers/gpu/drm/radeon/radeon_mode.h | 2 + drivers/gpu/drm/radeon/radeon_pm.c | 4 +- 7 files changed, 152 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f3645e15ef11..370b2c4a7c86 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -72,7 +72,7 @@ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); } -static void +void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) { struct drm_encoder *encoder = &radeon_encoder->base; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 763f3333776e..dea5f08bd23b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1461,6 +1461,7 @@ struct radeon_atif { struct radeon_atif_notifications notifications; struct radeon_atif_functions functions; struct radeon_atif_notification_cfg notification_cfg; + struct radeon_encoder *backlight_ctl; }; /* diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 0454eccc9c03..b052a556db79 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "drmP.h" #include "drm.h" @@ -33,6 +34,7 @@ #include "drm_crtc_helper.h" #include "radeon.h" #include "radeon_acpi.h" +#include "atom.h" #include @@ -44,10 +46,22 @@ struct atif_verify_interface { } __packed; struct atif_system_params { - u16 size; - u32 valid_mask; - u32 flags; - u8 command_code; + u16 size; /* structure size in bytes (includes size field) */ + u32 valid_mask; /* valid flags mask */ + u32 flags; /* flags */ + u8 command_code; /* notify command code */ +} __packed; + +struct atif_sbios_requests { + u16 size; /* structure size in bytes (includes size field) */ + u32 pending; /* pending sbios requests */ + u8 panel_exp_mode; /* panel expansion mode */ + u8 thermal_gfx; /* thermal state: target gfx controller */ + u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ + u8 forced_power_gfx; /* forced power state: target gfx controller */ + u8 forced_power_state; /* forced power state: state id */ + u8 system_power_src; /* system power source */ + u8 backlight_level; /* panel backlight level (0-255) */ } __packed; #define ATIF_NOTIFY_MASK 0x3 @@ -180,6 +194,8 @@ static int radeon_atif_get_notification_params(acpi_handle handle, size = min(sizeof(params), size); memcpy(¶ms, info->buffer.pointer, size); + DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", + params.flags, params.valid_mask); params.flags = params.flags & params.valid_mask; if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { @@ -198,10 +214,91 @@ static int radeon_atif_get_notification_params(acpi_handle handle, } out: + DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", + (n->enabled ? "enabled" : "disabled"), + n->command_code); kfree(info); return err; } +static int radeon_atif_get_sbios_requests(acpi_handle handle, + struct atif_sbios_requests *req) +{ + union acpi_object *info; + size_t size; + int count = 0; + + info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); + if (!info) + return -EIO; + + size = *(u16 *)info->buffer.pointer; + if (size < 0xd) { + count = -EINVAL; + goto out; + } + memset(req, 0, sizeof(*req)); + + size = min(sizeof(*req), size); + memcpy(req, info->buffer.pointer, size); + DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); + + count = hweight32(req->pending); + +out: + kfree(info); + return count; +} + +int radeon_atif_handler(struct radeon_device *rdev, + struct acpi_bus_event *event) +{ + struct radeon_atif *atif = &rdev->atif; + struct atif_sbios_requests req; + acpi_handle handle; + int count; + + DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", + event->device_class, event->type); + + if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) + return NOTIFY_DONE; + + if (!atif->notification_cfg.enabled || + event->type != atif->notification_cfg.command_code) + /* Not our event */ + return NOTIFY_DONE; + + /* Check pending SBIOS requests */ + handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); + count = radeon_atif_get_sbios_requests(handle, &req); + + if (count <= 0) + return NOTIFY_DONE; + + DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); + + if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { + struct radeon_encoder *enc = atif->backlight_ctl; + + if (enc) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + dig->backlight_level = req.backlight_level; + + DRM_DEBUG_DRIVER("Changing brightness to %d\n", + req.backlight_level); + + atombios_set_panel_brightness(enc); + + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } + } + /* TODO: check other events */ + + return NOTIFY_OK; +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { @@ -223,6 +320,33 @@ int radeon_acpi_init(struct radeon_device *rdev) goto out; } + if (atif->notifications.brightness_change) { + struct drm_encoder *tmp; + struct radeon_encoder *target = NULL; + + /* Find the encoder controlling the brightness */ + list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, + head) { + struct radeon_encoder *enc = to_radeon_encoder(tmp); + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + + if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && + dig->bl_dev != NULL) { + target = enc; + break; + } + } + + atif->backlight_ctl = target; + if (!target) { + /* Brightness change notification is enabled, but we + * didn't find a backlight controller, this should + * never happen. + */ + DRM_ERROR("Cannot find a backlight controller\n"); + } + } + if (atif->functions.sbios_requests && !atif->functions.system_params) { /* XXX check this workraround, if sbios request function is * present we have to see how it's configured in the system diff --git a/drivers/gpu/drm/radeon/radeon_acpi.h b/drivers/gpu/drm/radeon/radeon_acpi.h index 642aa4719454..be4af76f213d 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.h +++ b/drivers/gpu/drm/radeon/radeon_acpi.h @@ -24,6 +24,12 @@ #ifndef RADEON_ACPI_H #define RADEON_ACPI_H +struct radeon_device; +struct acpi_bus_event; + +int radeon_atif_handler(struct radeon_device *rdev, + struct acpi_bus_event *event); + /* AMD hw uses four ACPI control methods: * 1. ATIF * ARG0: (ACPI_INTEGER) function code diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 414b4acf6947..8c2471854cd7 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -103,11 +103,6 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) goto out; } - /* Call ACPI methods */ - acpi_status = radeon_acpi_init(rdev); - if (acpi_status) - dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n"); - /* Again modeset_init should fail only on fatal error * otherwise it should provide enough functionalities * for shadowfb to run @@ -115,6 +110,17 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) r = radeon_modeset_init(rdev); if (r) dev_err(&dev->pdev->dev, "Fatal error during modeset init\n"); + + /* Call ACPI methods: require modeset init + * but failure is not fatal + */ + if (!r) { + acpi_status = radeon_acpi_init(rdev); + if (acpi_status) + dev_dbg(&dev->pdev->dev, + "Error during ACPI methods call\n"); + } + out: if (r) radeon_driver_unload_kms(dev); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5005057974b1..1f411c2609d8 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -698,6 +698,8 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); +void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder); + /* legacy tv */ void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 2c2c901226f4..14e544e0eb31 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,6 +22,7 @@ */ #include "drmP.h" #include "radeon.h" +#include "radeon_acpi.h" #include "avivod.h" #include "atom.h" #ifdef CONFIG_ACPI @@ -94,7 +95,8 @@ static int radeon_acpi_event(struct notifier_block *nb, } } - return NOTIFY_OK; + /* Check for pending SBIOS requests */ + return radeon_atif_handler(rdev, entry); } #endif From c49170742d6928b16fb3839b47a94cc41630dbe0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 31 Jul 2012 17:14:35 -0400 Subject: [PATCH 20/79] drm/radeon: re-organize the acpi notifier callback Move it out of the radeon_pm.c and into radeon_acpi.c since we use it for more than just pm now. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 14 +++++---- drivers/gpu/drm/radeon/radeon_acpi.c | 32 ++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_kms.c | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 44 +++++----------------------- 4 files changed, 48 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index dea5f08bd23b..b5b16878f0cf 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1869,12 +1869,14 @@ extern void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_displ extern int ni_init_microcode(struct radeon_device *rdev); extern int ni_mc_load_microcode(struct radeon_device *rdev); -/* radeon_acpi.c */ -#if defined(CONFIG_ACPI) -extern int radeon_acpi_init(struct radeon_device *rdev); -#else -static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } -#endif +/* radeon_acpi.c */ +#if defined(CONFIG_ACPI) +extern int radeon_acpi_init(struct radeon_device *rdev); +extern void radeon_acpi_fini(struct radeon_device *rdev); +#else +static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } +static inline void radeon_acpi_fini(struct radeon_device *rdev) { } +#endif #include "radeon_object.h" diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index b052a556db79..ea22f4416f48 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,10 @@ #include +#define ACPI_AC_CLASS "ac_adapter" + +extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); + struct atif_verify_interface { u16 size; /* structure size in bytes (includes size field) */ u16 version; /* version */ @@ -299,6 +304,26 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_OK; } +static int radeon_acpi_event(struct notifier_block *nb, + unsigned long val, + void *data) +{ + struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); + struct acpi_bus_event *entry = (struct acpi_bus_event *)data; + + if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { + if (power_supply_is_system_supplied() > 0) + DRM_DEBUG_DRIVER("pm: AC\n"); + else + DRM_DEBUG_DRIVER("pm: DC\n"); + + radeon_pm_acpi_event_handler(rdev); + } + + /* Check for pending SBIOS requests */ + return radeon_atif_handler(rdev, entry); +} + /* Call all ACPI methods here */ int radeon_acpi_init(struct radeon_device *rdev) { @@ -367,6 +392,13 @@ int radeon_acpi_init(struct radeon_device *rdev) } out: + rdev->acpi_nb.notifier_call = radeon_acpi_event; + register_acpi_notifier(&rdev->acpi_nb); + return ret; } +void radeon_acpi_fini(struct radeon_device *rdev) +{ + unregister_acpi_notifier(&rdev->acpi_nb); +} diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 8c2471854cd7..cb8e94d1a2b2 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -51,6 +51,7 @@ int radeon_driver_unload_kms(struct drm_device *dev) if (rdev == NULL) return 0; + radeon_acpi_fini(rdev); radeon_modeset_fini(rdev); radeon_device_fini(rdev); kfree(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 14e544e0eb31..c15e505a15bc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -22,12 +22,8 @@ */ #include "drmP.h" #include "radeon.h" -#include "radeon_acpi.h" #include "avivod.h" #include "atom.h" -#ifdef CONFIG_ACPI -#include -#endif #include #include #include @@ -51,8 +47,6 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish static void radeon_pm_update_profile(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); -#define ACPI_AC_CLASS "ac_adapter" - int radeon_pm_get_type_index(struct radeon_device *rdev, enum radeon_pm_state_type ps_type, int instance) @@ -71,34 +65,17 @@ int radeon_pm_get_type_index(struct radeon_device *rdev, return rdev->pm.default_power_state_index; } -#ifdef CONFIG_ACPI -static int radeon_acpi_event(struct notifier_block *nb, - unsigned long val, - void *data) +void radeon_pm_acpi_event_handler(struct radeon_device *rdev) { - struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); - struct acpi_bus_event *entry = (struct acpi_bus_event *)data; - - if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { - if (power_supply_is_system_supplied() > 0) - DRM_DEBUG_DRIVER("pm: AC\n"); - else - DRM_DEBUG_DRIVER("pm: DC\n"); - - if (rdev->pm.pm_method == PM_METHOD_PROFILE) { - if (rdev->pm.profile == PM_PROFILE_AUTO) { - mutex_lock(&rdev->pm.mutex); - radeon_pm_update_profile(rdev); - radeon_pm_set_clocks(rdev); - mutex_unlock(&rdev->pm.mutex); - } + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (rdev->pm.profile == PM_PROFILE_AUTO) { + mutex_lock(&rdev->pm.mutex); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); } } - - /* Check for pending SBIOS requests */ - return radeon_atif_handler(rdev, entry); } -#endif static void radeon_pm_update_profile(struct radeon_device *rdev) { @@ -629,10 +606,6 @@ int radeon_pm_init(struct radeon_device *rdev) if (ret) DRM_ERROR("failed to create device file for power method\n"); -#ifdef CONFIG_ACPI - rdev->acpi_nb.notifier_call = radeon_acpi_event; - register_acpi_notifier(&rdev->acpi_nb); -#endif if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -663,9 +636,6 @@ void radeon_pm_fini(struct radeon_device *rdev) device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); -#ifdef CONFIG_ACPI - unregister_acpi_notifier(&rdev->acpi_nb); -#endif } if (rdev->pm.power_state) From 8a37c65df9dcbd1c891df2b4a94157999b654841 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Thu, 2 Aug 2012 15:30:27 +0200 Subject: [PATCH 21/79] ACPI video: allow events handlers to veto the keypress The standard video events may be overloaded for device specific purposes. For example AMD ACPI interface overloads ACPI_VIDEO_NOTIFY_PROBE (0x81) to signal AMD-specific events. In such cases we don't want to send the keypress (KEY_SWITCHVIDEOMODE) to the userspace because the user did not press the mode switch key (the spurious keypress confuses the DE which usually changes the display configuration and messes up a dual-screen setup). This patch gives the handlers the chance to examine the event and block the keypress if the event is device specific. v2: refactor as suggested by Zhang Rui Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/acpi/video.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 1e0a9e17c31d..f94d4c818fc7 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1448,8 +1448,7 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ acpi_bus_generate_proc_event(device, event, 0); - if (!acpi_notifier_call_chain(device, event, 0)) - keycode = KEY_SWITCHVIDEOMODE; + keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video @@ -1479,8 +1478,9 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) break; } - if (event != ACPI_VIDEO_NOTIFY_SWITCH) - acpi_notifier_call_chain(device, event, 0); + if (acpi_notifier_call_chain(device, event, 0)) + /* Something vetoed the keypress. */ + keycode = 0; if (keycode) { input_report_key(input, keycode, 1); From 92fdf89aa95de32dba1cb44fe7f5c54824b4b2c4 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Thu, 2 Aug 2012 11:39:38 -0400 Subject: [PATCH 22/79] drm/radeon: block the keypress on ATIF events The AMD ACPI interface may use ACPI_VIDEO_NOTIFY_PROBE to signal SBIOS requests; block the keypress in this case since the user did not actually press the mode switch key. Signed-off-by: Luca Tettamanti Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index ea22f4416f48..3486292892b5 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -301,7 +301,12 @@ int radeon_atif_handler(struct radeon_device *rdev, } /* TODO: check other events */ - return NOTIFY_OK; + /* We've handled the event, stop the notifier chain. The ACPI interface + * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to + * userspace if the event was generated only to signal a SBIOS + * request. + */ + return NOTIFY_BAD; } static int radeon_acpi_event(struct notifier_block *nb, From c3c651600bd83de5e1cbb5d9ec34a88efd2856e8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 2 Aug 2012 12:30:49 -0400 Subject: [PATCH 23/79] drm/radeon: document radeon_acpi.c Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_acpi.c | 101 +++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 3486292892b5..49a7d64be9e3 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -76,6 +76,16 @@ struct atif_sbios_requests { /* Call the ATIF method */ +/** + * radeon_atif_call - call an ATIF method + * + * @handle: acpi handle + * @function: the ATIF function to execute + * @params: ATIF function params + * + * Executes the requested ATIF function (all asics). + * Returns a pointer to the acpi output buffer. + */ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, struct acpi_buffer *params) { @@ -113,6 +123,16 @@ static union acpi_object *radeon_atif_call(acpi_handle handle, int function, return buffer.pointer; } +/** + * radeon_atif_parse_notification - parse supported notifications + * + * @n: supported notifications struct + * @mask: supported notifications mask from ATIF + * + * Use the supported notifications mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications + * are supported (all asics). + */ static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) { n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; @@ -126,6 +146,16 @@ static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; } +/** + * radeon_atif_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATIF + * + * Use the supported functions mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) { f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; @@ -140,6 +170,17 @@ static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mas f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; } +/** + * radeon_atif_verify_interface - verify ATIF + * + * @handle: acpi handle + * @atif: radeon atif struct + * + * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function + * to initialize ATIF and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ static int radeon_atif_verify_interface(acpi_handle handle, struct radeon_atif *atif) { @@ -175,6 +216,18 @@ out: return err; } +/** + * radeon_atif_get_notification_params - determine notify configuration + * + * @handle: acpi handle + * @n: atif notification configuration struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function + * to determine if a notifier is used and if so which one + * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) + * where n is specified in the result if a notifier is used. + * Returns 0 on success, error on failure. + */ static int radeon_atif_get_notification_params(acpi_handle handle, struct radeon_atif_notification_cfg *n) { @@ -226,6 +279,17 @@ out: return err; } +/** + * radeon_atif_get_sbios_requests - get requested sbios event + * + * @handle: acpi handle + * @req: atif sbios request struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function + * to determine what requests the sbios is making to the driver + * (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atif_get_sbios_requests(acpi_handle handle, struct atif_sbios_requests *req) { @@ -255,6 +319,16 @@ out: return count; } +/** + * radeon_atif_handler - handle ATIF notify requests + * + * @rdev: radeon_device pointer + * @event: atif sbios request struct + * + * Checks the acpi event and if it matches an atif event, + * handles it. + * Returns NOTIFY code + */ int radeon_atif_handler(struct radeon_device *rdev, struct acpi_bus_event *event) { @@ -309,6 +383,17 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_BAD; } +/** + * radeon_acpi_event - handle notify events + * + * @nb: notifier block + * @val: val + * @data: acpi event + * + * Calls relevant radeon functions in response to various + * acpi events. + * Returns NOTIFY code + */ static int radeon_acpi_event(struct notifier_block *nb, unsigned long val, void *data) @@ -330,6 +415,15 @@ static int radeon_acpi_event(struct notifier_block *nb, } /* Call all ACPI methods here */ +/** + * radeon_acpi_init - init driver acpi support + * + * @rdev: radeon_device pointer + * + * Verifies the AMD ACPI interfaces and registers with the acpi + * notifier chain (all asics). + * Returns 0 on success, error on failure. + */ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; @@ -403,6 +497,13 @@ out: return ret; } +/** + * radeon_acpi_fini - tear down driver acpi support + * + * @rdev: radeon_device pointer + * + * Unregisters with the acpi notifier chain (all asics). + */ void radeon_acpi_fini(struct radeon_device *rdev) { unregister_acpi_notifier(&rdev->acpi_nb); From 48fa412b7451530322cdbe969e404b798c6e204e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 14:01:57 -0400 Subject: [PATCH 24/79] drm/radeon: update ATPX verify interface handling (v2) Verify the ATPX interface and track what ATPX functions are available for future use. v2: rework due to tree changes Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 143 ++++++++++++++++--- 1 file changed, 125 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 950a1ac95d6a..c1f2671a7b0b 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -14,17 +14,50 @@ #include "radeon_acpi.h" +struct radeon_atpx_functions { + bool px_params; + bool power_cntl; + bool disp_mux_cntl; + bool i2c_mux_cntl; + bool switch_start; + bool switch_end; + bool disp_connectors_mapping; + bool disp_detetion_ports; +}; + +struct radeon_atpx { + struct radeon_atpx_functions functions; +}; + static struct radeon_atpx_priv { bool atpx_detected; /* handle for device - and atpx */ acpi_handle dhandle; acpi_handle atpx_handle; + struct radeon_atpx atpx; } radeon_atpx_priv; -static int radeon_atpx_get_version(acpi_handle handle) +struct atpx_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + +/** + * radeon_atpx_call - call an ATPX method + * + * @handle: acpi handle + * @function: the ATPX function to execute + * @params: ATPX function params + * + * Executes the requested ATPX function (all asics). + * Returns a pointer to the acpi output buffer. + */ +static union acpi_object *radeon_atpx_call(acpi_handle handle, int function, + struct acpi_buffer *params) { acpi_status status; - union acpi_object atpx_arg_elements[2], *obj; + union acpi_object atpx_arg_elements[2]; struct acpi_object_list atpx_arg; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -32,21 +65,96 @@ static int radeon_atpx_get_version(acpi_handle handle) atpx_arg.pointer = &atpx_arg_elements[0]; atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[0].integer.value = ATPX_FUNCTION_VERIFY_INTERFACE; + atpx_arg_elements[0].integer.value = function; - atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[1].integer.value = 0; - - status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); - if (ACPI_FAILURE(status)) { - printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status)); - return -ENOSYS; + if (params) { + atpx_arg_elements[1].type = ACPI_TYPE_BUFFER; + atpx_arg_elements[1].buffer.length = params->length; + atpx_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; + atpx_arg_elements[1].integer.value = 0; } - obj = (union acpi_object *)buffer.pointer; - if (obj && (obj->type == ACPI_TYPE_BUFFER)) - printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2)); - kfree(buffer.pointer); - return 0; + + status = acpi_evaluate_object(handle, "ATPX", &atpx_arg, &buffer); + + /* Fail only if calling the method fails and ATPX is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printk("failed to evaluate ATPX got %s\n", + acpi_format_exception(status)); + kfree(buffer.pointer); + return NULL; + } + + return buffer.pointer; +} + +/** + * radeon_atpx_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATPX + * + * Use the supported functions mask from ATPX function + * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ +static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask) +{ + f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED; + f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED; + f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED; + f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED; + f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; + f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; + f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; + f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; +} + +/** + * radeon_atpx_verify_interface - verify ATPX + * + * @handle: acpi handle + * @atpx: radeon atpx struct + * + * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function + * to initialize ATPX and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ +static int radeon_atpx_verify_interface(acpi_handle handle, + struct radeon_atpx *atpx) +{ + union acpi_object *info; + struct atpx_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atpx_call(handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 8) { + printk("ATPX buffer is too small: %lu\n", size); + err = -EINVAL; + goto out; + } + size = min(sizeof(output), size); + + memcpy(&output, info->buffer.pointer, size); + + /* TODO: check version? */ + printk("ATPX version %u\n", output.version); + + radeon_atpx_parse_functions(&atpx->functions, output.function_bits); + +out: + kfree(info); + return err; } static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value) @@ -161,9 +269,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) static int radeon_atpx_init(void) { /* set up the ATPX handle */ - - radeon_atpx_get_version(radeon_atpx_priv.atpx_handle); - return 0; + return radeon_atpx_verify_interface(radeon_atpx_priv.atpx_handle, + &radeon_atpx_priv.atpx); } static int radeon_atpx_get_client_id(struct pci_dev *pdev) From 492b49a2f21a7ce6cb0abce36017daa06036a626 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 14:07:37 -0400 Subject: [PATCH 25/79] drm/radeon: reorganize ATPX support (v2) - rework the acpi execute code - User proper parameters for ATPX functions v2: rebase fixes Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 166 ++++++++++++------- 1 file changed, 108 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index c1f2671a7b0b..331db7a95f09 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -26,6 +26,7 @@ struct radeon_atpx_functions { }; struct radeon_atpx { + acpi_handle handle; struct radeon_atpx_functions functions; }; @@ -33,7 +34,6 @@ static struct radeon_atpx_priv { bool atpx_detected; /* handle for device - and atpx */ acpi_handle dhandle; - acpi_handle atpx_handle; struct radeon_atpx atpx; } radeon_atpx_priv; @@ -43,6 +43,16 @@ struct atpx_verify_interface { u32 function_bits; /* supported functions bit vector */ } __packed; +struct atpx_power_control { + u16 size; + u8 dgpu_state; +} __packed; + +struct atpx_mux { + u16 size; + u16 mux; +} __packed; + /** * radeon_atpx_call - call an ATPX method * @@ -123,15 +133,14 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas * (all asics). * returns 0 on success, error on failure. */ -static int radeon_atpx_verify_interface(acpi_handle handle, - struct radeon_atpx *atpx) +static int radeon_atpx_verify_interface(struct radeon_atpx *atpx) { union acpi_object *info; struct atpx_verify_interface output; size_t size; int err = 0; - info = radeon_atpx_call(handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); + info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); if (!info) return -EIO; @@ -157,82 +166,124 @@ out: return err; } -static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value) +static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state) { - acpi_status status; - union acpi_object atpx_arg_elements[2]; - struct acpi_object_list atpx_arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - uint8_t buf[4] = {0}; + struct acpi_buffer params; + union acpi_object *info; + struct atpx_power_control input; - if (!handle) - return -EINVAL; - - atpx_arg.count = 2; - atpx_arg.pointer = &atpx_arg_elements[0]; - - atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; - atpx_arg_elements[0].integer.value = cmd_id; - - buf[2] = value & 0xff; - buf[3] = (value >> 8) & 0xff; - - atpx_arg_elements[1].type = ACPI_TYPE_BUFFER; - atpx_arg_elements[1].buffer.length = 4; - atpx_arg_elements[1].buffer.pointer = buf; - - status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); - if (ACPI_FAILURE(status)) { - printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status)); - return -ENOSYS; + if (atpx->functions.power_cntl) { + input.size = 3; + input.dgpu_state = state; + params.length = input.size; + params.pointer = &input; + info = radeon_atpx_call(atpx->handle, + ATPX_FUNCTION_POWER_CONTROL, + ¶ms); + if (!info) + return -EIO; + kfree(info); } - kfree(buffer.pointer); - return 0; } -static int radeon_atpx_set_discrete_state(acpi_handle handle, int state) +static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id) { - return radeon_atpx_execute(handle, ATPX_FUNCTION_POWER_CONTROL, state); + struct acpi_buffer params; + union acpi_object *info; + struct atpx_mux input; + + if (atpx->functions.disp_mux_cntl) { + input.size = 4; + input.mux = mux_id; + params.length = input.size; + params.pointer = &input; + info = radeon_atpx_call(atpx->handle, + ATPX_FUNCTION_DISPLAY_MUX_CONTROL, + ¶ms); + if (!info) + return -EIO; + kfree(info); + } + return 0; } -static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) +static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id) { - return radeon_atpx_execute(handle, ATPX_FUNCTION_DISPLAY_MUX_CONTROL, mux_id); + struct acpi_buffer params; + union acpi_object *info; + struct atpx_mux input; + + if (atpx->functions.i2c_mux_cntl) { + input.size = 4; + input.mux = mux_id; + params.length = input.size; + params.pointer = &input; + info = radeon_atpx_call(atpx->handle, + ATPX_FUNCTION_I2C_MUX_CONTROL, + ¶ms); + if (!info) + return -EIO; + kfree(info); + } + return 0; } -static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id) +static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id) { - return radeon_atpx_execute(handle, ATPX_FUNCTION_I2C_MUX_CONTROL, mux_id); + struct acpi_buffer params; + union acpi_object *info; + struct atpx_mux input; + + if (atpx->functions.switch_start) { + input.size = 4; + input.mux = mux_id; + params.length = input.size; + params.pointer = &input; + info = radeon_atpx_call(atpx->handle, + ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION, + ¶ms); + if (!info) + return -EIO; + kfree(info); + } + return 0; } -static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id) +static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id) { - return radeon_atpx_execute(handle, - ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION, - gpu_id); -} + struct acpi_buffer params; + union acpi_object *info; + struct atpx_mux input; -static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id) -{ - return radeon_atpx_execute(handle, - ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION, - gpu_id); + if (atpx->functions.switch_end) { + input.size = 4; + input.mux = mux_id; + params.length = input.size; + params.pointer = &input; + info = radeon_atpx_call(atpx->handle, + ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION, + ¶ms); + if (!info) + return -EIO; + kfree(info); + } + return 0; } static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) { - int gpu_id; + u16 gpu_id; if (id == VGA_SWITCHEROO_IGD) gpu_id = ATPX_INTEGRATED_GPU; else gpu_id = ATPX_DISCRETE_GPU; - radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id); - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id); - radeon_atpx_switch_i2c_mux(radeon_atpx_priv.atpx_handle, gpu_id); - radeon_atpx_switch_end(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_start(&radeon_atpx_priv.atpx, gpu_id); + radeon_atpx_switch_disp_mux(&radeon_atpx_priv.atpx, gpu_id); + radeon_atpx_switch_i2c_mux(&radeon_atpx_priv.atpx, gpu_id); + radeon_atpx_switch_end(&radeon_atpx_priv.atpx, gpu_id); return 0; } @@ -244,7 +295,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, if (id == VGA_SWITCHEROO_IGD) return 0; - radeon_atpx_set_discrete_state(radeon_atpx_priv.atpx_handle, state); + radeon_atpx_set_discrete_state(&radeon_atpx_priv.atpx, state); return 0; } @@ -262,15 +313,14 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) return false; radeon_atpx_priv.dhandle = dhandle; - radeon_atpx_priv.atpx_handle = atpx_handle; + radeon_atpx_priv.atpx.handle = atpx_handle; return true; } static int radeon_atpx_init(void) { /* set up the ATPX handle */ - return radeon_atpx_verify_interface(radeon_atpx_priv.atpx_handle, - &radeon_atpx_priv.atpx); + return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); } static int radeon_atpx_get_client_id(struct pci_dev *pdev) @@ -303,7 +353,7 @@ static bool radeon_atpx_detect(void) } if (has_atpx && vga_count == 2) { - acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", acpi_method_name); radeon_atpx_priv.atpx_detected = true; From 82e029357d4726bbfb31b4169f82dcaea5fa3eba Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 14:09:21 -0400 Subject: [PATCH 26/79] drm/radeon: document radeon_atpx_handler.c (v2) v2: rebase updates Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 111 +++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 331db7a95f09..582e99449c12 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -166,6 +166,16 @@ out: return err; } +/** + * radeon_atpx_set_discrete_state - power up/down discrete GPU + * + * @atpx: atpx info struct + * @state: discrete GPU state (0 = power down, 1 = power up) + * + * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to + * power down/up the discrete GPU (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state) { struct acpi_buffer params; @@ -187,6 +197,17 @@ static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state) return 0; } +/** + * radeon_atpx_switch_disp_mux - switch display mux + * + * @atpx: atpx info struct + * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) + * + * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to + * switch the display mux between the discrete GPU and integrated GPU + * (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id) { struct acpi_buffer params; @@ -208,6 +229,17 @@ static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id) return 0; } +/** + * radeon_atpx_switch_i2c_mux - switch i2c/hpd mux + * + * @atpx: atpx info struct + * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) + * + * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to + * switch the i2c/hpd mux between the discrete GPU and integrated GPU + * (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id) { struct acpi_buffer params; @@ -229,6 +261,17 @@ static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id) return 0; } +/** + * radeon_atpx_switch_start - notify the sbios of a GPU switch + * + * @atpx: atpx info struct + * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) + * + * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX + * function to notify the sbios that a switch between the discrete GPU and + * integrated GPU has begun (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id) { struct acpi_buffer params; @@ -250,6 +293,17 @@ static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id) return 0; } +/** + * radeon_atpx_switch_end - notify the sbios of a GPU switch + * + * @atpx: atpx info struct + * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) + * + * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX + * function to notify the sbios that a switch between the discrete GPU and + * integrated GPU has ended (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id) { struct acpi_buffer params; @@ -271,6 +325,15 @@ static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id) return 0; } +/** + * radeon_atpx_switchto - switch to the requested GPU + * + * @id: GPU to switch to + * + * Execute the necessary ATPX functions to switch between the discrete GPU and + * integrated GPU (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) { u16 gpu_id; @@ -288,6 +351,16 @@ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) return 0; } +/** + * radeon_atpx_switchto - switch to the requested GPU + * + * @id: GPU to switch to + * @state: requested power state (0 = off, 1 = on) + * + * Execute the necessary ATPX function to power down/up the discrete GPU + * (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, enum vga_switcheroo_state state) { @@ -299,6 +372,14 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, return 0; } +/** + * radeon_atpx_pci_probe_handle - look up the ATRM and ATPX handles + * + * @pdev: pci device + * + * Look up the ATPX and ATRM handles (all asics). + * Returns true if the handles are found, false if not. + */ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) { acpi_handle dhandle, atpx_handle; @@ -317,12 +398,26 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) return true; } +/** + * radeon_atpx_init - verify the ATPX interface + * + * Verify the ATPX interface (all asics). + * Returns 0 on success, error on failure. + */ static int radeon_atpx_init(void) { /* set up the ATPX handle */ return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); } +/** + * radeon_atpx_get_client_id - get the client id + * + * @pdev: pci device + * + * look up whether we are the integrated or discrete GPU (all asics). + * Returns the client id. + */ static int radeon_atpx_get_client_id(struct pci_dev *pdev) { if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) @@ -338,6 +433,12 @@ static struct vga_switcheroo_handler radeon_atpx_handler = { .get_client_id = radeon_atpx_get_client_id, }; +/** + * radeon_atpx_detect - detect whether we have PX + * + * Check if we have a PX system (all asics). + * Returns true if we have a PX system, false if not. + */ static bool radeon_atpx_detect(void) { char acpi_method_name[255] = { 0 }; @@ -362,6 +463,11 @@ static bool radeon_atpx_detect(void) return false; } +/** + * radeon_register_atpx_handler - register with vga_switcheroo + * + * Register the PX callbacks with vga_switcheroo (all asics). + */ void radeon_register_atpx_handler(void) { bool r; @@ -374,6 +480,11 @@ void radeon_register_atpx_handler(void) vga_switcheroo_register_handler(&radeon_atpx_handler); } +/** + * radeon_unregister_atpx_handler - unregister with vga_switcheroo + * + * Unregister the PX callbacks with vga_switcheroo (all asics). + */ void radeon_unregister_atpx_handler(void) { vga_switcheroo_unregister_handler(); From e3a1592085988c60a2207eb492b89493573a0303 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Aug 2012 11:13:43 -0400 Subject: [PATCH 27/79] drm/radeon: add initial support for ATCS ACPI methods Just verify the interface and track what functions are supported. Not actually used yet. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 12 +++ drivers/gpu/drm/radeon/radeon_acpi.c | 127 ++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b5b16878f0cf..99a5c8445014 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1464,6 +1464,17 @@ struct radeon_atif { struct radeon_encoder *backlight_ctl; }; +struct radeon_atcs_functions { + bool get_ext_state; + bool pcie_perf_req; + bool pcie_dev_rdy; + bool pcie_bus_width; +}; + +struct radeon_atcs { + struct radeon_atcs_functions functions; +}; + /* * Core structure, functions and helpers. */ @@ -1557,6 +1568,7 @@ struct radeon_device { struct mutex gpu_clock_mutex; /* ACPI interface */ struct radeon_atif atif; + struct radeon_atcs atcs; }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 49a7d64be9e3..cae895ba8e2f 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -74,6 +74,12 @@ struct atif_sbios_requests { #define ATIF_NOTIFY_81 1 #define ATIF_NOTIFY_N 2 +struct atcs_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + /* Call the ATIF method */ /** @@ -383,6 +389,118 @@ int radeon_atif_handler(struct radeon_device *rdev, return NOTIFY_BAD; } +/* Call the ATCS method + */ +/** + * radeon_atcs_call - call an ATCS method + * + * @handle: acpi handle + * @function: the ATCS function to execute + * @params: ATCS function params + * + * Executes the requested ATCS function (all asics). + * Returns a pointer to the acpi output buffer. + */ +static union acpi_object *radeon_atcs_call(acpi_handle handle, int function, + struct acpi_buffer *params) +{ + acpi_status status; + union acpi_object atcs_arg_elements[2]; + struct acpi_object_list atcs_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + atcs_arg.count = 2; + atcs_arg.pointer = &atcs_arg_elements[0]; + + atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; + atcs_arg_elements[0].integer.value = function; + + if (params) { + atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; + atcs_arg_elements[1].buffer.length = params->length; + atcs_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; + atcs_arg_elements[1].integer.value = 0; + } + + status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); + + /* Fail only if calling the method fails and ATIF is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", + acpi_format_exception(status)); + kfree(buffer.pointer); + return NULL; + } + + return buffer.pointer; +} + +/** + * radeon_atcs_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATCS + * + * Use the supported functions mask from ATCS function + * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ +static void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask) +{ + f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; + f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; + f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; + f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; +} + +/** + * radeon_atcs_verify_interface - verify ATCS + * + * @handle: acpi handle + * @atcs: radeon atcs struct + * + * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function + * to initialize ATCS and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ +static int radeon_atcs_verify_interface(acpi_handle handle, + struct radeon_atcs *atcs) +{ + union acpi_object *info; + struct atcs_verify_interface output; + size_t size; + int err = 0; + + info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 8) { + DRM_INFO("ATCS buffer is too small: %lu\n", size); + err = -EINVAL; + goto out; + } + size = min(sizeof(output), size); + + memcpy(&output, info->buffer.pointer, size); + + /* TODO: check version? */ + DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); + + radeon_atcs_parse_functions(&atcs->functions, output.function_bits); + +out: + kfree(info); + return err; +} + /** * radeon_acpi_event - handle notify events * @@ -428,6 +546,7 @@ int radeon_acpi_init(struct radeon_device *rdev) { acpi_handle handle; struct radeon_atif *atif = &rdev->atif; + struct radeon_atcs *atcs = &rdev->atcs; int ret; /* Get the device handle */ @@ -437,10 +556,16 @@ int radeon_acpi_init(struct radeon_device *rdev) if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) return 0; + /* Call the ATCS method */ + ret = radeon_atcs_verify_interface(handle, atcs); + if (ret) { + DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); + } + /* Call the ATIF method */ ret = radeon_atif_verify_interface(handle, atif); if (ret) { - DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret); + DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); goto out; } From 37e9b6a62fb775276f8edb5bd2b9f13a3102b9dd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 3 Aug 2012 11:39:43 -0400 Subject: [PATCH 28/79] drm/radeon: rework the backlight control to be an asic callback This cleans up the interface a bit as well. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 15 ++++---- drivers/gpu/drm/radeon/radeon.h | 5 ++- drivers/gpu/drm/radeon/radeon_acpi.c | 38 +++++++++++++------ drivers/gpu/drm/radeon/radeon_asic.c | 20 ++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 4 ++ .../gpu/drm/radeon/radeon_legacy_encoders.c | 33 ++++++++++------ drivers/gpu/drm/radeon/radeon_mode.h | 2 - 7 files changed, 84 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 370b2c4a7c86..f9910f099e6e 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -73,7 +73,7 @@ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, } void -atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) +atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { struct drm_encoder *encoder = &radeon_encoder->base; struct drm_device *dev = radeon_encoder->base.dev; @@ -82,8 +82,13 @@ atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder) DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) + return; + + if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && + radeon_encoder->enc_priv) { dig = radeon_encoder->enc_priv; + dig->backlight_level = level; radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level); switch (radeon_encoder->encoder_id) { @@ -137,11 +142,7 @@ static int radeon_atom_backlight_update_status(struct backlight_device *bd) struct radeon_backlight_privdata *pdata = bl_get_data(bd); struct radeon_encoder *radeon_encoder = pdata->encoder; - if (radeon_encoder->enc_priv) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - dig->backlight_level = radeon_atom_bl_level(bd); - atombios_set_panel_brightness(radeon_encoder); - } + atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd)); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 99a5c8445014..a1c4d4dac7df 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1153,6 +1153,8 @@ struct radeon_asic { u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc); /* wait for vblank */ void (*wait_for_vblank)(struct radeon_device *rdev, int crtc); + /* set backlight level */ + void (*set_backlight_level)(struct radeon_encoder *radeon_encoder, u8 level); } display; /* copy functions for bo handling */ struct { @@ -1461,7 +1463,7 @@ struct radeon_atif { struct radeon_atif_notifications notifications; struct radeon_atif_functions functions; struct radeon_atif_notification_cfg notification_cfg; - struct radeon_encoder *backlight_ctl; + struct radeon_encoder *encoder_for_bl; }; struct radeon_atcs_functions { @@ -1741,6 +1743,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) +#define radeon_set_backlight_level(rdev, e, l) (rdev)->asic->display.set_backlight_level((e), (l)) #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence)) #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) #define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index cae895ba8e2f..c3976eb341bf 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -364,19 +364,23 @@ int radeon_atif_handler(struct radeon_device *rdev, DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { - struct radeon_encoder *enc = atif->backlight_ctl; + struct radeon_encoder *enc = atif->encoder_for_bl; if (enc) { - struct radeon_encoder_atom_dig *dig = enc->enc_priv; - dig->backlight_level = req.backlight_level; - DRM_DEBUG_DRIVER("Changing brightness to %d\n", req.backlight_level); - atombios_set_panel_brightness(enc); + radeon_set_backlight_level(rdev, enc, req.backlight_level); - backlight_force_update(dig->bl_dev, - BACKLIGHT_UPDATE_HOTKEY); + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } else { + struct radeon_encoder_lvds *dig = enc->enc_priv; + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); + } } } /* TODO: check other events */ @@ -577,16 +581,26 @@ int radeon_acpi_init(struct radeon_device *rdev) list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, head) { struct radeon_encoder *enc = to_radeon_encoder(tmp); - struct radeon_encoder_atom_dig *dig = enc->enc_priv; if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && - dig->bl_dev != NULL) { - target = enc; - break; + enc->enc_priv) { + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *dig = enc->enc_priv; + if (dig->bl_dev) { + target = enc; + break; + } + } else { + struct radeon_encoder_lvds *dig = enc->enc_priv; + if (dig->bl_dev) { + target = enc; + break; + } + } } } - atif->backlight_ctl = target; + atif->encoder_for_bl = target; if (!target) { /* Brightness change notification is enabled, but we * didn't find a backlight controller, this should diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 973417c4b014..29834a2be3ea 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -198,6 +198,7 @@ static struct radeon_asic r100_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -272,6 +273,7 @@ static struct radeon_asic r200_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -346,6 +348,7 @@ static struct radeon_asic r300_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -420,6 +423,7 @@ static struct radeon_asic r300_asic_pcie = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -494,6 +498,7 @@ static struct radeon_asic r420_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -568,6 +573,7 @@ static struct radeon_asic rs400_asic = { .bandwidth_update = &r100_bandwidth_update, .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, + .set_backlight_level = &radeon_legacy_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -642,6 +648,7 @@ static struct radeon_asic rs600_asic = { .bandwidth_update = &rs600_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -716,6 +723,7 @@ static struct radeon_asic rs690_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .bandwidth_update = &rs690_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -790,6 +798,7 @@ static struct radeon_asic rv515_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .bandwidth_update = &rv515_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -864,6 +873,7 @@ static struct radeon_asic r520_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -937,6 +947,7 @@ static struct radeon_asic r600_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1010,6 +1021,7 @@ static struct radeon_asic rs780_asic = { .bandwidth_update = &rs690_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1083,6 +1095,7 @@ static struct radeon_asic rv770_asic = { .bandwidth_update = &rv515_bandwidth_update, .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1156,6 +1169,7 @@ static struct radeon_asic evergreen_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1229,6 +1243,7 @@ static struct radeon_asic sumo_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1302,6 +1317,7 @@ static struct radeon_asic btc_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1406,6 +1422,7 @@ static struct radeon_asic cayman_asic = { .bandwidth_update = &evergreen_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1500,6 +1517,7 @@ static struct radeon_asic trinity_asic = { .bandwidth_update = &dce6_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1604,6 +1622,7 @@ static struct radeon_asic si_asic = { .bandwidth_update = &dce6_bandwidth_update, .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, + .set_backlight_level = &atombios_set_backlight_level, }, .copy = { .blit = NULL, @@ -1697,6 +1716,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic->pm.set_engine_clock = &radeon_legacy_set_engine_clock; rdev->asic->pm.get_memory_clock = &radeon_legacy_get_memory_clock; rdev->asic->pm.set_memory_clock = NULL; + rdev->asic->display.set_backlight_level = &radeon_legacy_set_backlight_level; } break; case CHIP_RS400: diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 132429e0cccd..75d6c9e6aa8f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -42,6 +42,10 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev); void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock); void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); +void atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); +void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); + + /* * r100,rv100,rs100,rv200,rs200 */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 9910fe494744..ec00deaab9ca 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -290,10 +290,9 @@ static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) return level; } -static int radeon_legacy_backlight_update_status(struct backlight_device *bd) +void +radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { - struct radeon_backlight_privdata *pdata = bl_get_data(bd); - struct radeon_encoder *radeon_encoder = pdata->encoder; struct drm_device *dev = radeon_encoder->base.dev; struct radeon_device *rdev = dev->dev_private; int dpms_mode = DRM_MODE_DPMS_ON; @@ -301,19 +300,31 @@ static int radeon_legacy_backlight_update_status(struct backlight_device *bd) if (radeon_encoder->enc_priv) { if (rdev->is_atom_bios) { struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; - dpms_mode = lvds->dpms_mode; - lvds->backlight_level = radeon_legacy_lvds_level(bd); + if (lvds->backlight_level > 0) + dpms_mode = lvds->dpms_mode; + else + dpms_mode = DRM_MODE_DPMS_OFF; + lvds->backlight_level = level; } else { struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; - dpms_mode = lvds->dpms_mode; - lvds->backlight_level = radeon_legacy_lvds_level(bd); + if (lvds->backlight_level > 0) + dpms_mode = lvds->dpms_mode; + else + dpms_mode = DRM_MODE_DPMS_OFF; + lvds->backlight_level = level; } } - if (bd->props.brightness > 0) - radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); - else - radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF); + radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); +} + +static int radeon_legacy_backlight_update_status(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + + radeon_legacy_set_backlight_level(radeon_encoder, + radeon_legacy_lvds_level(bd)); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1f411c2609d8..5005057974b1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -698,8 +698,6 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc); -void atombios_set_panel_brightness(struct radeon_encoder *radeon_encoder); - /* legacy tv */ void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, From 1f0e29435386e42c942ee8385d10dbfc814f5cfe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 17 Aug 2012 10:31:34 -0400 Subject: [PATCH 29/79] drm/radeon/atom: add consolidate bpc code Several encoder setup functions had the same duplicated code for selecting the proper bpc setting for various atom tables. Consolidate it. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 96 +++++++--------------- 1 file changed, 29 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f9910f099e6e..dac32c8f76c4 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -439,6 +439,32 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) } +static u8 radeon_atom_get_bpc(struct drm_encoder *encoder) +{ + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int bpc = 8; + + if (connector) + bpc = radeon_get_monitor_bpc(connector); + + switch (bpc) { + case 0: + return PANEL_BPC_UNDEFINE; + case 6: + return PANEL_6BIT_PER_COLOR; + case 8: + default: + return PANEL_8BIT_PER_COLOR; + case 10: + return PANEL_10BIT_PER_COLOR; + case 12: + return PANEL_12BIT_PER_COLOR; + case 16: + return PANEL_16BIT_PER_COLOR; + } +} + + union dvo_encoder_control { ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; @@ -765,7 +791,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo int dp_clock = 0; int dp_lane_count = 0; int hpd_id = RADEON_HPD_NONE; - int bpc = 8; if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -775,7 +800,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo dp_clock = dig_connector->dp_clock; dp_lane_count = dig_connector->dp_lane_count; hpd_id = radeon_connector->hpd.hpd; - bpc = radeon_get_monitor_bpc(connector); } /* no dig encoder assigned */ @@ -852,27 +876,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; args.v3.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } + args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); break; case 4: args.v4.ucAction = action; @@ -896,27 +900,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; } args.v4.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } + args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); if (hpd_id == RADEON_HPD_NONE) args.v4.ucHPD_ID = 0; else @@ -1377,7 +1361,6 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, int dp_lane_count = 0; int connector_object_id = 0; u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - int bpc = 8; if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) connector = radeon_get_connector_for_encoder_init(encoder); @@ -1393,7 +1376,6 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, dp_lane_count = dig_connector->dp_lane_count; connector_object_id = (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - bpc = radeon_get_monitor_bpc(connector); } memset(&args, 0, sizeof(args)); @@ -1451,27 +1433,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; break; } - switch (bpc) { - case 0: - args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } + args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder); break; default: DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); From 4bf3dd9264cfb71f18714fcf2f810e276a44170b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 6 Aug 2012 18:57:44 +0200 Subject: [PATCH 30/79] drm/radeon: cleanup VM id handling a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store a reference to the VM into the IB structure, that makes calculating the IBs address a bit less complicated. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/ni.c | 5 +++-- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 5 +++-- drivers/gpu/drm/radeon/radeon_cs.c | 18 +++--------------- drivers/gpu/drm/radeon/radeon_ring.c | 14 +++++++++++--- drivers/gpu/drm/radeon/si.c | 5 +++-- 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 853800e8582f..fb6aa9dbd3a2 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -879,12 +879,13 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) #endif (ib->gpu_addr & 0xFFFFFFFC)); radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFF); - radeon_ring_write(ring, ib->length_dw | (ib->vm_id << 24)); + radeon_ring_write(ring, ib->length_dw | + (ib->vm ? (ib->vm->id << 24) : 0)); /* flush read cache over gart for this vmid */ radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); - radeon_ring_write(ring, ib->vm_id); + radeon_ring_write(ring, ib->vm ? ib->vm->id : 0); radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA); radeon_ring_write(ring, 0xFFFFFFFF); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ff3a444836d4..bf3d7902f5a0 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3800,7 +3800,7 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } WREG32(scratch, 0xCAFEDEAD); - r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, 256); + r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, NULL, 256); if (r) { return r; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 459c251991c1..fd4289bb78d9 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2635,7 +2635,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } WREG32(scratch, 0xCAFEDEAD); - r = radeon_ib_get(rdev, ring->idx, &ib, 256); + r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); return r; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a1c4d4dac7df..a5470e793043 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -592,7 +592,7 @@ struct radeon_ib { uint32_t *ptr; int ring; struct radeon_fence *fence; - unsigned vm_id; + struct radeon_vm *vm; bool is_const_ib; struct radeon_fence *sync_to[RADEON_NUM_RINGS]; struct radeon_semaphore *semaphore; @@ -734,7 +734,8 @@ struct si_rlc { }; int radeon_ib_get(struct radeon_device *rdev, int ring, - struct radeon_ib *ib, unsigned size); + struct radeon_ib *ib, struct radeon_vm *vm, + unsigned size); void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib); int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, struct radeon_ib *const_ib); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index b4a0db24f4dd..0a9d1eb719cf 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -363,7 +363,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, * uncached). */ r = radeon_ib_get(rdev, parser->ring, &parser->ib, - ib_chunk->length_dw * 4); + NULL, ib_chunk->length_dw * 4); if (r) { DRM_ERROR("Failed to get ib !\n"); return r; @@ -380,7 +380,6 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, return r; } radeon_cs_sync_rings(parser); - parser->ib.vm_id = 0; r = radeon_ib_schedule(rdev, &parser->ib, NULL); if (r) { DRM_ERROR("Failed to schedule IB !\n"); @@ -426,7 +425,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, return -EINVAL; } r = radeon_ib_get(rdev, parser->ring, &parser->const_ib, - ib_chunk->length_dw * 4); + vm, ib_chunk->length_dw * 4); if (r) { DRM_ERROR("Failed to get const ib !\n"); return r; @@ -450,7 +449,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, return -EINVAL; } r = radeon_ib_get(rdev, parser->ring, &parser->ib, - ib_chunk->length_dw * 4); + vm, ib_chunk->length_dw * 4); if (r) { DRM_ERROR("Failed to get ib !\n"); return r; @@ -478,19 +477,8 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, } radeon_cs_sync_rings(parser); - parser->ib.vm_id = vm->id; - /* ib pool is bind at 0 in virtual address space, - * so gpu_addr is the offset inside the pool bo - */ - parser->ib.gpu_addr = parser->ib.sa_bo->soffset; - if ((rdev->family >= CHIP_TAHITI) && (parser->chunk_const_ib_idx != -1)) { - parser->const_ib.vm_id = vm->id; - /* ib pool is bind at 0 in virtual address space, - * so gpu_addr is the offset inside the pool bo - */ - parser->const_ib.gpu_addr = parser->const_ib.sa_bo->soffset; r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib); } else { r = radeon_ib_schedule(rdev, &parser->ib, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 43c431a2686d..b9b1eddcd097 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -58,7 +58,8 @@ int radeon_debugfs_sa_init(struct radeon_device *rdev); * Returns 0 on success, error on failure. */ int radeon_ib_get(struct radeon_device *rdev, int ring, - struct radeon_ib *ib, unsigned size) + struct radeon_ib *ib, struct radeon_vm *vm, + unsigned size) { int i, r; @@ -76,8 +77,15 @@ int radeon_ib_get(struct radeon_device *rdev, int ring, ib->ring = ring; ib->fence = NULL; ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); - ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); - ib->vm_id = 0; + ib->vm = vm; + if (vm) { + /* ib pool is bind at 0 in virtual address space, + * so gpu_addr is the offset inside the pool bo + */ + ib->gpu_addr = ib->sa_bo->soffset; + } else { + ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); + } ib->is_const_ib = false; for (i = 0; i < RADEON_NUM_RINGS; ++i) ib->sync_to[i] = NULL; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 3feff33e9d7f..e0846ce65f65 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -1806,13 +1806,14 @@ void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) #endif (ib->gpu_addr & 0xFFFFFFFC)); radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); - radeon_ring_write(ring, ib->length_dw | (ib->vm_id << 24)); + radeon_ring_write(ring, ib->length_dw | + (ib->vm ? (ib->vm->id << 24) : 0)); if (!ib->is_const_ib) { /* flush read cache over gart for this vmid */ radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2); - radeon_ring_write(ring, ib->vm_id); + radeon_ring_write(ring, ib->vm ? ib->vm->id : 0); radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3)); radeon_ring_write(ring, PACKET3_TCL1_ACTION_ENA | PACKET3_TC_ACTION_ENA | From 05b0714768557c036fb9d74c197081fd2cba12bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 6 Aug 2012 20:21:10 +0200 Subject: [PATCH 31/79] drm/radeon: move VM funcs into asic structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So it looks more like the rest of the driver. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon.h | 35 ++++++++++--------- drivers/gpu/drm/radeon/radeon_asic.c | 50 +++++++++++++++------------- drivers/gpu/drm/radeon/radeon_gart.c | 16 ++++----- 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a5470e793043..5f54b87b181a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -641,28 +641,12 @@ struct radeon_vm { struct radeon_fence *fence; }; -struct radeon_vm_funcs { - int (*init)(struct radeon_device *rdev); - void (*fini)(struct radeon_device *rdev); - /* cs mutex must be lock for schedule_ib */ - int (*bind)(struct radeon_device *rdev, struct radeon_vm *vm, int id); - void (*unbind)(struct radeon_device *rdev, struct radeon_vm *vm); - void (*tlb_flush)(struct radeon_device *rdev, struct radeon_vm *vm); - uint32_t (*page_flags)(struct radeon_device *rdev, - struct radeon_vm *vm, - uint32_t flags); - void (*set_page)(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, uint64_t addr, uint32_t flags); -}; - struct radeon_vm_manager { struct mutex lock; struct list_head lru_vm; uint32_t use_bitmap; struct radeon_sa_manager sa_manager; uint32_t max_pfn; - /* fields constant after init */ - const struct radeon_vm_funcs *funcs; /* number of VMIDs */ unsigned nvm; /* vram base address for page table entry */ @@ -1128,6 +1112,18 @@ struct radeon_asic { void (*tlb_flush)(struct radeon_device *rdev); int (*set_page)(struct radeon_device *rdev, int i, uint64_t addr); } gart; + struct { + int (*init)(struct radeon_device *rdev); + void (*fini)(struct radeon_device *rdev); + int (*bind)(struct radeon_device *rdev, struct radeon_vm *vm, int id); + void (*unbind)(struct radeon_device *rdev, struct radeon_vm *vm); + void (*tlb_flush)(struct radeon_device *rdev, struct radeon_vm *vm); + uint32_t (*page_flags)(struct radeon_device *rdev, + struct radeon_vm *vm, + uint32_t flags); + void (*set_page)(struct radeon_device *rdev, struct radeon_vm *vm, + unsigned pfn, uint64_t addr, uint32_t flags); + } vm; /* ring specific callbacks */ struct { void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib); @@ -1735,6 +1731,13 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) +#define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) +#define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) +#define radeon_asic_vm_bind(rdev, v, id) (rdev)->asic->vm.bind((rdev), (v), (id)) +#define radeon_asic_vm_unbind(rdev, v) (rdev)->asic->vm.unbind((rdev), (v)) +#define radeon_asic_vm_tlb_flush(rdev, v) (rdev)->asic->vm.tlb_flush((rdev), (v)) +#define radeon_asic_vm_page_flags(rdev, v, flags) (rdev)->asic->vm.page_flags((rdev), (v), (flags)) +#define radeon_asic_vm_set_page(rdev, v, pfn, addr, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (addr), (flags)) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) #define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp)) #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 29834a2be3ea..951194c1d0a8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1358,16 +1358,6 @@ static struct radeon_asic btc_asic = { }, }; -static const struct radeon_vm_funcs cayman_vm_funcs = { - .init = &cayman_vm_init, - .fini = &cayman_vm_fini, - .bind = &cayman_vm_bind, - .unbind = &cayman_vm_unbind, - .tlb_flush = &cayman_vm_tlb_flush, - .page_flags = &cayman_vm_page_flags, - .set_page = &cayman_vm_set_page, -}; - static struct radeon_asic cayman_asic = { .init = &cayman_init, .fini = &cayman_fini, @@ -1382,6 +1372,15 @@ static struct radeon_asic cayman_asic = { .tlb_flush = &cayman_pcie_gart_tlb_flush, .set_page = &rs600_gart_set_page, }, + .vm = { + .init = &cayman_vm_init, + .fini = &cayman_vm_fini, + .bind = &cayman_vm_bind, + .unbind = &cayman_vm_unbind, + .tlb_flush = &cayman_vm_tlb_flush, + .page_flags = &cayman_vm_page_flags, + .set_page = &cayman_vm_set_page, + }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1477,6 +1476,15 @@ static struct radeon_asic trinity_asic = { .tlb_flush = &cayman_pcie_gart_tlb_flush, .set_page = &rs600_gart_set_page, }, + .vm = { + .init = &cayman_vm_init, + .fini = &cayman_vm_fini, + .bind = &cayman_vm_bind, + .unbind = &cayman_vm_unbind, + .tlb_flush = &cayman_vm_tlb_flush, + .page_flags = &cayman_vm_page_flags, + .set_page = &cayman_vm_set_page, + }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1558,16 +1566,6 @@ static struct radeon_asic trinity_asic = { }, }; -static const struct radeon_vm_funcs si_vm_funcs = { - .init = &si_vm_init, - .fini = &si_vm_fini, - .bind = &si_vm_bind, - .unbind = &si_vm_unbind, - .tlb_flush = &si_vm_tlb_flush, - .page_flags = &cayman_vm_page_flags, - .set_page = &cayman_vm_set_page, -}; - static struct radeon_asic si_asic = { .init = &si_init, .fini = &si_fini, @@ -1582,6 +1580,15 @@ static struct radeon_asic si_asic = { .tlb_flush = &si_pcie_gart_tlb_flush, .set_page = &rs600_gart_set_page, }, + .vm = { + .init = &si_vm_init, + .fini = &si_vm_fini, + .bind = &si_vm_bind, + .unbind = &si_vm_unbind, + .tlb_flush = &si_vm_tlb_flush, + .page_flags = &cayman_vm_page_flags, + .set_page = &cayman_vm_set_page, + }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1789,13 +1796,11 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic = &cayman_asic; /* set num crtcs */ rdev->num_crtc = 6; - rdev->vm_manager.funcs = &cayman_vm_funcs; break; case CHIP_ARUBA: rdev->asic = &trinity_asic; /* set num crtcs */ rdev->num_crtc = 4; - rdev->vm_manager.funcs = &cayman_vm_funcs; break; case CHIP_TAHITI: case CHIP_PITCAIRN: @@ -1803,7 +1808,6 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic = &si_asic; /* set num crtcs */ rdev->num_crtc = 6; - rdev->vm_manager.funcs = &si_vm_funcs; break; default: /* FIXME: not supported yet */ diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index bb3b7fe05ccd..b01c6435cb10 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -448,7 +448,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) return r; } - r = rdev->vm_manager.funcs->init(rdev); + r = radeon_asic_vm_init(rdev); if (r) return r; @@ -476,7 +476,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) } } - r = rdev->vm_manager.funcs->bind(rdev, vm, vm->id); + r = radeon_asic_vm_bind(rdev, vm, vm->id); if (r) { DRM_ERROR("Failed to bind vm %d!\n", vm->id); } @@ -522,7 +522,7 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, radeon_fence_unref(&vm->fence); /* hw unbind */ - rdev->vm_manager.funcs->unbind(rdev, vm); + radeon_asic_vm_unbind(rdev, vm); rdev->vm_manager.use_bitmap &= ~(1 << vm->id); list_del_init(&vm->list); vm->id = -1; @@ -553,7 +553,7 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) { radeon_vm_unbind_locked(rdev, vm); } - rdev->vm_manager.funcs->fini(rdev); + radeon_asic_vm_fini(rdev); mutex_unlock(&rdev->vm_manager.lock); radeon_sa_bo_manager_suspend(rdev, &rdev->vm_manager.sa_manager); @@ -639,7 +639,7 @@ retry_id: } /* do hw bind */ - r = rdev->vm_manager.funcs->bind(rdev, vm, id); + r = radeon_asic_vm_bind(rdev, vm, id); if (r) { radeon_sa_bo_free(rdev, &vm->sa_bo, NULL); return r; @@ -830,14 +830,14 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, } } pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; - flags = rdev->vm_manager.funcs->page_flags(rdev, bo_va->vm, bo_va->flags); + flags = radeon_asic_vm_page_flags(rdev, bo_va->vm, bo_va->flags); for (i = 0, addr = 0; i < ngpu_pages; i++) { if (mem && bo_va->valid) { addr = radeon_vm_get_addr(rdev, mem, i); } - rdev->vm_manager.funcs->set_page(rdev, bo_va->vm, i + pfn, addr, flags); + radeon_asic_vm_set_page(rdev, bo_va->vm, i + pfn, addr, flags); } - rdev->vm_manager.funcs->tlb_flush(rdev, bo_va->vm); + radeon_asic_vm_tlb_flush(rdev, bo_va->vm); return 0; } From d66a76269a57f84b785f7449818b843de1f07915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 6 Aug 2012 20:45:03 +0200 Subject: [PATCH 32/79] drm/radeon: remove vm_unbind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It actually isn't very useful. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/ni.c | 11 ----------- drivers/gpu/drm/radeon/radeon.h | 2 -- drivers/gpu/drm/radeon/radeon_asic.c | 3 --- drivers/gpu/drm/radeon/radeon_gart.c | 1 - drivers/gpu/drm/radeon/si.c | 12 ------------ 5 files changed, 29 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index fb6aa9dbd3a2..7786c4a60d6c 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1509,17 +1509,6 @@ int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) return 0; } -void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm) -{ - WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (vm->id << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (vm->id << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0); - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-7 are the VM contexts0-7 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id); -} - void cayman_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm) { if (vm->id == -1) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5f54b87b181a..19a29db7c1f5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1116,7 +1116,6 @@ struct radeon_asic { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); int (*bind)(struct radeon_device *rdev, struct radeon_vm *vm, int id); - void (*unbind)(struct radeon_device *rdev, struct radeon_vm *vm); void (*tlb_flush)(struct radeon_device *rdev, struct radeon_vm *vm); uint32_t (*page_flags)(struct radeon_device *rdev, struct radeon_vm *vm, @@ -1734,7 +1733,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) #define radeon_asic_vm_bind(rdev, v, id) (rdev)->asic->vm.bind((rdev), (v), (id)) -#define radeon_asic_vm_unbind(rdev, v) (rdev)->asic->vm.unbind((rdev), (v)) #define radeon_asic_vm_tlb_flush(rdev, v) (rdev)->asic->vm.tlb_flush((rdev), (v)) #define radeon_asic_vm_page_flags(rdev, v, flags) (rdev)->asic->vm.page_flags((rdev), (v), (flags)) #define radeon_asic_vm_set_page(rdev, v, pfn, addr, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (addr), (flags)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 951194c1d0a8..f524735f05ad 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1376,7 +1376,6 @@ static struct radeon_asic cayman_asic = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, .bind = &cayman_vm_bind, - .unbind = &cayman_vm_unbind, .tlb_flush = &cayman_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, @@ -1480,7 +1479,6 @@ static struct radeon_asic trinity_asic = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, .bind = &cayman_vm_bind, - .unbind = &cayman_vm_unbind, .tlb_flush = &cayman_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, @@ -1584,7 +1582,6 @@ static struct radeon_asic si_asic = { .init = &si_vm_init, .fini = &si_vm_fini, .bind = &si_vm_bind, - .unbind = &si_vm_unbind, .tlb_flush = &si_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index b01c6435cb10..1bcf26ff6a36 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -522,7 +522,6 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, radeon_fence_unref(&vm->fence); /* hw unbind */ - radeon_asic_vm_unbind(rdev, vm); rdev->vm_manager.use_bitmap &= ~(1 << vm->id); list_del_init(&vm->list); vm->id = -1; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index e0846ce65f65..1a459ad485c9 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2803,18 +2803,6 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) return 0; } -void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm) -{ - if (vm->id < 8) - WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0); - else - WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2), 0); - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-15 are the VM contexts0-15 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id); -} - void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm) { if (vm->id == -1) From f82cbddddbd368f391d45738601fa29a75cfbe3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 9 Aug 2012 16:35:36 +0200 Subject: [PATCH 33/79] drm/radeon: add sync helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_cs.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 0a9d1eb719cf..85a80e467482 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -115,19 +115,27 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority return 0; } +static void radeon_cs_sync_to(struct radeon_cs_parser *p, + struct radeon_fence *fence) +{ + struct radeon_fence *other; + + if (!fence) + return; + + other = p->ib.sync_to[fence->ring]; + p->ib.sync_to[fence->ring] = radeon_fence_later(fence, other); +} + static void radeon_cs_sync_rings(struct radeon_cs_parser *p) { int i; for (i = 0; i < p->nrelocs; i++) { - struct radeon_fence *a, *b; - - if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj) + if (!p->relocs[i].robj) continue; - a = p->relocs[i].robj->tbo.sync_obj; - b = p->ib.sync_to[a->ring]; - p->ib.sync_to[a->ring] = radeon_fence_later(a, b); + radeon_cs_sync_to(p, p->relocs[i].robj->tbo.sync_obj); } } From 9b40e5d8427f12567749978f66e86e5e8fced5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 8 Aug 2012 12:22:43 +0200 Subject: [PATCH 34/79] drm/radeon: make VM flushs a ring operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move flushing the VMs as function into the rings. First step to make VM operations async. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/ni.c | 31 ++++++++++++++-------------- drivers/gpu/drm/radeon/radeon.h | 6 ++++-- drivers/gpu/drm/radeon/radeon_asic.c | 12 ++++++++--- drivers/gpu/drm/radeon/radeon_asic.h | 3 +-- drivers/gpu/drm/radeon/radeon_cs.c | 1 + drivers/gpu/drm/radeon/radeon_gart.c | 4 +++- drivers/gpu/drm/radeon/radeon_ring.c | 8 +++++++ drivers/gpu/drm/radeon/si.c | 15 -------------- 8 files changed, 42 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7786c4a60d6c..8e3d70c7c9b7 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1502,24 +1502,9 @@ int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (id << 2), 0); WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (id << 2), vm->last_pfn); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12); - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-7 are the VM contexts0-7 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << id); return 0; } -void cayman_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm) -{ - if (vm->id == -1) - return; - - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-7 are the VM contexts0-7 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id); -} - #define R600_PTE_VALID (1 << 0) #define R600_PTE_SYSTEM (1 << 1) #define R600_PTE_SNOOPED (1 << 2) @@ -1551,3 +1536,19 @@ void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, addr |= flags; writeq(addr, ptr + (pfn * 8)); } + +void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) +{ + struct radeon_ring *ring = &rdev->ring[ib->ring]; + + if (!ib->vm || ib->vm->id == -1) + return; + + /* flush hdp cache */ + radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); + radeon_ring_write(ring, 0x1); + + /* bits 0-7 are the VM contexts0-7 */ + radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); + radeon_ring_write(ring, 1 << ib->vm->id); +} diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 19a29db7c1f5..320355de9c54 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -639,6 +639,8 @@ struct radeon_vm { struct mutex mutex; /* last fence for cs using this vm */ struct radeon_fence *fence; + /* last flush or NULL if we still need to flush */ + struct radeon_fence *last_flush; }; struct radeon_vm_manager { @@ -1116,7 +1118,6 @@ struct radeon_asic { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); int (*bind)(struct radeon_device *rdev, struct radeon_vm *vm, int id); - void (*tlb_flush)(struct radeon_device *rdev, struct radeon_vm *vm); uint32_t (*page_flags)(struct radeon_device *rdev, struct radeon_vm *vm, uint32_t flags); @@ -1135,6 +1136,7 @@ struct radeon_asic { int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); + void (*vm_flush)(struct radeon_device *rdev, struct radeon_ib *ib); } ring[RADEON_NUM_RINGS]; /* irqs */ struct { @@ -1733,7 +1735,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) #define radeon_asic_vm_bind(rdev, v, id) (rdev)->asic->vm.bind((rdev), (v), (id)) -#define radeon_asic_vm_tlb_flush(rdev, v) (rdev)->asic->vm.tlb_flush((rdev), (v)) #define radeon_asic_vm_page_flags(rdev, v, flags) (rdev)->asic->vm.page_flags((rdev), (v), (flags)) #define radeon_asic_vm_set_page(rdev, v, pfn, addr, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (addr), (flags)) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) @@ -1742,6 +1743,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib)) #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib)) #define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp)) +#define radeon_ring_vm_flush(rdev, r, ib) (rdev)->asic->ring[(r)].vm_flush((rdev), (ib)) #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f524735f05ad..4a6e39f7ffd1 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1376,7 +1376,6 @@ static struct radeon_asic cayman_asic = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, .bind = &cayman_vm_bind, - .tlb_flush = &cayman_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1390,6 +1389,7 @@ static struct radeon_asic cayman_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1400,6 +1400,7 @@ static struct radeon_asic cayman_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1410,6 +1411,7 @@ static struct radeon_asic cayman_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, } }, .irq = { @@ -1479,7 +1481,6 @@ static struct radeon_asic trinity_asic = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, .bind = &cayman_vm_bind, - .tlb_flush = &cayman_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1493,6 +1494,7 @@ static struct radeon_asic trinity_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1503,6 +1505,7 @@ static struct radeon_asic trinity_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &cayman_ring_ib_execute, @@ -1513,6 +1516,7 @@ static struct radeon_asic trinity_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, } }, .irq = { @@ -1582,7 +1586,6 @@ static struct radeon_asic si_asic = { .init = &si_vm_init, .fini = &si_vm_fini, .bind = &si_vm_bind, - .tlb_flush = &si_vm_tlb_flush, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1596,6 +1599,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1606,6 +1610,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1616,6 +1621,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, + .vm_flush = &cayman_vm_flush, } }, .irq = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 75d6c9e6aa8f..11a31d64bacc 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -442,7 +442,7 @@ int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id); void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); -void cayman_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm); +void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, struct radeon_vm *vm, uint32_t flags); @@ -472,7 +472,6 @@ int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id); void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); -void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); uint64_t si_get_gpu_clock(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 85a80e467482..d4a804b58feb 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -484,6 +484,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, goto out; } radeon_cs_sync_rings(parser); + radeon_cs_sync_to(parser, vm->last_flush); if ((rdev->family >= CHIP_TAHITI) && (parser->chunk_const_ib_idx != -1)) { diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 1bcf26ff6a36..125b7c31fafc 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -520,6 +520,7 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, break; } radeon_fence_unref(&vm->fence); + radeon_fence_unref(&vm->last_flush); /* hw unbind */ rdev->vm_manager.use_bitmap &= ~(1 << vm->id); @@ -639,6 +640,7 @@ retry_id: /* do hw bind */ r = radeon_asic_vm_bind(rdev, vm, id); + radeon_fence_unref(&vm->last_flush); if (r) { radeon_sa_bo_free(rdev, &vm->sa_bo, NULL); return r; @@ -836,7 +838,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, } radeon_asic_vm_set_page(rdev, bo_va->vm, i + pfn, addr, flags); } - radeon_asic_vm_tlb_flush(rdev, bo_va->vm); + radeon_fence_unref(&vm->last_flush); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index b9b1eddcd097..b4df25e2ac88 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -160,6 +160,10 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, if (!need_sync) { radeon_semaphore_free(rdev, &ib->semaphore, NULL); } + /* if we can't remember our last VM flush then flush now! */ + if (ib->vm && !ib->vm->last_flush) { + radeon_ring_vm_flush(rdev, ib->ring, ib); + } if (const_ib) { radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); radeon_semaphore_free(rdev, &const_ib->semaphore, NULL); @@ -174,6 +178,10 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, if (const_ib) { const_ib->fence = radeon_fence_ref(ib->fence); } + /* we just flushed the VM, remember that */ + if (ib->vm && !ib->vm->last_flush) { + ib->vm->last_flush = radeon_fence_ref(ib->fence); + } radeon_ring_unlock_commit(rdev, ring); return 0; } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1a459ad485c9..4016927b268d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2796,24 +2796,9 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) else WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((id - 8) << 2), vm->pt_gpu_addr >> 12); - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-15 are the VM contexts0-15 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << id); return 0; } -void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm) -{ - if (vm->id == -1) - return; - - /* flush hdp cache */ - WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); - /* bits 0-15 are the VM contexts0-15 */ - WREG32(VM_INVALIDATE_REQUEST, 1 << vm->id); -} - /* * RLC */ From ee60e29f1dc650bf2239b757038973ef32f10878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 9 Aug 2012 16:21:08 +0200 Subject: [PATCH 35/79] drm/radeon: rework VMID handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move binding onto the ring, simplifying handling a bit. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/ni.c | 20 ++-- drivers/gpu/drm/radeon/radeon.h | 30 +++++- drivers/gpu/drm/radeon/radeon_asic.c | 9 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 +- drivers/gpu/drm/radeon/radeon_cs.c | 9 +- drivers/gpu/drm/radeon/radeon_device.c | 1 - drivers/gpu/drm/radeon/radeon_gart.c | 128 +++++++++++++++++-------- drivers/gpu/drm/radeon/si.c | 30 ++++-- 8 files changed, 154 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 8e3d70c7c9b7..de378d685803 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1497,14 +1497,6 @@ void cayman_vm_fini(struct radeon_device *rdev) { } -int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) -{ - WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (id << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (id << 2), vm->last_pfn); - WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12); - return 0; -} - #define R600_PTE_VALID (1 << 0) #define R600_PTE_SYSTEM (1 << 1) #define R600_PTE_SNOOPED (1 << 2) @@ -1540,10 +1532,20 @@ void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) { struct radeon_ring *ring = &rdev->ring[ib->ring]; + struct radeon_vm *vm = ib->vm; - if (!ib->vm || ib->vm->id == -1) + if (vm == NULL) return; + radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (vm->id << 2), 0)); + radeon_ring_write(ring, 0); + + radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (vm->id << 2), 0)); + radeon_ring_write(ring, vm->last_pfn); + + radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0)); + radeon_ring_write(ring, vm->pt_gpu_addr >> 12); + /* flush hdp cache */ radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); radeon_ring_write(ring, 0x1); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 320355de9c54..617ca45734de 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -253,6 +253,22 @@ static inline struct radeon_fence *radeon_fence_later(struct radeon_fence *a, } } +static inline bool radeon_fence_is_earlier(struct radeon_fence *a, + struct radeon_fence *b) +{ + if (!a) { + return false; + } + + if (!b) { + return true; + } + + BUG_ON(a->ring != b->ring); + + return a->seq < b->seq; +} + /* * Tiling registers */ @@ -628,10 +644,13 @@ struct radeon_ring { /* * VM */ + +#define RADEON_NUM_VM 16 + struct radeon_vm { struct list_head list; struct list_head va; - int id; + unsigned id; unsigned last_pfn; u64 pt_gpu_addr; u64 *pt; @@ -646,7 +665,7 @@ struct radeon_vm { struct radeon_vm_manager { struct mutex lock; struct list_head lru_vm; - uint32_t use_bitmap; + struct radeon_fence *active[RADEON_NUM_VM]; struct radeon_sa_manager sa_manager; uint32_t max_pfn; /* number of VMIDs */ @@ -1117,7 +1136,6 @@ struct radeon_asic { struct { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); - int (*bind)(struct radeon_device *rdev, struct radeon_vm *vm, int id); uint32_t (*page_flags)(struct radeon_device *rdev, struct radeon_vm *vm, uint32_t flags); @@ -1734,7 +1752,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) -#define radeon_asic_vm_bind(rdev, v, id) (rdev)->asic->vm.bind((rdev), (v), (id)) #define radeon_asic_vm_page_flags(rdev, v, flags) (rdev)->asic->vm.page_flags((rdev), (v), (flags)) #define radeon_asic_vm_set_page(rdev, v, pfn, addr, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (addr), (flags)) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) @@ -1817,6 +1834,11 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm); void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm); int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm); void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); +struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, + struct radeon_vm *vm, int ring); +void radeon_vm_fence(struct radeon_device *rdev, + struct radeon_vm *vm, + struct radeon_fence *fence); int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 4a6e39f7ffd1..98c586ac1999 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1375,7 +1375,6 @@ static struct radeon_asic cayman_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .bind = &cayman_vm_bind, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1480,7 +1479,6 @@ static struct radeon_asic trinity_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .bind = &cayman_vm_bind, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1585,7 +1583,6 @@ static struct radeon_asic si_asic = { .vm = { .init = &si_vm_init, .fini = &si_vm_fini, - .bind = &si_vm_bind, .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, @@ -1599,7 +1596,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, - .vm_flush = &cayman_vm_flush, + .vm_flush = &si_vm_flush, }, [CAYMAN_RING_TYPE_CP1_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1610,7 +1607,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, - .vm_flush = &cayman_vm_flush, + .vm_flush = &si_vm_flush, }, [CAYMAN_RING_TYPE_CP2_INDEX] = { .ib_execute = &si_ring_ib_execute, @@ -1621,7 +1618,7 @@ static struct radeon_asic si_asic = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &si_gpu_is_lockup, - .vm_flush = &cayman_vm_flush, + .vm_flush = &si_vm_flush, } }, .irq = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 11a31d64bacc..25e8d000dac9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -440,7 +440,6 @@ int cayman_asic_reset(struct radeon_device *rdev); void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); -int cayman_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id); void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, @@ -470,8 +469,7 @@ int si_irq_set(struct radeon_device *rdev); int si_irq_process(struct radeon_device *rdev); int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); -int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id); -void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); +void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); uint64_t si_get_gpu_clock(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index d4a804b58feb..dc4554e0a711 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -485,6 +485,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, } radeon_cs_sync_rings(parser); radeon_cs_sync_to(parser, vm->last_flush); + radeon_cs_sync_to(parser, radeon_vm_grab_id(rdev, vm, parser->ring)); if ((rdev->family >= CHIP_TAHITI) && (parser->chunk_const_ib_idx != -1)) { @@ -493,13 +494,11 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, r = radeon_ib_schedule(rdev, &parser->ib, NULL); } -out: if (!r) { - if (vm->fence) { - radeon_fence_unref(&vm->fence); - } - vm->fence = radeon_fence_ref(parser->ib.fence); + radeon_vm_fence(rdev, vm, parser->ib.fence); } + +out: mutex_unlock(&vm->mutex); mutex_unlock(&rdev->vm_manager.lock); return r; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index c78f0346dfe4..331a952c9b53 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1018,7 +1018,6 @@ int radeon_device_init(struct radeon_device *rdev, return r; /* initialize vm here */ mutex_init(&rdev->vm_manager.lock); - rdev->vm_manager.use_bitmap = 1; rdev->vm_manager.max_pfn = 1 << 20; INIT_LIST_HEAD(&rdev->vm_manager.lru_vm); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 125b7c31fafc..0fd0ba9236a6 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -437,7 +437,6 @@ int radeon_vm_manager_init(struct radeon_device *rdev) int r; if (!rdev->vm_manager.enabled) { - /* mark first vm as always in use, it's the system one */ /* allocate enough for 2 full VM pts */ r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, rdev->vm_manager.max_pfn * 8 * 2, @@ -461,7 +460,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) /* restore page table */ list_for_each_entry(vm, &rdev->vm_manager.lru_vm, list) { - if (vm->id == -1) + if (vm->sa_bo == NULL) continue; list_for_each_entry(bo_va, &vm->va, vm_list) { @@ -475,11 +474,6 @@ int radeon_vm_manager_init(struct radeon_device *rdev) DRM_ERROR("Failed to update pte for vm %d!\n", vm->id); } } - - r = radeon_asic_vm_bind(rdev, vm, vm->id); - if (r) { - DRM_ERROR("Failed to bind vm %d!\n", vm->id); - } } return 0; } @@ -500,10 +494,6 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, { struct radeon_bo_va *bo_va; - if (vm->id == -1) { - return; - } - /* wait for vm use to end */ while (vm->fence) { int r; @@ -523,9 +513,7 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, radeon_fence_unref(&vm->last_flush); /* hw unbind */ - rdev->vm_manager.use_bitmap &= ~(1 << vm->id); list_del_init(&vm->list); - vm->id = -1; radeon_sa_bo_free(rdev, &vm->sa_bo, NULL); vm->pt = NULL; @@ -544,6 +532,7 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev, void radeon_vm_manager_fini(struct radeon_device *rdev) { struct radeon_vm *vm, *tmp; + int i; if (!rdev->vm_manager.enabled) return; @@ -553,6 +542,9 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) { radeon_vm_unbind_locked(rdev, vm); } + for (i = 0; i < RADEON_NUM_VM; ++i) { + radeon_fence_unref(&rdev->vm_manager.active[i]); + } radeon_asic_vm_fini(rdev); mutex_unlock(&rdev->vm_manager.lock); @@ -593,14 +585,13 @@ void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm) int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm) { struct radeon_vm *vm_evict; - unsigned i; - int id = -1, r; + int r; if (vm == NULL) { return -EINVAL; } - if (vm->id != -1) { + if (vm->sa_bo != NULL) { /* update lru */ list_del_init(&vm->list); list_add_tail(&vm->list, &rdev->vm_manager.lru_vm); @@ -623,35 +614,88 @@ retry: vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo); memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8)); -retry_id: - /* search for free vm */ - for (i = 0; i < rdev->vm_manager.nvm; i++) { - if (!(rdev->vm_manager.use_bitmap & (1 << i))) { - id = i; - break; - } - } - /* evict vm if necessary */ - if (id == -1) { - vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list); - radeon_vm_unbind(rdev, vm_evict); - goto retry_id; - } - - /* do hw bind */ - r = radeon_asic_vm_bind(rdev, vm, id); - radeon_fence_unref(&vm->last_flush); - if (r) { - radeon_sa_bo_free(rdev, &vm->sa_bo, NULL); - return r; - } - rdev->vm_manager.use_bitmap |= 1 << id; - vm->id = id; list_add_tail(&vm->list, &rdev->vm_manager.lru_vm); return radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo, &rdev->ring_tmp_bo.bo->tbo.mem); } +/** + * radeon_vm_grab_id - allocate the next free VMID + * + * @rdev: radeon_device pointer + * @vm: vm to allocate id for + * @ring: ring we want to submit job to + * + * Allocate an id for the vm (cayman+). + * Returns the fence we need to sync to (if any). + * + * Global and local mutex must be locked! + */ +struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, + struct radeon_vm *vm, int ring) +{ + struct radeon_fence *best[RADEON_NUM_RINGS] = {}; + unsigned choices[2] = {}; + unsigned i; + + /* check if the id is still valid */ + if (vm->fence && vm->fence == rdev->vm_manager.active[vm->id]) + return NULL; + + /* we definately need to flush */ + radeon_fence_unref(&vm->last_flush); + + /* skip over VMID 0, since it is the system VM */ + for (i = 1; i < rdev->vm_manager.nvm; ++i) { + struct radeon_fence *fence = rdev->vm_manager.active[i]; + + if (fence == NULL) { + /* found a free one */ + vm->id = i; + return NULL; + } + + if (radeon_fence_is_earlier(fence, best[fence->ring])) { + best[fence->ring] = fence; + choices[fence->ring == ring ? 0 : 1] = i; + } + } + + for (i = 0; i < 2; ++i) { + if (choices[i]) { + vm->id = choices[i]; + return rdev->vm_manager.active[choices[i]]; + } + } + + /* should never happen */ + BUG(); + return NULL; +} + +/** + * radeon_vm_fence - remember fence for vm + * + * @rdev: radeon_device pointer + * @vm: vm we want to fence + * @fence: fence to remember + * + * Fence the vm (cayman+). + * Set the fence used to protect page table and id. + * + * Global and local mutex must be locked! + */ +void radeon_vm_fence(struct radeon_device *rdev, + struct radeon_vm *vm, + struct radeon_fence *fence) +{ + radeon_fence_unref(&rdev->vm_manager.active[vm->id]); + rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence); + + radeon_fence_unref(&vm->fence); + vm->fence = radeon_fence_ref(fence); +} + /* object have to be reserved */ /** * radeon_vm_bo_add - add a bo to a specific vm @@ -806,7 +850,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, uint32_t flags; /* nothing to do if vm isn't bound */ - if (vm->id == -1) + if (vm->sa_bo == NULL) return 0; bo_va = radeon_bo_va(bo, vm); @@ -928,7 +972,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) { int r; - vm->id = -1; + vm->id = 0; vm->fence = NULL; mutex_init(&vm->mutex); INIT_LIST_HEAD(&vm->list); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 4016927b268d..51a471dc319c 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2789,14 +2789,30 @@ void si_vm_fini(struct radeon_device *rdev) { } -int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id) +void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) { - if (id < 8) - WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (id << 2), vm->pt_gpu_addr >> 12); - else - WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((id - 8) << 2), - vm->pt_gpu_addr >> 12); - return 0; + struct radeon_ring *ring = &rdev->ring[ib->ring]; + struct radeon_vm *vm = ib->vm; + + if (vm == NULL) + return; + + if (vm->id < 8) { + radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + + (vm->id << 2), 0)); + } else { + radeon_ring_write(ring, PACKET0(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + + ((vm->id - 8) << 2), 0)); + } + radeon_ring_write(ring, vm->pt_gpu_addr >> 12); + + /* flush hdp cache */ + radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); + radeon_ring_write(ring, 0x1); + + /* bits 0-7 are the VM contexts0-7 */ + radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); + radeon_ring_write(ring, 1 << ib->vm->id); } /* From ddf03f5cdd98c6ea486f3007a5542241634c9093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 9 Aug 2012 20:02:28 +0200 Subject: [PATCH 36/79] drm/radeon: rework VM page table handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the need to wait for anything. Still not ideal, since we need to free pt on va remove. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon.h | 4 +- drivers/gpu/drm/radeon/radeon_cs.c | 28 +------ drivers/gpu/drm/radeon/radeon_gart.c | 107 +++++++++------------------ drivers/gpu/drm/radeon/radeon_sa.c | 22 +++--- 4 files changed, 44 insertions(+), 117 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 617ca45734de..d6cd1f57fece 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -301,7 +301,6 @@ struct radeon_bo_va { uint64_t soffset; uint64_t eoffset; uint32_t flags; - struct radeon_fence *fence; bool valid; }; @@ -1832,8 +1831,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev); void radeon_vm_manager_fini(struct radeon_device *rdev); int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm); void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm); -int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm); -void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); +int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm); struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, struct radeon_vm *vm, int ring); void radeon_vm_fence(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index dc4554e0a711..300fc25d9003 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -286,30 +286,6 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) return 0; } -static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser, - struct radeon_fence *fence) -{ - struct radeon_fpriv *fpriv = parser->filp->driver_priv; - struct radeon_vm *vm = &fpriv->vm; - struct radeon_bo_list *lobj; - - if (parser->chunk_ib_idx == -1) { - return; - } - if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) { - return; - } - - list_for_each_entry(lobj, &parser->validated, tv.head) { - struct radeon_bo_va *bo_va; - struct radeon_bo *rbo = lobj->bo; - - bo_va = radeon_bo_va(rbo, vm); - radeon_fence_unref(&bo_va->fence); - bo_va->fence = radeon_fence_ref(fence); - } -} - /** * cs_parser_fini() - clean parser states * @parser: parser structure holding parsing context. @@ -323,8 +299,6 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) unsigned i; if (!error) { - /* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */ - radeon_bo_vm_fence_va(parser, parser->ib.fence); ttm_eu_fence_buffer_objects(&parser->validated, parser->ib.fence); } else { @@ -475,7 +449,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, mutex_lock(&rdev->vm_manager.lock); mutex_lock(&vm->mutex); - r = radeon_vm_bind(rdev, vm); + r = radeon_vm_alloc_pt(rdev, vm); if (r) { goto out; } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 0fd0ba9236a6..da1b2dbe4550 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -478,43 +478,26 @@ int radeon_vm_manager_init(struct radeon_device *rdev) return 0; } -/* global mutex must be lock */ /** - * radeon_vm_unbind_locked - unbind a specific vm + * radeon_vm_free_pt - free the page table for a specific vm * * @rdev: radeon_device pointer * @vm: vm to unbind * - * Unbind the requested vm (cayman+). - * Wait for use of the VM to finish, then unbind the page table, - * and free the page table memory. + * Free the page table of a specific vm (cayman+). + * + * Global and local mutex must be lock! */ -static void radeon_vm_unbind_locked(struct radeon_device *rdev, +static void radeon_vm_free_pt(struct radeon_device *rdev, struct radeon_vm *vm) { struct radeon_bo_va *bo_va; - /* wait for vm use to end */ - while (vm->fence) { - int r; - r = radeon_fence_wait(vm->fence, false); - if (r) - DRM_ERROR("error while waiting for fence: %d\n", r); - if (r == -EDEADLK) { - mutex_unlock(&rdev->vm_manager.lock); - r = radeon_gpu_reset(rdev); - mutex_lock(&rdev->vm_manager.lock); - if (!r) - continue; - } - break; - } - radeon_fence_unref(&vm->fence); - radeon_fence_unref(&vm->last_flush); + if (!vm->sa_bo) + return; - /* hw unbind */ list_del_init(&vm->list); - radeon_sa_bo_free(rdev, &vm->sa_bo, NULL); + radeon_sa_bo_free(rdev, &vm->sa_bo, vm->fence); vm->pt = NULL; list_for_each_entry(bo_va, &vm->va, vm_list) { @@ -538,9 +521,11 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) return; mutex_lock(&rdev->vm_manager.lock); - /* unbind all active vm */ + /* free all allocated page tables */ list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) { - radeon_vm_unbind_locked(rdev, vm); + mutex_lock(&vm->mutex); + radeon_vm_free_pt(rdev, vm); + mutex_unlock(&vm->mutex); } for (i = 0; i < RADEON_NUM_VM; ++i) { radeon_fence_unref(&rdev->vm_manager.active[i]); @@ -553,36 +538,19 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) rdev->vm_manager.enabled = false; } -/* global mutex must be locked */ /** - * radeon_vm_unbind - locked version of unbind - * - * @rdev: radeon_device pointer - * @vm: vm to unbind - * - * Locked version that wraps radeon_vm_unbind_locked (cayman+). - */ -void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm) -{ - mutex_lock(&vm->mutex); - radeon_vm_unbind_locked(rdev, vm); - mutex_unlock(&vm->mutex); -} - -/* global and local mutex must be locked */ -/** - * radeon_vm_bind - bind a page table to a VMID + * radeon_vm_alloc_pt - allocates a page table for a VM * * @rdev: radeon_device pointer * @vm: vm to bind * - * Bind the requested vm (cayman+). - * Suballocate memory for the page table, allocate a VMID - * and bind the page table to it, and finally start to populate - * the page table. + * Allocate a page table for the requested vm (cayman+). + * Also starts to populate the page table. * Returns 0 for success, error for failure. + * + * Global and local mutex must be locked! */ -int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm) +int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) { struct radeon_vm *vm_evict; int r; @@ -602,14 +570,20 @@ retry: r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8), RADEON_GPU_PAGE_SIZE, false); - if (r) { + if (r == -ENOMEM) { if (list_empty(&rdev->vm_manager.lru_vm)) { return r; } vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list); - radeon_vm_unbind(rdev, vm_evict); + mutex_lock(&vm_evict->mutex); + radeon_vm_free_pt(rdev, vm_evict); + mutex_unlock(&vm_evict->mutex); goto retry; + + } else if (r) { + return r; } + vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo); vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo); memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8)); @@ -758,7 +732,7 @@ int radeon_vm_bo_add(struct radeon_device *rdev, if (last_pfn > vm->last_pfn) { /* grow va space 32M by 32M */ unsigned align = ((32 << 20) >> 12) - 1; - radeon_vm_unbind_locked(rdev, vm); + radeon_vm_free_pt(rdev, vm); vm->last_pfn = (last_pfn + align) & ~align; } mutex_unlock(&rdev->vm_manager.lock); @@ -886,7 +860,6 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, return 0; } -/* object have to be reserved */ /** * radeon_vm_bo_rmv - remove a bo to a specific vm * @@ -898,36 +871,22 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, * Remove @bo from the list of bos associated with the vm and * remove the ptes for @bo in the page table. * Returns 0 for success. + * + * Object have to be reserved! */ int radeon_vm_bo_rmv(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo) { struct radeon_bo_va *bo_va; - int r; bo_va = radeon_bo_va(bo, vm); if (bo_va == NULL) return 0; - /* wait for va use to end */ - while (bo_va->fence) { - r = radeon_fence_wait(bo_va->fence, false); - if (r) { - DRM_ERROR("error while waiting for fence: %d\n", r); - } - if (r == -EDEADLK) { - r = radeon_gpu_reset(rdev); - if (!r) - continue; - } - break; - } - radeon_fence_unref(&bo_va->fence); - mutex_lock(&rdev->vm_manager.lock); mutex_lock(&vm->mutex); - radeon_vm_bo_update_pte(rdev, vm, bo, NULL); + radeon_vm_free_pt(rdev, vm); mutex_unlock(&rdev->vm_manager.lock); list_del(&bo_va->vm_list); mutex_unlock(&vm->mutex); @@ -1010,7 +969,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) mutex_lock(&rdev->vm_manager.lock); mutex_lock(&vm->mutex); - radeon_vm_unbind_locked(rdev, vm); + radeon_vm_free_pt(rdev, vm); mutex_unlock(&rdev->vm_manager.lock); /* remove all bo at this point non are busy any more because unbind @@ -1021,7 +980,6 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm); list_del_init(&bo_va->bo_list); list_del_init(&bo_va->vm_list); - radeon_fence_unref(&bo_va->fence); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); kfree(bo_va); } @@ -1033,10 +991,11 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) r = radeon_bo_reserve(bo_va->bo, false); if (!r) { list_del_init(&bo_va->bo_list); - radeon_fence_unref(&bo_va->fence); radeon_bo_unreserve(bo_va->bo); kfree(bo_va); } } + radeon_fence_unref(&vm->fence); + radeon_fence_unref(&vm->last_flush); mutex_unlock(&vm->mutex); } diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 4e771240fdd0..105fde69d045 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -316,7 +316,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, { struct radeon_fence *fences[RADEON_NUM_RINGS]; unsigned tries[RADEON_NUM_RINGS]; - int i, r = -ENOMEM; + int i, r; BUG_ON(align > RADEON_GPU_PAGE_SIZE); BUG_ON(size > sa_manager->size); @@ -331,7 +331,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, INIT_LIST_HEAD(&(*sa_bo)->flist); spin_lock(&sa_manager->wq.lock); - while(1) { + do { for (i = 0; i < RADEON_NUM_RINGS; ++i) { fences[i] = NULL; tries[i] = 0; @@ -349,26 +349,22 @@ int radeon_sa_bo_new(struct radeon_device *rdev, /* see if we can skip over some allocations */ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); - if (!block) { - break; - } - spin_unlock(&sa_manager->wq.lock); r = radeon_fence_wait_any(rdev, fences, false); spin_lock(&sa_manager->wq.lock); /* if we have nothing to wait for block */ - if (r == -ENOENT) { + if (r == -ENOENT && block) { r = wait_event_interruptible_locked( sa_manager->wq, radeon_sa_event(sa_manager, size, align) ); - } - if (r) { - goto out_err; - } - }; -out_err: + } else if (r == -ENOENT) { + r = -ENOMEM; + } + + } while (!r); + spin_unlock(&sa_manager->wq.lock); kfree(*sa_bo); *sa_bo = NULL; From 089a786e2cf5d07d495b3cb1ac0b959c6dd10d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 11 Aug 2012 11:54:05 +0200 Subject: [PATCH 37/79] drm/radeon: Move looping over the PTEs into chip code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes it easier to move it into the rings. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/ni.c | 22 +++++++++++++++------- drivers/gpu/drm/radeon/radeon.h | 12 ++++++------ drivers/gpu/drm/radeon/radeon_asic.c | 3 --- drivers/gpu/drm/radeon/radeon_asic.h | 7 +++---- drivers/gpu/drm/radeon/radeon_gart.c | 24 ++++++++++-------------- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index de378d685803..8bec8113d3a1 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1503,9 +1503,7 @@ void cayman_vm_fini(struct radeon_device *rdev) #define R600_PTE_READABLE (1 << 5) #define R600_PTE_WRITEABLE (1 << 6) -uint32_t cayman_vm_page_flags(struct radeon_device *rdev, - struct radeon_vm *vm, - uint32_t flags) +uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags) { uint32_t r600_flags = 0; @@ -1520,13 +1518,23 @@ uint32_t cayman_vm_page_flags(struct radeon_device *rdev, } void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, uint64_t addr, uint32_t flags) + unsigned pfn, struct ttm_mem_reg *mem, + unsigned npages, uint32_t flags) { void __iomem *ptr = (void *)vm->pt; + uint64_t addr; + int i; - addr = addr & 0xFFFFFFFFFFFFF000ULL; - addr |= flags; - writeq(addr, ptr + (pfn * 8)); + addr = flags = cayman_vm_page_flags(rdev, flags); + + for (i = 0; i < npages; ++i, ++pfn) { + if (mem) { + addr = radeon_vm_get_addr(rdev, mem, i); + addr = addr & 0xFFFFFFFFFFFFF000ULL; + addr |= flags; + } + writeq(addr, ptr + (pfn * 8)); + } } void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d6cd1f57fece..ae7409a0f62b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1135,11 +1135,9 @@ struct radeon_asic { struct { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); - uint32_t (*page_flags)(struct radeon_device *rdev, - struct radeon_vm *vm, - uint32_t flags); void (*set_page)(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, uint64_t addr, uint32_t flags); + unsigned pfn, struct ttm_mem_reg *mem, + unsigned npages, uint32_t flags); } vm; /* ring specific callbacks */ struct { @@ -1751,8 +1749,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) -#define radeon_asic_vm_page_flags(rdev, v, flags) (rdev)->asic->vm.page_flags((rdev), (v), (flags)) -#define radeon_asic_vm_set_page(rdev, v, pfn, addr, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (addr), (flags)) +#define radeon_asic_vm_set_page(rdev, v, pfn, mem, npages, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (mem), (npages), (flags)) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) #define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp)) #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp)) @@ -1837,6 +1834,9 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, void radeon_vm_fence(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_fence *fence); +u64 radeon_vm_get_addr(struct radeon_device *rdev, + struct ttm_mem_reg *mem, + unsigned pfn); int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 98c586ac1999..6e4e67edf60f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1375,7 +1375,6 @@ static struct radeon_asic cayman_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1479,7 +1478,6 @@ static struct radeon_asic trinity_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1583,7 +1581,6 @@ static struct radeon_asic si_asic = { .vm = { .init = &si_vm_init, .fini = &si_vm_fini, - .page_flags = &cayman_vm_page_flags, .set_page = &cayman_vm_set_page, }, .ring = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 25e8d000dac9..2b3dd3173022 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -442,11 +442,10 @@ int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); -uint32_t cayman_vm_page_flags(struct radeon_device *rdev, - struct radeon_vm *vm, - uint32_t flags); +uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, uint64_t addr, uint32_t flags); + unsigned pfn, struct ttm_mem_reg *mem, + unsigned npages, uint32_t flags); int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); /* DCE6 - SI */ diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index da1b2dbe4550..0f9a40f84d7a 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -450,7 +450,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) r = radeon_asic_vm_init(rdev); if (r) return r; - + rdev->vm_manager.enabled = true; r = radeon_sa_bo_manager_start(rdev, &rdev->vm_manager.sa_manager); @@ -773,9 +773,9 @@ int radeon_vm_bo_add(struct radeon_device *rdev, * to (cayman+). * Returns the physical address of the page. */ -static u64 radeon_vm_get_addr(struct radeon_device *rdev, - struct ttm_mem_reg *mem, - unsigned pfn) +u64 radeon_vm_get_addr(struct radeon_device *rdev, + struct ttm_mem_reg *mem, + unsigned pfn) { u64 addr = 0; @@ -819,9 +819,8 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct ttm_mem_reg *mem) { struct radeon_bo_va *bo_va; - unsigned ngpu_pages, i; - uint64_t addr = 0, pfn; - uint32_t flags; + unsigned ngpu_pages; + uint64_t pfn; /* nothing to do if vm isn't bound */ if (vm->sa_bo == NULL) @@ -848,14 +847,11 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, bo_va->flags |= RADEON_VM_PAGE_SYSTEM; } } - pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; - flags = radeon_asic_vm_page_flags(rdev, bo_va->vm, bo_va->flags); - for (i = 0, addr = 0; i < ngpu_pages; i++) { - if (mem && bo_va->valid) { - addr = radeon_vm_get_addr(rdev, mem, i); - } - radeon_asic_vm_set_page(rdev, bo_va->vm, i + pfn, addr, flags); + if (!bo_va->valid) { + mem = NULL; } + pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; + radeon_asic_vm_set_page(rdev, bo_va->vm, pfn, mem, ngpu_pages, bo_va->flags); radeon_fence_unref(&vm->last_flush); return 0; } From 3e8970f96ba2539539059736039f09624da9fe11 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 13 Aug 2012 12:07:33 -0400 Subject: [PATCH 38/79] drm/radeon: make sure ib bo is properly bound and up to date in vm space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that the ib bo is bound and is page table is up to date in the virtual address space. Signed-off-by: Jerome Glisse Reviewed-by: Christian König --- drivers/gpu/drm/radeon/radeon_cs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 300fc25d9003..3ae7c27c9d6c 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -372,10 +372,15 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser, struct radeon_vm *vm) { + struct radeon_device *rdev = parser->rdev; struct radeon_bo_list *lobj; struct radeon_bo *bo; int r; + r = radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo, &rdev->ring_tmp_bo.bo->tbo.mem); + if (r) { + return r; + } list_for_each_entry(lobj, &parser->validated, tv.head) { bo = lobj->bo; r = radeon_vm_bo_update_pte(parser->rdev, vm, bo, &bo->tbo.mem); From 2a6f1abbb48f1d90f20b8198c4894c0469468405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 11 Aug 2012 15:00:30 +0200 Subject: [PATCH 39/79] drm/radeon: make page table updates async v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently doing the update with the CP. v2: Rebased on Jeromes bugfix. Make validity comparison more human readable. Signed-off-by: Christian König --- drivers/gpu/drm/radeon/ni.c | 20 ++++---- drivers/gpu/drm/radeon/nid.h | 1 + drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_asic.c | 3 ++ drivers/gpu/drm/radeon/radeon_gart.c | 70 +++++++++++++++++++++------- 5 files changed, 71 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 8bec8113d3a1..c803328c0cf9 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1521,20 +1521,24 @@ void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, unsigned pfn, struct ttm_mem_reg *mem, unsigned npages, uint32_t flags) { - void __iomem *ptr = (void *)vm->pt; - uint64_t addr; + struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index]; + uint64_t addr, pt = vm->pt_gpu_addr + pfn * 8; int i; addr = flags = cayman_vm_page_flags(rdev, flags); - for (i = 0; i < npages; ++i, ++pfn) { - if (mem) { - addr = radeon_vm_get_addr(rdev, mem, i); + radeon_ring_write(ring, PACKET3(PACKET3_ME_WRITE, 1 + npages * 2)); + radeon_ring_write(ring, pt & 0xffffffff); + radeon_ring_write(ring, (pt >> 32) & 0xff); + for (i = 0; i < npages; ++i) { + if (mem) { + addr = radeon_vm_get_addr(rdev, mem, i); addr = addr & 0xFFFFFFFFFFFFF000ULL; addr |= flags; - } - writeq(addr, ptr + (pfn * 8)); - } + } + radeon_ring_write(ring, addr & 0xffffffff); + radeon_ring_write(ring, (addr >> 32) & 0xffffffff); + } } void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 870db340d377..2423d1b5d385 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -585,6 +585,7 @@ #define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 #define PACKET3_SET_RESOURCE_INDIRECT 0x74 #define PACKET3_SET_APPEND_CNT 0x75 +#define PACKET3_ME_WRITE 0x7A #endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ae7409a0f62b..d48bd3045db6 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1135,6 +1135,8 @@ struct radeon_asic { struct { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); + + u32 pt_ring_index; void (*set_page)(struct radeon_device *rdev, struct radeon_vm *vm, unsigned pfn, struct ttm_mem_reg *mem, unsigned npages, uint32_t flags); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 6e4e67edf60f..2f7adeab049b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1375,6 +1375,7 @@ static struct radeon_asic cayman_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1478,6 +1479,7 @@ static struct radeon_asic trinity_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &cayman_vm_set_page, }, .ring = { @@ -1581,6 +1583,7 @@ static struct radeon_asic si_asic = { .vm = { .init = &si_vm_init, .fini = &si_vm_fini, + .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .set_page = &cayman_vm_set_page, }, .ring = { diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 0f9a40f84d7a..d7bd46bd9067 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -464,15 +464,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev) continue; list_for_each_entry(bo_va, &vm->va, vm_list) { - struct ttm_mem_reg *mem = NULL; - if (bo_va->valid) - mem = &bo_va->bo->tbo.mem; - bo_va->valid = false; - r = radeon_vm_bo_update_pte(rdev, vm, bo_va->bo, mem); - if (r) { - DRM_ERROR("Failed to update pte for vm %d!\n", vm->id); - } } } return 0; @@ -801,7 +793,6 @@ u64 radeon_vm_get_addr(struct radeon_device *rdev, return addr; } -/* object have to be reserved & global and local mutex must be locked */ /** * radeon_vm_bo_update_pte - map a bo into the vm page table * @@ -812,15 +803,21 @@ u64 radeon_vm_get_addr(struct radeon_device *rdev, * * Fill in the page table entries for @bo (cayman+). * Returns 0 for success, -EINVAL for failure. + * + * Object have to be reserved & global and local mutex must be locked! */ int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo, struct ttm_mem_reg *mem) { + unsigned ridx = rdev->asic->vm.pt_ring_index; + struct radeon_ring *ring = &rdev->ring[ridx]; + struct radeon_semaphore *sem = NULL; struct radeon_bo_va *bo_va; - unsigned ngpu_pages; + unsigned ngpu_pages, ndw; uint64_t pfn; + int r; /* nothing to do if vm isn't bound */ if (vm->sa_bo == NULL) @@ -832,7 +829,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, return -EINVAL; } - if (bo_va->valid && mem) + if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) return 0; ngpu_pages = radeon_bo_ngpu_pages(bo); @@ -846,12 +843,50 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, if (mem->mem_type == TTM_PL_TT) { bo_va->flags |= RADEON_VM_PAGE_SYSTEM; } - } - if (!bo_va->valid) { - mem = NULL; + if (!bo_va->valid) { + mem = NULL; + } + } else { + bo_va->valid = false; } pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; - radeon_asic_vm_set_page(rdev, bo_va->vm, pfn, mem, ngpu_pages, bo_va->flags); + + if (vm->fence && radeon_fence_signaled(vm->fence)) { + radeon_fence_unref(&vm->fence); + } + + if (vm->fence && vm->fence->ring != ridx) { + r = radeon_semaphore_create(rdev, &sem); + if (r) { + return r; + } + } + + /* estimate number of dw needed */ + ndw = 32; + ndw += (ngpu_pages >> 12) * 3; + ndw += ngpu_pages * 2; + + r = radeon_ring_lock(rdev, ring, ndw); + if (r) { + return r; + } + + if (sem && radeon_fence_need_sync(vm->fence, ridx)) { + radeon_semaphore_sync_rings(rdev, sem, vm->fence->ring, ridx); + radeon_fence_note_sync(vm->fence, ridx); + } + + radeon_asic_vm_set_page(rdev, vm, pfn, mem, ngpu_pages, bo_va->flags); + + radeon_fence_unref(&vm->fence); + r = radeon_fence_emit(rdev, &vm->fence, ridx); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } + radeon_ring_unlock_commit(rdev, ring); + radeon_semaphore_free(rdev, &sem, vm->fence); radeon_fence_unref(&vm->last_flush); return 0; } @@ -875,6 +910,7 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, struct radeon_bo *bo) { struct radeon_bo_va *bo_va; + int r; bo_va = radeon_bo_va(bo, vm); if (bo_va == NULL) @@ -882,14 +918,14 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, mutex_lock(&rdev->vm_manager.lock); mutex_lock(&vm->mutex); - radeon_vm_free_pt(rdev, vm); + r = radeon_vm_bo_update_pte(rdev, vm, bo, NULL); mutex_unlock(&rdev->vm_manager.lock); list_del(&bo_va->vm_list); mutex_unlock(&vm->mutex); list_del(&bo_va->bo_list); kfree(bo_va); - return 0; + return r; } /** From 7a083293c16bb334945fff8b33e3018fd375b33f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 31 Aug 2012 13:51:21 -0400 Subject: [PATCH 40/79] drm/radeon: document async VM changes in ni.c Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/ni.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index c803328c0cf9..e09d3a84a656 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1517,6 +1517,13 @@ uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags) return r600_flags; } +/** + * cayman_vm_set_page - update the page tables using the CP + * + * @rdev: radeon_device pointer + * + * Update the page tables using the CP (cayman-si). + */ void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, unsigned pfn, struct ttm_mem_reg *mem, unsigned npages, uint32_t flags) @@ -1541,6 +1548,14 @@ void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, } } +/** + * cayman_vm_flush - vm flush using the CP + * + * @rdev: radeon_device pointer + * + * Update the page table base and flush the VM TLB + * using the CP (cayman-si). + */ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) { struct radeon_ring *ring = &rdev->ring[ib->ring]; From 4755fab5fa949d68e8579eb2e7b73b8e9e75045e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Aug 2012 13:30:49 -0400 Subject: [PATCH 41/79] drm/radeon: implement bounds checking on thermal controller lookup Don't read past the end of the array if we encounter an unknown thermal controller. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_atombios.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index e368b3027cba..01b90b4f5e22 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2009,7 +2009,8 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); /* add the i2c bus for thermal/fan chip */ - if (power_info->info.ucOverdriveThermalController > 0) { + if ((power_info->info.ucOverdriveThermalController > 0) && + (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) { DRM_INFO("Possible %s thermal controller at 0x%02x\n", thermal_controller_names[power_info->info.ucOverdriveThermalController], power_info->info.ucOverdriveControllerAddress >> 1); @@ -2213,7 +2214,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucType == ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { DRM_INFO("Special thermal controller config\n"); - } else { + } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[controller->ucType], controller->ucI2cAddress >> 1, @@ -2228,6 +2229,12 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } + } else { + DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", + controller->ucType, + controller->ucI2cAddress >> 1, + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); } } } From b9ce0afeef13b18b12caec476f1e6dd76f0f094b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 31 Aug 2012 13:28:12 -0400 Subject: [PATCH 42/79] drm/radeon: remove dead function def Was removed in the async VM update series. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_asic.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2b3dd3173022..29b3d0545f94 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -440,11 +440,10 @@ int cayman_asic_reset(struct radeon_device *rdev); void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); -void cayman_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm); void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, struct ttm_mem_reg *mem, + unsigned pfn, struct ttm_mem_reg *mem, unsigned npages, uint32_t flags); int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); From 1109ca09b9e2f2766d64d037a88ea8816559b3b3 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Fri, 31 Aug 2012 13:43:50 -0400 Subject: [PATCH 43/79] drm/radeon: Mark all possible functions / structs as static Let's allow GCC to optimize better. This exposed some five unused functions, but this patch doesn't remove them. Signed-off-by: Lauri Kasanen Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 4 +-- drivers/gpu/drm/radeon/evergreen.c | 12 ++++----- drivers/gpu/drm/radeon/evergreen_cs.c | 2 +- drivers/gpu/drm/radeon/ni.c | 8 +++--- drivers/gpu/drm/radeon/r100.c | 14 +++++------ drivers/gpu/drm/radeon/r300.c | 4 +-- drivers/gpu/drm/radeon/r520.c | 4 +-- drivers/gpu/drm/radeon/r600.c | 18 ++++++------- drivers/gpu/drm/radeon/r600_cs.c | 2 +- drivers/gpu/drm/radeon/r600_hdmi.c | 2 +- drivers/gpu/drm/radeon/radeon_combios.c | 2 +- drivers/gpu/drm/radeon/radeon_connectors.c | 28 ++++++++++----------- drivers/gpu/drm/radeon/radeon_cs.c | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_fb.c | 2 +- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- drivers/gpu/drm/radeon/radeon_ioc32.c | 2 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 4 +-- drivers/gpu/drm/radeon/radeon_ring.c | 8 +++--- drivers/gpu/drm/radeon/radeon_test.c | 2 +- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 6 ++--- drivers/gpu/drm/radeon/rs600.c | 14 +++++------ drivers/gpu/drm/radeon/rs690.c | 6 ++--- drivers/gpu/drm/radeon/rv515.c | 18 ++++++------- drivers/gpu/drm/radeon/rv770.c | 10 ++++---- drivers/gpu/drm/radeon/si.c | 6 ++--- 27 files changed, 93 insertions(+), 93 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index dac32c8f76c4..07441cb718a3 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -2489,7 +2489,7 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = { .destroy = radeon_enc_destroy, }; -struct radeon_encoder_atom_dac * +static struct radeon_encoder_atom_dac * radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) { struct drm_device *dev = radeon_encoder->base.dev; @@ -2503,7 +2503,7 @@ radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) return dac; } -struct radeon_encoder_atom_dig * +static struct radeon_encoder_atom_dig * radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) { int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 90366e309495..ef47879c5d40 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1121,7 +1121,7 @@ void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev) } } -int evergreen_pcie_gart_enable(struct radeon_device *rdev) +static int evergreen_pcie_gart_enable(struct radeon_device *rdev) { u32 tmp; int r; @@ -1180,7 +1180,7 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) return 0; } -void evergreen_pcie_gart_disable(struct radeon_device *rdev) +static void evergreen_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; @@ -1205,7 +1205,7 @@ void evergreen_pcie_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void evergreen_pcie_gart_fini(struct radeon_device *rdev) +static void evergreen_pcie_gart_fini(struct radeon_device *rdev) { evergreen_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); @@ -1213,7 +1213,7 @@ void evergreen_pcie_gart_fini(struct radeon_device *rdev) } -void evergreen_agp_enable(struct radeon_device *rdev) +static void evergreen_agp_enable(struct radeon_device *rdev) { u32 tmp; @@ -1556,7 +1556,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) return 0; } -int evergreen_cp_resume(struct radeon_device *rdev) +static int evergreen_cp_resume(struct radeon_device *rdev) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; u32 tmp; @@ -2709,7 +2709,7 @@ static void evergreen_irq_ack(struct radeon_device *rdev) } } -void evergreen_irq_disable(struct radeon_device *rdev) +static void evergreen_irq_disable(struct radeon_device *rdev) { r600_disable_interrupts(rdev); /* Wait and acknowledge irq */ diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index e44a62a07fe3..0f32ea4d608b 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -995,7 +995,7 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p) * Assume that chunk_ib_index is properly set. Will return -EINVAL * if packet is bigger than remaining ib size. or if packets is unknown. **/ -int evergreen_cs_packet_parse(struct radeon_cs_parser *p, +static int evergreen_cs_packet_parse(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx) { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index e09d3a84a656..b23821674a95 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -726,7 +726,7 @@ void cayman_pcie_gart_tlb_flush(struct radeon_device *rdev) WREG32(VM_INVALIDATE_REQUEST, 1); } -int cayman_pcie_gart_enable(struct radeon_device *rdev) +static int cayman_pcie_gart_enable(struct radeon_device *rdev) { int i, r; @@ -793,7 +793,7 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) return 0; } -void cayman_pcie_gart_disable(struct radeon_device *rdev) +static void cayman_pcie_gart_disable(struct radeon_device *rdev) { /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); @@ -813,7 +813,7 @@ void cayman_pcie_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void cayman_pcie_gart_fini(struct radeon_device *rdev) +static void cayman_pcie_gart_fini(struct radeon_device *rdev) { cayman_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); @@ -1005,7 +1005,7 @@ static void cayman_cp_fini(struct radeon_device *rdev) radeon_scratch_free(rdev, ring->rptr_save_reg); } -int cayman_cp_resume(struct radeon_device *rdev) +static int cayman_cp_resume(struct radeon_device *rdev) { static const int ridx[] = { RADEON_RING_TYPE_GFX_INDEX, diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index bf3d7902f5a0..cd11760f2395 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2513,7 +2513,7 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track /* * Global GPU functions */ -void r100_errata(struct radeon_device *rdev) +static void r100_errata(struct radeon_device *rdev) { rdev->pll_errata = 0; @@ -2529,7 +2529,7 @@ void r100_errata(struct radeon_device *rdev) } /* Wait for vertical sync on primary CRTC */ -void r100_gpu_wait_for_vsync(struct radeon_device *rdev) +static void r100_gpu_wait_for_vsync(struct radeon_device *rdev) { uint32_t crtc_gen_cntl, tmp; int i; @@ -2551,7 +2551,7 @@ void r100_gpu_wait_for_vsync(struct radeon_device *rdev) } /* Wait for vertical sync on secondary CRTC */ -void r100_gpu_wait_for_vsync2(struct radeon_device *rdev) +static void r100_gpu_wait_for_vsync2(struct radeon_device *rdev) { uint32_t crtc2_gen_cntl, tmp; int i; @@ -2572,7 +2572,7 @@ void r100_gpu_wait_for_vsync2(struct radeon_device *rdev) } } -int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) +static int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) { unsigned i; uint32_t tmp; @@ -2933,7 +2933,7 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state) WREG32(RADEON_CONFIG_CNTL, temp); } -void r100_mc_init(struct radeon_device *rdev) +static void r100_mc_init(struct radeon_device *rdev) { u64 base; @@ -3005,7 +3005,7 @@ void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) r100_pll_errata_after_data(rdev); } -void r100_set_safe_registers(struct radeon_device *rdev) +static void r100_set_safe_registers(struct radeon_device *rdev) { if (ASIC_IS_RN50(rdev)) { rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm; @@ -3947,7 +3947,7 @@ static void r100_mc_program(struct radeon_device *rdev) r100_mc_resume(rdev, &save); } -void r100_clock_startup(struct radeon_device *rdev) +static void r100_clock_startup(struct radeon_device *rdev) { u32 tmp; diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 646a1927dda7..4949bfc14b58 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -296,7 +296,7 @@ void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_unlock_commit(rdev, ring); } -void r300_errata(struct radeon_device *rdev) +static void r300_errata(struct radeon_device *rdev) { rdev->pll_errata = 0; @@ -322,7 +322,7 @@ int r300_mc_wait_for_idle(struct radeon_device *rdev) return -1; } -void r300_gpu_init(struct radeon_device *rdev) +static void r300_gpu_init(struct radeon_device *rdev) { uint32_t gb_tile_config, tmp; diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 079d3c52c08a..28b4f871aaf4 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -119,7 +119,7 @@ static void r520_vram_get_type(struct radeon_device *rdev) rdev->mc.vram_width *= 2; } -void r520_mc_init(struct radeon_device *rdev) +static void r520_mc_init(struct radeon_device *rdev) { r520_vram_get_type(rdev); @@ -131,7 +131,7 @@ void r520_mc_init(struct radeon_device *rdev) radeon_update_bandwidth_info(rdev); } -void r520_mc_program(struct radeon_device *rdev) +static void r520_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index fd4289bb78d9..48460b4b3e2e 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -98,7 +98,7 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev); /* r600,rv610,rv630,rv620,rv635,rv670 */ int r600_mc_wait_for_idle(struct radeon_device *rdev); -void r600_gpu_init(struct radeon_device *rdev); +static void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); @@ -881,7 +881,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev) return radeon_gart_table_vram_alloc(rdev); } -int r600_pcie_gart_enable(struct radeon_device *rdev) +static int r600_pcie_gart_enable(struct radeon_device *rdev) { u32 tmp; int r, i; @@ -938,7 +938,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) return 0; } -void r600_pcie_gart_disable(struct radeon_device *rdev) +static void r600_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; int i; @@ -971,14 +971,14 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void r600_pcie_gart_fini(struct radeon_device *rdev) +static void r600_pcie_gart_fini(struct radeon_device *rdev) { radeon_gart_fini(rdev); r600_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); } -void r600_agp_enable(struct radeon_device *rdev) +static void r600_agp_enable(struct radeon_device *rdev) { u32 tmp; int i; @@ -1158,7 +1158,7 @@ static void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc } } -int r600_mc_init(struct radeon_device *rdev) +static int r600_mc_init(struct radeon_device *rdev) { u32 tmp; int chansize, numchan; @@ -1258,7 +1258,7 @@ void r600_vram_scratch_fini(struct radeon_device *rdev) * reset, it's up to the caller to determine if the GPU needs one. We * might add an helper function to check that. */ -int r600_gpu_soft_reset(struct radeon_device *rdev) +static int r600_gpu_soft_reset(struct radeon_device *rdev) { struct rv515_mc_save save; u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) | @@ -1433,7 +1433,7 @@ int r600_count_pipe_bits(uint32_t val) return ret; } -void r600_gpu_init(struct radeon_device *rdev) +static void r600_gpu_init(struct radeon_device *rdev) { u32 tiling_config; u32 ramcfg; @@ -2347,7 +2347,7 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg) /* FIXME: implement */ } -int r600_startup(struct radeon_device *rdev) +static int r600_startup(struct radeon_device *rdev) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; int r; diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index f37676d7f217..32fbdf9ff265 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -847,7 +847,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) * Assume that chunk_ib_index is properly set. Will return -EINVAL * if packet is bigger than remaining ib size. or if packets is unknown. **/ -int r600_cs_packet_parse(struct radeon_cs_parser *p, +static int r600_cs_packet_parse(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx) { diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index e3558c3ef24a..857a7d7862fb 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -53,7 +53,7 @@ enum r600_hdmi_iec_status_bits { AUDIO_STATUS_LEVEL = 0x80 }; -struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { +static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { /* 32kHz 44.1kHz 48kHz */ /* Clock N CTS N CTS N CTS */ { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index f75247d42ffd..854d1e230369 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3319,7 +3319,7 @@ static void combios_write_ram_size(struct drm_device *dev) WREG32(RADEON_CONFIG_MEMSIZE, mem_size); } -void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) +static void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) { uint16_t dyn_clk_info = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 748c5f229c28..69a142fc3d1d 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -194,7 +194,7 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c } } -struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) +static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) { struct drm_mode_object *obj; struct drm_encoder *encoder; @@ -215,7 +215,7 @@ struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int enc return NULL; } -struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) +static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; struct drm_mode_object *obj; @@ -366,7 +366,7 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn } } -int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, +static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { struct drm_device *dev = connector->dev; @@ -687,13 +687,13 @@ static int radeon_lvds_set_property(struct drm_connector *connector, } -struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { +static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { .get_modes = radeon_lvds_get_modes, .mode_valid = radeon_lvds_mode_valid, .best_encoder = radeon_best_single_encoder, }; -struct drm_connector_funcs radeon_lvds_connector_funcs = { +static const struct drm_connector_funcs radeon_lvds_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -805,13 +805,13 @@ radeon_vga_detect(struct drm_connector *connector, bool force) return ret; } -struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { +static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { .get_modes = radeon_vga_get_modes, .mode_valid = radeon_vga_mode_valid, .best_encoder = radeon_best_single_encoder, }; -struct drm_connector_funcs radeon_vga_connector_funcs = { +static const struct drm_connector_funcs radeon_vga_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_vga_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -875,13 +875,13 @@ radeon_tv_detect(struct drm_connector *connector, bool force) return ret; } -struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = { +static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = { .get_modes = radeon_tv_get_modes, .mode_valid = radeon_tv_mode_valid, .best_encoder = radeon_best_single_encoder, }; -struct drm_connector_funcs radeon_tv_connector_funcs = { +static const struct drm_connector_funcs radeon_tv_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_tv_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -1085,7 +1085,7 @@ out: } /* okay need to be smart in here about which encoder to pick */ -struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) +static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1175,13 +1175,13 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector, return MODE_OK; } -struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { +static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { .get_modes = radeon_dvi_get_modes, .mode_valid = radeon_dvi_mode_valid, .best_encoder = radeon_dvi_encoder, }; -struct drm_connector_funcs radeon_dvi_connector_funcs = { +static const struct drm_connector_funcs radeon_dvi_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_dvi_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -1458,13 +1458,13 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, } } -struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { +static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { .get_modes = radeon_dp_get_modes, .mode_valid = radeon_dp_mode_valid, .best_encoder = radeon_dvi_encoder, }; -struct drm_connector_funcs radeon_dp_connector_funcs = { +static const struct drm_connector_funcs radeon_dp_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 3ae7c27c9d6c..e24150659bc7 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -32,7 +32,7 @@ void r100_cs_dump_packet(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt); -int radeon_cs_parser_relocs(struct radeon_cs_parser *p) +static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) { struct drm_device *ddev = p->rdev->ddev; struct radeon_cs_chunk *chunk; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 331a952c9b53..6fca11c64dcd 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -842,7 +842,7 @@ static unsigned int radeon_vga_set_decode(void *cookie, bool state) * Validates certain module parameters and updates * the associated values used by the driver (all asics). */ -void radeon_check_arguments(struct radeon_device *rdev) +static void radeon_check_arguments(struct radeon_device *rdev) { /* vramlimit must be a power of two */ switch (radeon_vram_limit) { diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 5906914a78bc..8b088ca12095 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -317,7 +317,7 @@ static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, } static char *mode_option; -int radeon_parse_options(char *options) +static int radeon_parse_options(char *options) { char *this_opt; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 2a59375dbe52..1eb3db52a36e 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -399,7 +399,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) return 0; } -bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) +static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) { unsigned i; diff --git a/drivers/gpu/drm/radeon/radeon_ioc32.c b/drivers/gpu/drm/radeon/radeon_ioc32.c index 48b7cea31e08..c4bb2269be10 100644 --- a/drivers/gpu/drm/radeon/radeon_ioc32.c +++ b/drivers/gpu/drm/radeon/radeon_ioc32.c @@ -369,7 +369,7 @@ static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, #define compat_radeon_cp_setparam NULL #endif /* X86_64 || IA64 */ -drm_ioctl_compat_t *radeon_compat_ioctls[] = { +static drm_ioctl_compat_t *radeon_compat_ioctls[] = { [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple, diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 94b4a1c12893..e946bfcf25b5 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -206,7 +206,7 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); } -void radeon_restore_common_regs(struct drm_device *dev) +static void radeon_restore_common_regs(struct drm_device *dev) { /* don't need this yet */ } @@ -295,7 +295,7 @@ static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, return 1; } -void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) +static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index b4df25e2ac88..993cf712074f 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -43,7 +43,7 @@ * produce command buffers which are send to the kernel and * put in IBs for execution by the requested ring. */ -int radeon_debugfs_sa_init(struct radeon_device *rdev); +static int radeon_debugfs_sa_init(struct radeon_device *rdev); /** * radeon_ib_get - request an IB (Indirect Buffer) @@ -291,7 +291,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) * wptr. The GPU then starts fetching commands and executes * them until the pointers are equal again. */ -int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); +static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); /** * radeon_ring_write - write a value to the ring @@ -819,7 +819,7 @@ static struct drm_info_list radeon_debugfs_sa_list[] = { #endif -int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) +static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) { #if defined(CONFIG_DEBUG_FS) unsigned i; @@ -839,7 +839,7 @@ int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *rin return 0; } -int radeon_debugfs_sa_init(struct radeon_device *rdev) +static int radeon_debugfs_sa_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 7c16540c10ff..587c09a00ba2 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -313,7 +313,7 @@ out_cleanup: printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); } -void radeon_test_ring_sync2(struct radeon_device *rdev, +static void radeon_test_ring_sync2(struct radeon_device *rdev, struct radeon_ring *ringA, struct radeon_ring *ringB, struct radeon_ring *ringC) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 5b71c716d83f..5ebe1b3e5db2 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -549,7 +549,7 @@ static struct ttm_backend_func radeon_backend_func = { .destroy = &radeon_ttm_backend_destroy, }; -struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, +static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) { diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 2752f7f78237..73051ce3121e 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -242,7 +242,7 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev) return -1; } -void rs400_gpu_init(struct radeon_device *rdev) +static void rs400_gpu_init(struct radeon_device *rdev) { /* FIXME: is this correct ? */ r420_pipes_init(rdev); @@ -252,7 +252,7 @@ void rs400_gpu_init(struct radeon_device *rdev) } } -void rs400_mc_init(struct radeon_device *rdev) +static void rs400_mc_init(struct radeon_device *rdev) { u64 base; @@ -370,7 +370,7 @@ static int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev) #endif } -void rs400_mc_program(struct radeon_device *rdev) +static void rs400_mc_program(struct radeon_device *rdev) { struct r100_mc_save save; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 8f7064492e4b..dc8d021a999b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -43,7 +43,7 @@ #include "rs600_reg_safe.h" -void rs600_gpu_init(struct radeon_device *rdev); +static void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); static const u32 crtc_offsets[2] = @@ -432,7 +432,7 @@ void rs600_gart_tlb_flush(struct radeon_device *rdev) tmp = RREG32_MC(R_000100_MC_PT0_CNTL); } -int rs600_gart_init(struct radeon_device *rdev) +static int rs600_gart_init(struct radeon_device *rdev) { int r; @@ -514,7 +514,7 @@ static int rs600_gart_enable(struct radeon_device *rdev) return 0; } -void rs600_gart_disable(struct radeon_device *rdev) +static void rs600_gart_disable(struct radeon_device *rdev) { u32 tmp; @@ -525,7 +525,7 @@ void rs600_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void rs600_gart_fini(struct radeon_device *rdev) +static void rs600_gart_fini(struct radeon_device *rdev) { radeon_gart_fini(rdev); rs600_gart_disable(rdev); @@ -753,7 +753,7 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev) return -1; } -void rs600_gpu_init(struct radeon_device *rdev) +static void rs600_gpu_init(struct radeon_device *rdev) { r420_pipes_init(rdev); /* Wait for mc idle */ @@ -761,7 +761,7 @@ void rs600_gpu_init(struct radeon_device *rdev) dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n"); } -void rs600_mc_init(struct radeon_device *rdev) +static void rs600_mc_init(struct radeon_device *rdev) { u64 base; @@ -823,7 +823,7 @@ void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) WREG32(R_000074_MC_IND_DATA, v); } -void rs600_debugfs(struct radeon_device *rdev) +static void rs600_debugfs(struct radeon_device *rdev) { if (r100_debugfs_rbbm_init(rdev)) DRM_ERROR("Failed to register debugfs file for RBBM !\n"); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 3b663fcfe061..5cd5aceb69fa 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -145,7 +145,7 @@ void rs690_pm_info(struct radeon_device *rdev) rdev->pm.sideport_bandwidth.full = dfixed_div(rdev->pm.sideport_bandwidth, tmp); } -void rs690_mc_init(struct radeon_device *rdev) +static void rs690_mc_init(struct radeon_device *rdev) { u64 base; @@ -224,7 +224,7 @@ struct rs690_watermark { fixed20_12 sclk; }; -void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, +static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, struct radeon_crtc *crtc, struct rs690_watermark *wm) { @@ -581,7 +581,7 @@ void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) WREG32(R_000078_MC_INDEX, 0x7F); } -void rs690_mc_program(struct radeon_device *rdev) +static void rs690_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index aa8ef491ef3c..2d75d30be5b4 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -35,9 +35,9 @@ #include "rv515_reg_safe.h" /* This files gather functions specifics to: rv515 */ -int rv515_debugfs_pipes_info_init(struct radeon_device *rdev); -int rv515_debugfs_ga_info_init(struct radeon_device *rdev); -void rv515_gpu_init(struct radeon_device *rdev); +static int rv515_debugfs_pipes_info_init(struct radeon_device *rdev); +static int rv515_debugfs_ga_info_init(struct radeon_device *rdev); +static void rv515_gpu_init(struct radeon_device *rdev); int rv515_mc_wait_for_idle(struct radeon_device *rdev); void rv515_debugfs(struct radeon_device *rdev) @@ -143,7 +143,7 @@ void rv515_vga_render_disable(struct radeon_device *rdev) RREG32(R_000300_VGA_RENDER_CONTROL) & C_000300_VGA_VSTATUS_CNTL); } -void rv515_gpu_init(struct radeon_device *rdev) +static void rv515_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; @@ -189,7 +189,7 @@ static void rv515_vram_get_type(struct radeon_device *rdev) } } -void rv515_mc_init(struct radeon_device *rdev) +static void rv515_mc_init(struct radeon_device *rdev) { rv515_vram_get_type(rdev); @@ -261,7 +261,7 @@ static struct drm_info_list rv515_ga_info_list[] = { }; #endif -int rv515_debugfs_pipes_info_init(struct radeon_device *rdev) +static int rv515_debugfs_pipes_info_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) return radeon_debugfs_add_files(rdev, rv515_pipes_info_list, 1); @@ -270,7 +270,7 @@ int rv515_debugfs_pipes_info_init(struct radeon_device *rdev) #endif } -int rv515_debugfs_ga_info_init(struct radeon_device *rdev) +static int rv515_debugfs_ga_info_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) return radeon_debugfs_add_files(rdev, rv515_ga_info_list, 1); @@ -310,7 +310,7 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control); } -void rv515_mc_program(struct radeon_device *rdev) +static void rv515_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; @@ -787,7 +787,7 @@ struct rv515_watermark { fixed20_12 sclk; }; -void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, +static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, struct radeon_crtc *crtc, struct rv515_watermark *wm) { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index ca8ffec10ff6..2469afe11b85 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -124,7 +124,7 @@ void rv770_pm_misc(struct radeon_device *rdev) /* * GART */ -int rv770_pcie_gart_enable(struct radeon_device *rdev) +static int rv770_pcie_gart_enable(struct radeon_device *rdev) { u32 tmp; int r, i; @@ -175,7 +175,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) return 0; } -void rv770_pcie_gart_disable(struct radeon_device *rdev) +static void rv770_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; int i; @@ -201,7 +201,7 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void rv770_pcie_gart_fini(struct radeon_device *rdev) +static void rv770_pcie_gart_fini(struct radeon_device *rdev) { radeon_gart_fini(rdev); rv770_pcie_gart_disable(rdev); @@ -209,7 +209,7 @@ void rv770_pcie_gart_fini(struct radeon_device *rdev) } -void rv770_agp_enable(struct radeon_device *rdev) +static void rv770_agp_enable(struct radeon_device *rdev) { u32 tmp; int i; @@ -839,7 +839,7 @@ void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) } } -int rv770_mc_init(struct radeon_device *rdev) +static int rv770_mc_init(struct radeon_device *rdev) { u32 tmp; int chansize, numchan; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 51a471dc319c..2a5c337715de 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2364,7 +2364,7 @@ void si_pcie_gart_tlb_flush(struct radeon_device *rdev) WREG32(VM_INVALIDATE_REQUEST, 1); } -int si_pcie_gart_enable(struct radeon_device *rdev) +static int si_pcie_gart_enable(struct radeon_device *rdev) { int r, i; @@ -2437,7 +2437,7 @@ int si_pcie_gart_enable(struct radeon_device *rdev) return 0; } -void si_pcie_gart_disable(struct radeon_device *rdev) +static void si_pcie_gart_disable(struct radeon_device *rdev) { /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); @@ -2456,7 +2456,7 @@ void si_pcie_gart_disable(struct radeon_device *rdev) radeon_gart_table_vram_unpin(rdev); } -void si_pcie_gart_fini(struct radeon_device *rdev) +static void si_pcie_gart_fini(struct radeon_device *rdev) { si_pcie_gart_disable(rdev); radeon_gart_table_vram_free(rdev); From e9e2fbe975a1938b1acadb94ac7d5934298974ac Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Tue, 31 Jul 2012 17:41:46 +0300 Subject: [PATCH 44/79] drm/radeon: Remove unused functions This applies on top of drm/radeon: Mark all possible functions / structs as static. Signed-off-by: Lauri Kasanen Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 44 --------------------- drivers/gpu/drm/radeon/radeon_combios.c | 9 ----- drivers/gpu/drm/radeon/radeon_fb.c | 16 -------- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 5 --- 4 files changed, 74 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index cd11760f2395..f3892efcf7f4 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2528,50 +2528,6 @@ static void r100_errata(struct radeon_device *rdev) } } -/* Wait for vertical sync on primary CRTC */ -static void r100_gpu_wait_for_vsync(struct radeon_device *rdev) -{ - uint32_t crtc_gen_cntl, tmp; - int i; - - crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); - if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || - !(crtc_gen_cntl & RADEON_CRTC_EN)) { - return; - } - /* Clear the CRTC_VBLANK_SAVE bit */ - WREG32(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_CRTC_STATUS); - if (tmp & RADEON_CRTC_VBLANK_SAVE) { - return; - } - DRM_UDELAY(1); - } -} - -/* Wait for vertical sync on secondary CRTC */ -static void r100_gpu_wait_for_vsync2(struct radeon_device *rdev) -{ - uint32_t crtc2_gen_cntl, tmp; - int i; - - crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); - if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || - !(crtc2_gen_cntl & RADEON_CRTC2_EN)) - return; - - /* Clear the CRTC_VBLANK_SAVE bit */ - WREG32(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_CRTC2_STATUS); - if (tmp & RADEON_CRTC2_VBLANK_SAVE) { - return; - } - DRM_UDELAY(1); - } -} - static int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) { unsigned i; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 854d1e230369..8a73f0758903 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3319,15 +3319,6 @@ static void combios_write_ram_size(struct drm_device *dev) WREG32(RADEON_CONFIG_MEMSIZE, mem_size); } -static void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) -{ - uint16_t dyn_clk_info = - combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); - - if (dyn_clk_info) - combios_parse_pll_table(dev, dyn_clk_info); -} - void radeon_combios_asic_init(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 8b088ca12095..6ada72c6d7a1 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -316,22 +316,6 @@ static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, return new_fb; } -static char *mode_option; -static int radeon_parse_options(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) - continue; - mode_option = this_opt; - } - return 0; -} - void radeon_fb_output_poll_changed(struct radeon_device *rdev) { drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index e946bfcf25b5..5677a424b585 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -206,11 +206,6 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); } -static void radeon_restore_common_regs(struct drm_device *dev) -{ - /* don't need this yet */ -} - static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; From 1678dbc22e4b2cfe24a7e042d822ddb837e378c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 6 Sep 2012 13:48:07 +0200 Subject: [PATCH 45/79] drm/radeon: fix VM syncing with multiple rings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a VM is used on more than one ring we need to sync to the last user. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index e24150659bc7..d59eb59cdb81 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -463,7 +463,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, goto out; } radeon_cs_sync_rings(parser); - radeon_cs_sync_to(parser, vm->last_flush); + radeon_cs_sync_to(parser, vm->fence); radeon_cs_sync_to(parser, radeon_vm_grab_id(rdev, vm, parser->ring)); if ((rdev->family >= CHIP_TAHITI) && From a36e70b2e55539aba0ba8a934c46b71c235488ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:09:57 +0200 Subject: [PATCH 46/79] drm/radeon: fix VA range check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The end offset is exclusive not inclusive. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_gart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index d7bd46bd9067..614e31a6f832 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -732,7 +732,7 @@ int radeon_vm_bo_add(struct radeon_device *rdev, head = &vm->va; last_offset = 0; list_for_each_entry(tmp, &vm->va, vm_list) { - if (bo_va->soffset >= last_offset && bo_va->eoffset < tmp->soffset) { + if (bo_va->soffset >= last_offset && bo_va->eoffset <= tmp->soffset) { /* bo can be added before this one */ break; } From 96a5844f90a6d3b1c0cabfe4870e62e7b1cc4640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:09:58 +0200 Subject: [PATCH 47/79] drm/radeon: fix VA overlap check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_gart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 614e31a6f832..5694421b7c67 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -736,7 +736,7 @@ int radeon_vm_bo_add(struct radeon_device *rdev, /* bo can be added before this one */ break; } - if (bo_va->soffset >= tmp->soffset && bo_va->soffset < tmp->eoffset) { + if (bo_va->eoffset > tmp->soffset && bo_va->soffset < tmp->eoffset) { /* bo and tmp overlap, invalid offset */ dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", bo, (unsigned)bo_va->soffset, tmp->bo, From ca19f21ece0ad96c77f45a01c43f3bb582f1a35c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:09:59 +0200 Subject: [PATCH 48/79] drm/radeon: move IB pool to 1MB offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even GPUs can have a null pointer dereference, so move the IB pool to another offset to catch those. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_gart.c | 2 +- drivers/gpu/drm/radeon/radeon_ring.c | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d48bd3045db6..55f17f9bc095 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -123,6 +123,7 @@ extern int radeon_lockup_timeout; #define CAYMAN_RING_TYPE_CP2_INDEX 2 /* hardcode those limit for now */ +#define RADEON_VA_IB_OFFSET (1 << 20) #define RADEON_VA_RESERVED_SIZE (8 << 20) #define RADEON_IB_VM_MAX_SIZE (64 << 10) diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 5694421b7c67..1b1c001e269a 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -980,7 +980,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) /* map the ib pool buffer at 0 in virtual address space, set * read only */ - r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, 0, + r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 993cf712074f..d90b0bc6f072 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -79,10 +79,10 @@ int radeon_ib_get(struct radeon_device *rdev, int ring, ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); ib->vm = vm; if (vm) { - /* ib pool is bind at 0 in virtual address space, - * so gpu_addr is the offset inside the pool bo + /* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address + * space and soffset is the offset inside the pool bo */ - ib->gpu_addr = ib->sa_bo->soffset; + ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET; } else { ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); } From 421ca7ab86aef01b4e22fb171d3d6bad6f1a5b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:10:00 +0200 Subject: [PATCH 49/79] drm/radeon: move and rename radeon_bo_va function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't really belong into the object functions, also rename it to avoid collisions with struct radeon_bo_va. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_gart.c | 34 +++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_gem.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 13 ---------- drivers/gpu/drm/radeon/radeon_object.h | 2 -- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 55f17f9bc095..8cca1d2f0510 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1846,6 +1846,8 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct ttm_mem_reg *mem); void radeon_vm_bo_invalidate(struct radeon_device *rdev, struct radeon_bo *bo); +struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, + struct radeon_bo *bo); int radeon_vm_bo_add(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 1b1c001e269a..2c594910064d 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -662,7 +662,31 @@ void radeon_vm_fence(struct radeon_device *rdev, vm->fence = radeon_fence_ref(fence); } -/* object have to be reserved */ +/** + * radeon_vm_bo_find - find the bo_va for a specific vm & bo + * + * @vm: requested vm + * @bo: requested buffer object + * + * Find @bo inside the requested vm (cayman+). + * Search inside the @bos vm list for the requested vm + * Returns the found bo_va or NULL if none is found + * + * Object has to be reserved! + */ +struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, + struct radeon_bo *bo) +{ + struct radeon_bo_va *bo_va; + + list_for_each_entry(bo_va, &bo->va, bo_list) { + if (bo_va->vm == vm) { + return bo_va; + } + } + return NULL; +} + /** * radeon_vm_bo_add - add a bo to a specific vm * @@ -676,6 +700,8 @@ void radeon_vm_fence(struct radeon_device *rdev, * Add @bo to the list of bos associated with the vm and validate * the offset requested within the vm address space. * Returns 0 for success, error for failure. + * + * Object has to be reserved! */ int radeon_vm_bo_add(struct radeon_device *rdev, struct radeon_vm *vm, @@ -823,7 +849,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, if (vm->sa_bo == NULL) return 0; - bo_va = radeon_bo_va(bo, vm); + bo_va = radeon_vm_bo_find(vm, bo); if (bo_va == NULL) { dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm); return -EINVAL; @@ -912,7 +938,7 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, struct radeon_bo_va *bo_va; int r; - bo_va = radeon_bo_va(bo, vm); + bo_va = radeon_vm_bo_find(vm, bo); if (bo_va == NULL) return 0; @@ -1009,7 +1035,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) */ r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (!r) { - bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm); + bo_va = radeon_vm_bo_find(vm, rdev->ring_tmp_bo.bo); list_del_init(&bo_va->bo_list); list_del_init(&bo_va->vm_list); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 1b57b0058ad6..6cac5cca3d81 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -461,7 +461,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, } switch (args->operation) { case RADEON_VA_MAP: - bo_va = radeon_bo_va(rbo, &fpriv->vm); + bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); if (bo_va) { args->operation = RADEON_VA_RESULT_VA_EXIST; args->offset = bo_va->soffset; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 9024e7222839..2844e0b204b0 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -646,16 +646,3 @@ int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait) } return 0; } - -/* object have to be reserved */ -struct radeon_bo_va *radeon_bo_va(struct radeon_bo *rbo, struct radeon_vm *vm) -{ - struct radeon_bo_va *bo_va; - - list_for_each_entry(bo_va, &rbo->va, bo_list) { - if (bo_va->vm == vm) { - return bo_va; - } - } - return NULL; -} diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 17fb99f177cf..2aaf6e305e42 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -141,8 +141,6 @@ extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); -extern struct radeon_bo_va *radeon_bo_va(struct radeon_bo *rbo, - struct radeon_vm *vm); /* * sub allocation From d63dfed5e9aa5fbea25a471300ee1b33bdc710d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:10:01 +0200 Subject: [PATCH 50/79] drm/radeon: let bo_reserve take no_intr instead of no_wait param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The no_wait param isn't used anywhere, and actually isn't very usefull at all. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_object.c | 7 +++---- drivers/gpu/drm/radeon/radeon_object.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 2844e0b204b0..8d23b7e2ae3d 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -627,18 +627,17 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) /** * radeon_bo_reserve - reserve bo * @bo: bo structure - * @no_wait: don't sleep while trying to reserve (return -EBUSY) + * @no_intr: don't return -ERESTARTSYS on pending signal * * Returns: - * -EBUSY: buffer is busy and @no_wait is true * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by * a signal. Release all buffer reservations and return to user-space. */ -int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait) +int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr) { int r; - r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); + r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0); if (unlikely(r != 0)) { if (r != -ERESTARTSYS) dev_err(bo->rdev->dev, "%p reserve failed\n", bo); diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 2aaf6e305e42..93cd491fff2e 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -52,7 +52,7 @@ static inline unsigned radeon_mem_type_to_domain(u32 mem_type) return 0; } -int radeon_bo_reserve(struct radeon_bo *bo, bool no_wait); +int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr); static inline void radeon_bo_unreserve(struct radeon_bo *bo) { From d59f70216b7166f03fa732964deafc6453d62eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:10:02 +0200 Subject: [PATCH 51/79] drm/radeon: fix gem_close_object handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the reserve non interruptible. Signed-off-by: Christian König Reviewed-by: Jerome Glisse --- drivers/gpu/drm/radeon/radeon_gem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 6cac5cca3d81..cfad667ce785 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -134,13 +134,16 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct radeon_device *rdev = rbo->rdev; struct radeon_fpriv *fpriv = file_priv->driver_priv; struct radeon_vm *vm = &fpriv->vm; + int r; if (rdev->family < CHIP_CAYMAN) { return; } - if (radeon_bo_reserve(rbo, false)) { - dev_err(rdev->dev, "leaking bo va because we fail to reserve bo\n"); + r = radeon_bo_reserve(rbo, true); + if (r) { + dev_err(rdev->dev, "leaking bo va because " + "we fail to reserve bo (%d)\n", r); return; } radeon_vm_bo_rmv(rdev, vm, rbo); From e971bd5e45764ff76df0ff110a19bf6b924f84d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 11 Sep 2012 16:10:04 +0200 Subject: [PATCH 52/79] drm/radeon: rework the VM code a bit more (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roughly based on how nouveau is handling it. Instead of adding the bo_va when the address is set add the bo_va when the handle is opened, but set the address to zero until userspace tells us where to place it. This fixes another bunch of problems with glamor. v2: agd5f: fix build after dropping patch 7/8. Signed-off-by: Christian König --- drivers/gpu/drm/radeon/radeon.h | 30 +++-- drivers/gpu/drm/radeon/radeon_gart.c | 157 ++++++++++++++++--------- drivers/gpu/drm/radeon/radeon_gem.c | 47 +++++++- drivers/gpu/drm/radeon/radeon_object.c | 2 +- 4 files changed, 159 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8cca1d2f0510..4d67f0f5a5a3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -292,17 +292,20 @@ struct radeon_mman { /* bo virtual address in a specific vm */ struct radeon_bo_va { - /* bo list is protected by bo being reserved */ + /* protected by bo being reserved */ struct list_head bo_list; - /* vm list is protected by vm mutex */ - struct list_head vm_list; - /* constant after initialization */ - struct radeon_vm *vm; - struct radeon_bo *bo; uint64_t soffset; uint64_t eoffset; uint32_t flags; bool valid; + unsigned ref_count; + + /* protected by vm mutex */ + struct list_head vm_list; + + /* constant after initialization */ + struct radeon_vm *vm; + struct radeon_bo *bo; }; struct radeon_bo { @@ -1848,14 +1851,15 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, struct radeon_bo *bo); struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, struct radeon_bo *bo); -int radeon_vm_bo_add(struct radeon_device *rdev, - struct radeon_vm *vm, - struct radeon_bo *bo, - uint64_t offset, - uint32_t flags); +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, + struct radeon_vm *vm, + struct radeon_bo *bo); +int radeon_vm_bo_set_addr(struct radeon_device *rdev, + struct radeon_bo_va *bo_va, + uint64_t offset, + uint32_t flags); int radeon_vm_bo_rmv(struct radeon_device *rdev, - struct radeon_vm *vm, - struct radeon_bo *bo); + struct radeon_bo_va *bo_va); /* audio */ void r600_audio_update_hdmi(struct work_struct *work); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2c594910064d..2f28ff34c085 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -693,51 +693,83 @@ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, * @rdev: radeon_device pointer * @vm: requested vm * @bo: radeon buffer object - * @offset: requested offset of the buffer in the VM address space - * @flags: attributes of pages (read/write/valid/etc.) * * Add @bo into the requested vm (cayman+). - * Add @bo to the list of bos associated with the vm and validate - * the offset requested within the vm address space. + * Add @bo to the list of bos associated with the vm + * Returns newly added bo_va or NULL for failure + * + * Object has to be reserved! + */ +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, + struct radeon_vm *vm, + struct radeon_bo *bo) +{ + struct radeon_bo_va *bo_va; + + bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); + if (bo_va == NULL) { + return NULL; + } + bo_va->vm = vm; + bo_va->bo = bo; + bo_va->soffset = 0; + bo_va->eoffset = 0; + bo_va->flags = 0; + bo_va->valid = false; + bo_va->ref_count = 1; + INIT_LIST_HEAD(&bo_va->bo_list); + INIT_LIST_HEAD(&bo_va->vm_list); + + mutex_lock(&vm->mutex); + list_add(&bo_va->vm_list, &vm->va); + list_add_tail(&bo_va->bo_list, &bo->va); + mutex_unlock(&vm->mutex); + + return bo_va; +} + +/** + * radeon_vm_bo_set_addr - set bos virtual address inside a vm + * + * @rdev: radeon_device pointer + * @bo_va: bo_va to store the address + * @soffset: requested offset of the buffer in the VM address space + * @flags: attributes of pages (read/write/valid/etc.) + * + * Set offset of @bo_va (cayman+). + * Validate and set the offset requested within the vm address space. * Returns 0 for success, error for failure. * * Object has to be reserved! */ -int radeon_vm_bo_add(struct radeon_device *rdev, - struct radeon_vm *vm, - struct radeon_bo *bo, - uint64_t offset, - uint32_t flags) +int radeon_vm_bo_set_addr(struct radeon_device *rdev, + struct radeon_bo_va *bo_va, + uint64_t soffset, + uint32_t flags) { - struct radeon_bo_va *bo_va, *tmp; + uint64_t size = radeon_bo_size(bo_va->bo); + uint64_t eoffset, last_offset = 0; + struct radeon_vm *vm = bo_va->vm; + struct radeon_bo_va *tmp; struct list_head *head; - uint64_t size = radeon_bo_size(bo), last_offset = 0; unsigned last_pfn; - bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); - if (bo_va == NULL) { - return -ENOMEM; - } - bo_va->vm = vm; - bo_va->bo = bo; - bo_va->soffset = offset; - bo_va->eoffset = offset + size; - bo_va->flags = flags; - bo_va->valid = false; - INIT_LIST_HEAD(&bo_va->bo_list); - INIT_LIST_HEAD(&bo_va->vm_list); - /* make sure object fit at this offset */ - if (bo_va->soffset >= bo_va->eoffset) { - kfree(bo_va); - return -EINVAL; - } + if (soffset) { + /* make sure object fit at this offset */ + eoffset = soffset + size; + if (soffset >= eoffset) { + return -EINVAL; + } - last_pfn = bo_va->eoffset / RADEON_GPU_PAGE_SIZE; - if (last_pfn > rdev->vm_manager.max_pfn) { - kfree(bo_va); - dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", - last_pfn, rdev->vm_manager.max_pfn); - return -EINVAL; + last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; + if (last_pfn > rdev->vm_manager.max_pfn) { + dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", + last_pfn, rdev->vm_manager.max_pfn); + return -EINVAL; + } + + } else { + eoffset = last_pfn = 0; } mutex_lock(&vm->mutex); @@ -758,24 +790,33 @@ int radeon_vm_bo_add(struct radeon_device *rdev, head = &vm->va; last_offset = 0; list_for_each_entry(tmp, &vm->va, vm_list) { - if (bo_va->soffset >= last_offset && bo_va->eoffset <= tmp->soffset) { + if (bo_va == tmp) { + /* skip over currently modified bo */ + continue; + } + + if (soffset >= last_offset && eoffset <= tmp->soffset) { /* bo can be added before this one */ break; } - if (bo_va->eoffset > tmp->soffset && bo_va->soffset < tmp->eoffset) { + if (eoffset > tmp->soffset && soffset < tmp->eoffset) { /* bo and tmp overlap, invalid offset */ dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", - bo, (unsigned)bo_va->soffset, tmp->bo, + bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, (unsigned)tmp->soffset, (unsigned)tmp->eoffset); - kfree(bo_va); mutex_unlock(&vm->mutex); return -EINVAL; } last_offset = tmp->eoffset; head = &tmp->vm_list; } - list_add(&bo_va->vm_list, head); - list_add_tail(&bo_va->bo_list, &bo->va); + + bo_va->soffset = soffset; + bo_va->eoffset = eoffset; + bo_va->flags = flags; + bo_va->valid = false; + list_move(&bo_va->vm_list, head); + mutex_unlock(&vm->mutex); return 0; } @@ -855,6 +896,12 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, return -EINVAL; } + if (!bo_va->soffset) { + dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", + bo, vm); + return -EINVAL; + } + if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) return 0; @@ -921,33 +968,26 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, * radeon_vm_bo_rmv - remove a bo to a specific vm * * @rdev: radeon_device pointer - * @vm: requested vm - * @bo: radeon buffer object + * @bo_va: requested bo_va * - * Remove @bo from the requested vm (cayman+). - * Remove @bo from the list of bos associated with the vm and - * remove the ptes for @bo in the page table. + * Remove @bo_va->bo from the requested vm (cayman+). + * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and + * remove the ptes for @bo_va in the page table. * Returns 0 for success. * * Object have to be reserved! */ int radeon_vm_bo_rmv(struct radeon_device *rdev, - struct radeon_vm *vm, - struct radeon_bo *bo) + struct radeon_bo_va *bo_va) { - struct radeon_bo_va *bo_va; int r; - bo_va = radeon_vm_bo_find(vm, bo); - if (bo_va == NULL) - return 0; - mutex_lock(&rdev->vm_manager.lock); - mutex_lock(&vm->mutex); - r = radeon_vm_bo_update_pte(rdev, vm, bo, NULL); + mutex_lock(&bo_va->vm->mutex); + r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); mutex_unlock(&rdev->vm_manager.lock); list_del(&bo_va->vm_list); - mutex_unlock(&vm->mutex); + mutex_unlock(&bo_va->vm->mutex); list_del(&bo_va->bo_list); kfree(bo_va); @@ -987,6 +1027,7 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, */ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) { + struct radeon_bo_va *bo_va; int r; vm->id = 0; @@ -1006,8 +1047,10 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) /* map the ib pool buffer at 0 in virtual address space, set * read only */ - r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, RADEON_VA_IB_OFFSET, - RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); + bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); + r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, + RADEON_VM_PAGE_READABLE | + RADEON_VM_PAGE_SNOOPED); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index cfad667ce785..6579befa5101 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -124,6 +124,30 @@ void radeon_gem_fini(struct radeon_device *rdev) */ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) { + struct radeon_bo *rbo = gem_to_radeon_bo(obj); + struct radeon_device *rdev = rbo->rdev; + struct radeon_fpriv *fpriv = file_priv->driver_priv; + struct radeon_vm *vm = &fpriv->vm; + struct radeon_bo_va *bo_va; + int r; + + if (rdev->family < CHIP_CAYMAN) { + return 0; + } + + r = radeon_bo_reserve(rbo, false); + if (r) { + return r; + } + + bo_va = radeon_vm_bo_find(vm, rbo); + if (!bo_va) { + bo_va = radeon_vm_bo_add(rdev, vm, rbo); + } else { + ++bo_va->ref_count; + } + radeon_bo_unreserve(rbo); + return 0; } @@ -134,6 +158,7 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct radeon_device *rdev = rbo->rdev; struct radeon_fpriv *fpriv = file_priv->driver_priv; struct radeon_vm *vm = &fpriv->vm; + struct radeon_bo_va *bo_va; int r; if (rdev->family < CHIP_CAYMAN) { @@ -146,7 +171,12 @@ void radeon_gem_object_close(struct drm_gem_object *obj, "we fail to reserve bo (%d)\n", r); return; } - radeon_vm_bo_rmv(rdev, vm, rbo); + bo_va = radeon_vm_bo_find(vm, rbo); + if (bo_va) { + if (--bo_va->ref_count == 0) { + radeon_vm_bo_rmv(rdev, bo_va); + } + } radeon_bo_unreserve(rbo); } @@ -462,19 +492,24 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference_unlocked(gobj); return r; } + bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); + if (!bo_va) { + args->operation = RADEON_VA_RESULT_ERROR; + drm_gem_object_unreference_unlocked(gobj); + return -ENOENT; + } + switch (args->operation) { case RADEON_VA_MAP: - bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); - if (bo_va) { + if (bo_va->soffset) { args->operation = RADEON_VA_RESULT_VA_EXIST; args->offset = bo_va->soffset; goto out; } - r = radeon_vm_bo_add(rdev, &fpriv->vm, rbo, - args->offset, args->flags); + r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); break; case RADEON_VA_UNMAP: - r = radeon_vm_bo_rmv(rdev, &fpriv->vm, rbo); + r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0); break; default: break; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8d23b7e2ae3d..a236795dc69a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -52,7 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo) list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) { /* remove from all vm address space */ - radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo); + radeon_vm_bo_rmv(bo->rdev, bo_va); } } From 2f6fa79a7e4cc380cc55ef967101cee340b8364b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Sep 2012 12:26:09 -0400 Subject: [PATCH 53/79] drm/radeon: clean up encoder dp checks Use the proper struct in the union. That field has the same offset in every struct, so no functional change. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 07441cb718a3..7dc3ba2792a2 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -866,14 +866,14 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo else args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode)) args.v3.ucLaneNum = dp_lane_count; else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v3.ucLaneNum = 8; else args.v3.ucLaneNum = 4; - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; args.v3.acConfig.ucDigSel = dig->dig_encoder; args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); @@ -886,14 +886,14 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo else args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) args.v4.ucLaneNum = dp_lane_count; else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v4.ucLaneNum = 8; else args.v4.ucLaneNum = 4; - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) { + if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) { if (dp_clock == 270000) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; else if (dp_clock == 540000) From 6e76a2df91c516714bf1f039b9614696aaaeaeb2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Sep 2012 12:30:37 -0400 Subject: [PATCH 54/79] drm/radeon: white space cleanup in transmitter setup Makes it more consistent with the surrounding code. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 7dc3ba2792a2..784f6e784604 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1013,8 +1013,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.asMode.ucLaneSet = lane_set; } else { if (is_dp) - args.v1.usPixelClock = - cpu_to_le16(dp_clock / 10); + args.v1.usPixelClock = cpu_to_le16(dp_clock / 10); else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else @@ -1071,8 +1070,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v2.asMode.ucLaneSet = lane_set; } else { if (is_dp) - args.v2.usPixelClock = - cpu_to_le16(dp_clock / 10); + args.v2.usPixelClock = cpu_to_le16(dp_clock / 10); else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else @@ -1114,8 +1112,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v3.asMode.ucLaneSet = lane_set; } else { if (is_dp) - args.v3.usPixelClock = - cpu_to_le16(dp_clock / 10); + args.v3.usPixelClock = cpu_to_le16(dp_clock / 10); else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else @@ -1174,8 +1171,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v4.asMode.ucLaneSet = lane_set; } else { if (is_dp) - args.v4.usPixelClock = - cpu_to_le16(dp_clock / 10); + args.v4.usPixelClock = cpu_to_le16(dp_clock / 10); else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else From e729586e33593cd11112ff22fa8f0e801af05b4e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 12 Sep 2012 17:58:07 -0400 Subject: [PATCH 55/79] drm/radeon/atom: fix typo in SetPixelClock handling MiscInfo field should be programmed with the crtc id rather than the pll id. However, at this point the two are the same for chips with this version of the table. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 2817101fb167..cc1b2444a5e5 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -837,7 +837,10 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, args.v3.ucFracFbDiv = frac_fb_div; args.v3.ucPostDiv = post_div; args.v3.ucPpll = pll_id; - args.v3.ucMiscInfo = (pll_id << 2); + if (crtc_id == ATOM_CRTC2) + args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; + else + args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1; if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; args.v3.ucTransmitterId = encoder_id; From a59fbb8e18566a346a2736000d979576ab7525fe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Sep 2012 12:01:48 -0400 Subject: [PATCH 56/79] drm/radeon: fix typo in atombios_get_encoder_mode comparing the encoder mode to the encoder id for DVO. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 784f6e784604..266036b10fec 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -662,7 +662,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) return ATOM_ENCODER_MODE_DP; /* DVO is always DVO */ - if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)) return ATOM_ENCODER_MODE_DVO; connector = radeon_get_connector_for_encoder(encoder); From f3dd8508d459a2d0d0bc426144b92f1696d4fe86 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 31 Aug 2012 11:56:50 -0400 Subject: [PATCH 57/79] drm/radeon: rework pll selection (v4) For DP we can use the same PPLL for all active DP encoders. Take advantage of that to prevent cases where we may end up sharing a PPLL between DP and non-DP which won't work. Also clean up the code a bit. v2: - fix missing pll_id assignment in crtc init v3: - fix DP PPLL check - document functions - break in main encoder search loop after matching. no need to keep checking additional encoders. v4: - same as v3, but re-apply to drm-next as the corner cases are fixed properly in subsequent patches. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=54471 Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 163 +++++++++++++++++++------ 1 file changed, 129 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index cc1b2444a5e5..8e73d53b769e 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1482,14 +1482,98 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc) } } +/** + * radeon_get_pll_use_mask - look up a mask of which pplls are in use + * + * @crtc: drm crtc + * + * Returns the mask of which PPLLs (Pixel PLLs) are in use. + */ +static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc *test_crtc; + struct radeon_crtc *radeon_test_crtc; + u32 pll_in_use = 0; + + list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { + if (crtc == test_crtc) + continue; + + radeon_test_crtc = to_radeon_crtc(test_crtc); + if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) + pll_in_use |= (1 << radeon_test_crtc->pll_id); + } + return pll_in_use; +} + +/** + * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP + * + * @crtc: drm crtc + * + * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is + * also in DP mode. For DP, a single PPLL can be used for all DP + * crtcs/encoders. + */ +static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_encoder *test_encoder; + struct radeon_crtc *radeon_test_crtc; + + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + if (test_encoder->crtc && (test_encoder->crtc != crtc)) { + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { + /* for DP use the same PLL for all */ + radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); + if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) + return radeon_test_crtc->pll_id; + } + } + } + return ATOM_PPLL_INVALID; +} + +/** + * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. + * + * @crtc: drm crtc + * + * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors + * a single PPLL can be used for all DP crtcs/encoders. For non-DP + * monitors a dedicated PPLL must be used. If a particular board has + * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming + * as there is no need to program the PLL itself. If we are not able to + * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to + * avoid messing up an existing monitor. + * + * Asic specific PLL information + * + * DCE 6.1 + * - PPLL2 is only available to UNIPHYA (both DP and non-DP) + * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) + * + * DCE 6.0 + * - PPLL0 is available to all UNIPHY (DP only) + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + * DCE 5.0 + * - DCPLL is available to all UNIPHY (DP only) + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + * DCE 3.0/4.0/4.1 + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + */ static int radeon_atom_pick_pll(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_encoder *test_encoder; - struct drm_crtc *test_crtc; - uint32_t pll_in_use = 0; + u32 pll_in_use; + int pll; if (ASIC_IS_DCE61(rdev)) { list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { @@ -1501,32 +1585,40 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) if ((test_radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && - (dig->linkb == false)) /* UNIPHY A uses PPLL2 */ + (dig->linkb == false)) + /* UNIPHY A uses PPLL2 */ return ATOM_PPLL2; + else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { + /* UNIPHY B/C/D/E/F */ + if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ + return ATOM_PPLL_INVALID; + else { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } + } + break; } } /* UNIPHY B/C/D/E/F */ - list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { - struct radeon_crtc *radeon_test_crtc; - - if (crtc == test_crtc) - continue; - - radeon_test_crtc = to_radeon_crtc(test_crtc); - if ((radeon_test_crtc->pll_id == ATOM_PPLL0) || - (radeon_test_crtc->pll_id == ATOM_PPLL1)) - pll_in_use |= (1 << radeon_test_crtc->pll_id); - } - if (!(pll_in_use & 4)) + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL0))) return ATOM_PPLL0; - return ATOM_PPLL1; + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; } else if (ASIC_IS_DCE4(rdev)) { list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { if (test_encoder->crtc && (test_encoder->crtc == crtc)) { /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, * depending on the asic: * DCE4: PPLL or ext clock - * DCE5: DCPLL or ext clock + * DCE5: PPLL, DCPLL, or ext clock + * DCE6: PPLL, PPLL0, or ext clock * * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip * PPLL/DCPLL programming and only program the DP DTO for the @@ -1534,31 +1626,34 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) */ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ return ATOM_PPLL_INVALID; else if (ASIC_IS_DCE6(rdev)) + /* use PPLL0 for all DP */ return ATOM_PPLL0; else if (ASIC_IS_DCE5(rdev)) + /* use DCPLL for all DP */ return ATOM_DCPLL; + else { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } } + break; } } - - /* otherwise, pick one of the plls */ - list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { - struct radeon_crtc *radeon_test_crtc; - - if (crtc == test_crtc) - continue; - - radeon_test_crtc = to_radeon_crtc(test_crtc); - if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && - (radeon_test_crtc->pll_id <= ATOM_PPLL2)) - pll_in_use |= (1 << radeon_test_crtc->pll_id); - } - if (!(pll_in_use & 1)) + /* all other cases */ + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + if (!(pll_in_use & (1 << ATOM_PPLL1))) return ATOM_PPLL1; - return ATOM_PPLL2; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; } else + /* use PPLL1 or PPLL2 */ return radeon_crtc->crtc_id; } @@ -1700,7 +1795,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) break; } done: - radeon_crtc->pll_id = -1; + radeon_crtc->pll_id = ATOM_PPLL_INVALID; } static const struct drm_crtc_helper_funcs atombios_helper_funcs = { @@ -1749,6 +1844,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev, else radeon_crtc->crtc_offset = 0; } - radeon_crtc->pll_id = -1; + radeon_crtc->pll_id = ATOM_PPLL_INVALID; drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); } From 9dbbcfc6894957fdbb311ba92c85c026659878b5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 12 Sep 2012 17:39:57 -0400 Subject: [PATCH 58/79] drm/radeon/dce3: use a single PPLL for all DP displays If possible, use a single PPLL for multiple DP displays on DCE3.x. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8e73d53b769e..c5a040677d48 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1652,6 +1652,30 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return ATOM_PPLL1; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; + } else if (ASIC_IS_DCE3(rdev)) { + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + if (test_encoder->crtc && (test_encoder->crtc == crtc)) { + /* in DP mode, the DP ref clock can come from either PPLL + * depending on the asic: + * DCE3: PPLL1 or PPLL2 + */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } + break; + } + } + /* all other cases */ + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; } else /* use PPLL1 or PPLL2 */ return radeon_crtc->crtc_id; From 2f454cf1261ba913e2f660b7555864b340502c60 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 12 Sep 2012 18:54:14 -0400 Subject: [PATCH 59/79] drm/radeon: allow PPLL sharing on non-DP displays If several non-DP displays use the same pixel clock we can use the same PPLL for all of them. If all relevant displays have the same pixel clock, this allows the driver to: - use fewer PPLLs which saves power - support more than two non-DP displays on DCE4+ The current drm modesetting infrastructure doesn't really provide a good framework for validating combinations that work or won't work, so it's possible you could go from a working configuration to a non-working one by changing the mode a one of the displays. However, there this is better than what was there before. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 113 +++++++++++++++++++------ 1 file changed, 86 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index c5a040677d48..2f7cc9e3b175 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1535,6 +1535,49 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) return ATOM_PPLL_INVALID; } +/** + * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc + * + * @crtc: drm crtc + * @encoder: drm encoder + * + * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can + * be shared (i.e., same clock). + */ +static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc, + struct drm_encoder *encoder) +{ + struct drm_device *dev = crtc->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *test_encoder; + struct radeon_crtc *radeon_test_crtc; + struct radeon_encoder *test_radeon_encoder; + u32 target_clock, test_clock; + + if (radeon_encoder->native_mode.clock) + target_clock = radeon_encoder->native_mode.clock; + else + target_clock = crtc->mode.clock; + + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + if (test_encoder->crtc && (test_encoder->crtc != crtc)) { + if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { + test_radeon_encoder = to_radeon_encoder(test_encoder); + radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); + /* for non-DP check the clock */ + if (test_radeon_encoder->native_mode.clock) + test_clock = test_radeon_encoder->native_mode.clock; + else + test_clock = test_encoder->crtc->mode.clock; + if ((target_clock == test_clock) && + (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)) + return radeon_test_crtc->pll_id; + } + } + } + return ATOM_PPLL_INVALID; +} + /** * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. * @@ -1568,7 +1611,6 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) */ static int radeon_atom_pick_pll(struct drm_crtc *crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_encoder *test_encoder; @@ -1599,6 +1641,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) if (pll != ATOM_PPLL_INVALID) return pll; } + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); + if (pll != ATOM_PPLL_INVALID) + return pll; } break; } @@ -1640,28 +1687,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) if (pll != ATOM_PPLL_INVALID) return pll; } - } - break; - } - } - /* all other cases */ - pll_in_use = radeon_get_pll_use_mask(crtc); - if (!(pll_in_use & (1 << ATOM_PPLL2))) - return ATOM_PPLL2; - if (!(pll_in_use & (1 << ATOM_PPLL1))) - return ATOM_PPLL1; - DRM_ERROR("unable to allocate a PPLL\n"); - return ATOM_PPLL_INVALID; - } else if (ASIC_IS_DCE3(rdev)) { - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc == crtc)) { - /* in DP mode, the DP ref clock can come from either PPLL - * depending on the asic: - * DCE3: PPLL1 or PPLL2 - */ - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); if (pll != ATOM_PPLL_INVALID) return pll; } @@ -1676,10 +1704,41 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return ATOM_PPLL1; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; - } else - /* use PPLL1 or PPLL2 */ - return radeon_crtc->crtc_id; - + } else { + /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ + if (!ASIC_IS_AVIVO(rdev)) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + return radeon_crtc->crtc_id; + } + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + if (test_encoder->crtc && (test_encoder->crtc == crtc)) { + /* in DP mode, the DP ref clock can come from either PPLL + * depending on the asic: + * DCE3: PPLL1 or PPLL2 + */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); + if (pll != ATOM_PPLL_INVALID) + return pll; + } + break; + } + } + /* all other cases */ + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; + } } void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev) From 19eca43e5a52a8e47fdd40e940912b2417c7c055 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Sep 2012 10:56:16 -0400 Subject: [PATCH 60/79] drm/radeon: rework crtc pll setup to better support PPLL sharing We need the calculate the pixel clock before allocating a PPLL in order to insure the clocks really match. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 277 ++++++++++++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 32 +-- 2 files changed, 178 insertions(+), 131 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 2f7cc9e3b175..cf8ac5a5d8ca 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -533,11 +533,9 @@ union adjust_pixel_clock { }; static u32 atombios_adjust_pll(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct radeon_pll *pll, - bool ss_enabled, - struct radeon_atom_ss *ss) + struct drm_display_mode *mode) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder = NULL; @@ -550,32 +548,32 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, bool is_duallink = false; /* reset the pll flags */ - pll->flags = 0; + radeon_crtc->pll_flags = 0; if (ASIC_IS_AVIVO(rdev)) { if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) - pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ - RADEON_PLL_PREFER_CLOSEST_LOWER); + radeon_crtc->pll_flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/ + RADEON_PLL_PREFER_CLOSEST_LOWER); if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ - pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; if (rdev->family < CHIP_RV770) - pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; /* use frac fb div on APUs */ if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) - pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; } else { - pll->flags |= RADEON_PLL_LEGACY; + radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; if (mode->clock > 200000) /* range limits??? */ - pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else - pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -598,12 +596,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, /* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (ss_enabled) { - if (ss->refdiv) { - pll->flags |= RADEON_PLL_USE_REF_DIV; - pll->reference_div = ss->refdiv; + if (radeon_crtc->ss_enabled) { + if (radeon_crtc->ss.refdiv) { + radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; + radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; if (ASIC_IS_AVIVO(rdev)) - pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; } } } @@ -613,14 +611,14 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) adjusted_clock = mode->clock * 2; if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - pll->flags |= RADEON_PLL_IS_LCD; + radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; } else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) - pll->flags |= RADEON_PLL_USE_REF_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; } break; } @@ -650,7 +648,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); args.v1.ucTransmitterID = radeon_encoder->encoder_id; args.v1.ucEncodeMode = encoder_mode; - if (ss_enabled && ss->percentage) + if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) args.v1.ucConfig |= ADJUST_DISPLAY_CONFIG_SS_ENABLE; @@ -663,7 +661,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; args.v3.sInput.ucEncodeMode = encoder_mode; args.v3.sInput.ucDispPllConfig = 0; - if (ss_enabled && ss->percentage) + if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE; if (ENCODER_MODE_IS_DP(encoder_mode)) { @@ -695,14 +693,14 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, index, (uint32_t *)&args); adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; if (args.v3.sOutput.ucRefDiv) { - pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; - pll->flags |= RADEON_PLL_USE_REF_DIV; - pll->reference_div = args.v3.sOutput.ucRefDiv; + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; + radeon_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv; } if (args.v3.sOutput.ucPostDiv) { - pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; - pll->flags |= RADEON_PLL_USE_POST_DIV; - pll->post_div = args.v3.sOutput.ucPostDiv; + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + radeon_crtc->pll_flags |= RADEON_PLL_USE_POST_DIV; + radeon_crtc->pll_post_div = args.v3.sOutput.ucPostDiv; } break; default: @@ -910,6 +908,109 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + int encoder_mode = 0; + + radeon_crtc->bpc = 8; + radeon_crtc->ss_enabled = false; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + encoder_mode = atombios_get_encoder_mode(encoder); + break; + } + } + + if (!radeon_encoder) + return false; + + if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector = + radeon_get_connector_for_encoder(encoder); + struct radeon_connector *radeon_connector = + to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + int dp_clock; + radeon_crtc->bpc = radeon_get_monitor_bpc(connector); + + switch (encoder_mode) { + case ATOM_ENCODER_MODE_DP_MST: + case ATOM_ENCODER_MODE_DP: + /* DP/eDP */ + dp_clock = dig_connector->dp_clock / 10; + if (ASIC_IS_DCE4(rdev)) + radeon_crtc->ss_enabled = + radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, + ASIC_INTERNAL_SS_ON_DP, + dp_clock); + else { + if (dp_clock == 16200) { + radeon_crtc->ss_enabled = + radeon_atombios_get_ppll_ss_info(rdev, + &radeon_crtc->ss, + ATOM_DP_SS_ID2); + if (!radeon_crtc->ss_enabled) + radeon_crtc->ss_enabled = + radeon_atombios_get_ppll_ss_info(rdev, + &radeon_crtc->ss, + ATOM_DP_SS_ID1); + } else + radeon_crtc->ss_enabled = + radeon_atombios_get_ppll_ss_info(rdev, + &radeon_crtc->ss, + ATOM_DP_SS_ID1); + } + break; + case ATOM_ENCODER_MODE_LVDS: + if (ASIC_IS_DCE4(rdev)) + radeon_crtc->ss_enabled = + radeon_atombios_get_asic_ss_info(rdev, + &radeon_crtc->ss, + dig->lcd_ss_id, + mode->clock / 10); + else + radeon_crtc->ss_enabled = + radeon_atombios_get_ppll_ss_info(rdev, + &radeon_crtc->ss, + dig->lcd_ss_id); + break; + case ATOM_ENCODER_MODE_DVI: + if (ASIC_IS_DCE4(rdev)) + radeon_crtc->ss_enabled = + radeon_atombios_get_asic_ss_info(rdev, + &radeon_crtc->ss, + ASIC_INTERNAL_SS_ON_TMDS, + mode->clock / 10); + break; + case ATOM_ENCODER_MODE_HDMI: + if (ASIC_IS_DCE4(rdev)) + radeon_crtc->ss_enabled = + radeon_atombios_get_asic_ss_info(rdev, + &radeon_crtc->ss, + ASIC_INTERNAL_SS_ON_HDMI, + mode->clock / 10); + break; + default: + break; + } + } + + /* adjust pixel clock as needed */ + radeon_crtc->adjusted_clock = atombios_adjust_pll(crtc, mode); + + return true; +} + static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -920,11 +1021,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode u32 pll_clock = mode->clock; u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; struct radeon_pll *pll; - u32 adjusted_clock; int encoder_mode = 0; - struct radeon_atom_ss ss; - bool ss_enabled = false; - int bpc = 8; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { @@ -951,109 +1048,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode break; } - if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || - (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector = - radeon_get_connector_for_encoder(encoder); - struct radeon_connector *radeon_connector = - to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - int dp_clock; - bpc = radeon_get_monitor_bpc(connector); - - switch (encoder_mode) { - case ATOM_ENCODER_MODE_DP_MST: - case ATOM_ENCODER_MODE_DP: - /* DP/eDP */ - dp_clock = dig_connector->dp_clock / 10; - if (ASIC_IS_DCE4(rdev)) - ss_enabled = - radeon_atombios_get_asic_ss_info(rdev, &ss, - ASIC_INTERNAL_SS_ON_DP, - dp_clock); - else { - if (dp_clock == 16200) { - ss_enabled = - radeon_atombios_get_ppll_ss_info(rdev, &ss, - ATOM_DP_SS_ID2); - if (!ss_enabled) - ss_enabled = - radeon_atombios_get_ppll_ss_info(rdev, &ss, - ATOM_DP_SS_ID1); - } else - ss_enabled = - radeon_atombios_get_ppll_ss_info(rdev, &ss, - ATOM_DP_SS_ID1); - } - break; - case ATOM_ENCODER_MODE_LVDS: - if (ASIC_IS_DCE4(rdev)) - ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss, - dig->lcd_ss_id, - mode->clock / 10); - else - ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss, - dig->lcd_ss_id); - break; - case ATOM_ENCODER_MODE_DVI: - if (ASIC_IS_DCE4(rdev)) - ss_enabled = - radeon_atombios_get_asic_ss_info(rdev, &ss, - ASIC_INTERNAL_SS_ON_TMDS, - mode->clock / 10); - break; - case ATOM_ENCODER_MODE_HDMI: - if (ASIC_IS_DCE4(rdev)) - ss_enabled = - radeon_atombios_get_asic_ss_info(rdev, &ss, - ASIC_INTERNAL_SS_ON_HDMI, - mode->clock / 10); - break; - default: - break; - } - } - - /* adjust pixel clock as needed */ - adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); + /* update pll params */ + pll->flags = radeon_crtc->pll_flags; + pll->reference_div = radeon_crtc->pll_reference_div; + pll->post_div = radeon_crtc->pll_post_div; if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) /* TV seems to prefer the legacy algo on some boards */ - radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); + radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, + &fb_div, &frac_fb_div, &ref_div, &post_div); else if (ASIC_IS_AVIVO(rdev)) - radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); + radeon_compute_pll_avivo(pll, radeon_crtc->adjusted_clock, &pll_clock, + &fb_div, &frac_fb_div, &ref_div, &post_div); else - radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); + radeon_compute_pll_legacy(pll, radeon_crtc->adjusted_clock, &pll_clock, + &fb_div, &frac_fb_div, &ref_div, &post_div); - atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss); + atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, + radeon_crtc->crtc_id, &radeon_crtc->ss); atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, encoder_mode, radeon_encoder->encoder_id, mode->clock, - ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss); + ref_div, fb_div, frac_fb_div, post_div, + radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss); - if (ss_enabled) { + if (radeon_crtc->ss_enabled) { /* calculate ss amount and step size */ if (ASIC_IS_DCE4(rdev)) { u32 step_size; - u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000; - ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; - ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & + u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000; + radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK; + radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK; - if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) - step_size = (4 * amount * ref_div * (ss.rate * 2048)) / + if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD) + step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / (125 * 25 * pll->reference_freq / 100); else - step_size = (2 * amount * ref_div * (ss.rate * 2048)) / + step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) / (125 * 25 * pll->reference_freq / 100); - ss.step = step_size; + radeon_crtc->ss.step = step_size; } - atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss); + atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, + radeon_crtc->crtc_id, &radeon_crtc->ss); } } @@ -1809,6 +1846,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, { if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; + if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) + return false; return true; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5005057974b1..9f45e4bf06e9 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -282,6 +282,18 @@ struct radeon_tv_regs { uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN]; }; +struct radeon_atom_ss { + uint16_t percentage; + uint8_t type; + uint16_t step; + uint8_t delay; + uint8_t range; + uint8_t refdiv; + /* asic_ss */ + uint16_t rate; + uint16_t amount; +}; + struct radeon_crtc { struct drm_crtc base; int crtc_id; @@ -306,6 +318,14 @@ struct radeon_crtc { /* page flipping */ struct radeon_unpin_work *unpin_work; int deferred_flip_completion; + /* pll sharing */ + struct radeon_atom_ss ss; + bool ss_enabled; + u32 adjusted_clock; + int bpc; + u32 pll_reference_div; + u32 pll_post_div; + u32 pll_flags; }; struct radeon_encoder_primary_dac { @@ -359,18 +379,6 @@ struct radeon_encoder_ext_tmds { }; /* spread spectrum */ -struct radeon_atom_ss { - uint16_t percentage; - uint8_t type; - uint16_t step; - uint8_t delay; - uint8_t range; - uint8_t refdiv; - /* asic_ss */ - uint16_t rate; - uint16_t amount; -}; - struct radeon_encoder_atom_dig { bool linkb; /* atom dig */ From 5df3196bac972138fa62ea17ed036161ae710062 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Sep 2012 11:52:08 -0400 Subject: [PATCH 61/79] drm/radeon: store the encoder in the radeon_crtc This saves lots of lookups later. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 375 +++++++++++-------------- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 167 insertions(+), 209 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index cf8ac5a5d8ca..53a3b29d2d9d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -83,25 +83,19 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); ENABLE_SCALER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); - + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); /* fixme - fill in enc_priv for atom dac */ enum radeon_tv_std tv_std = TV_STD_NTSC; bool is_tv = false, is_cv = false; - struct drm_encoder *encoder; if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) return; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - /* find tv std */ - if (encoder->crtc == crtc) { - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { - struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; - tv_std = tv_dac->tv_std; - is_tv = true; - } - } + if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) { + struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; + tv_std = tv_dac->tv_std; + is_tv = true; } memset(&args, 0, sizeof(args)); @@ -538,14 +532,14 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder = NULL; - struct radeon_encoder *radeon_encoder = NULL; - struct drm_connector *connector = NULL; + struct drm_encoder *encoder = radeon_crtc->encoder; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); u32 adjusted_clock = mode->clock; - int encoder_mode = 0; + int encoder_mode = atombios_get_encoder_mode(encoder); u32 dp_clock = mode->clock; - int bpc = 8; - bool is_duallink = false; + int bpc = radeon_get_monitor_bpc(connector); + bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); /* reset the pll flags */ radeon_crtc->pll_flags = 0; @@ -576,54 +570,44 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - radeon_encoder = to_radeon_encoder(encoder); - connector = radeon_get_connector_for_encoder(encoder); - bpc = radeon_get_monitor_bpc(connector); - encoder_mode = atombios_get_encoder_mode(encoder); - is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); - if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || - (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; + if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; - dp_clock = dig_connector->dp_clock; - } - } - - /* use recommended ref_div for ss */ - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (radeon_crtc->ss_enabled) { - if (radeon_crtc->ss.refdiv) { - radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; - radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; - if (ASIC_IS_AVIVO(rdev)) - radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; - } - } - } - - if (ASIC_IS_AVIVO(rdev)) { - /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) - adjusted_clock = mode->clock * 2; - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; - } else { - if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; - if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) - radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; - } - break; + dp_clock = dig_connector->dp_clock; } } + /* use recommended ref_div for ss */ + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (radeon_crtc->ss_enabled) { + if (radeon_crtc->ss.refdiv) { + radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; + radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; + if (ASIC_IS_AVIVO(rdev)) + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + } + } + } + + if (ASIC_IS_AVIVO(rdev)) { + /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) + adjusted_clock = mode->clock * 2; + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + radeon_crtc->pll_flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_crtc->pll_flags |= RADEON_PLL_IS_LCD; + } else { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + radeon_crtc->pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) + radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; + } + /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock * accordingly based on the encoder/transmitter to work around * special hw requirements. @@ -913,29 +897,18 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder = NULL; - struct radeon_encoder *radeon_encoder = NULL; - int encoder_mode = 0; + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); + int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); radeon_crtc->bpc = 8; radeon_crtc->ss_enabled = false; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - radeon_encoder = to_radeon_encoder(encoder); - encoder_mode = atombios_get_encoder_mode(encoder); - break; - } - } - - if (!radeon_encoder) - return false; - if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || - (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { + (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct drm_connector *connector = - radeon_get_connector_for_encoder(encoder); + radeon_get_connector_for_encoder(radeon_crtc->encoder); struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector = @@ -1016,23 +989,12 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder = NULL; - struct radeon_encoder *radeon_encoder = NULL; + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); u32 pll_clock = mode->clock; u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; struct radeon_pll *pll; - int encoder_mode = 0; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - radeon_encoder = to_radeon_encoder(encoder); - encoder_mode = atombios_get_encoder_mode(encoder); - break; - } - } - - if (!radeon_encoder) - return; + int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); switch (radeon_crtc->pll_id) { case ATOM_PPLL1: @@ -1557,15 +1519,15 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_encoder *test_encoder; - struct radeon_crtc *radeon_test_crtc; + struct radeon_crtc *test_radeon_crtc; list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { if (test_encoder->crtc && (test_encoder->crtc != crtc)) { if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { /* for DP use the same PLL for all */ - radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); - if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) - return radeon_test_crtc->pll_id; + test_radeon_crtc = to_radeon_crtc(test_encoder->crtc); + if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) + return test_radeon_crtc->pll_id; } } } @@ -1581,13 +1543,14 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can * be shared (i.e., same clock). */ -static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc, - struct drm_encoder *encoder) +static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); struct drm_encoder *test_encoder; - struct radeon_crtc *radeon_test_crtc; + struct radeon_crtc *test_radeon_crtc; struct radeon_encoder *test_radeon_encoder; u32 target_clock, test_clock; @@ -1600,15 +1563,15 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc, if (test_encoder->crtc && (test_encoder->crtc != crtc)) { if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { test_radeon_encoder = to_radeon_encoder(test_encoder); - radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); + test_radeon_crtc = to_radeon_crtc(test_encoder->crtc); /* for non-DP check the clock */ if (test_radeon_encoder->native_mode.clock) test_clock = test_radeon_encoder->native_mode.clock; else test_clock = test_encoder->crtc->mode.clock; if ((target_clock == test_clock) && - (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)) - return radeon_test_crtc->pll_id; + (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) + return test_radeon_crtc->pll_id; } } } @@ -1648,44 +1611,38 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc, */ static int radeon_atom_pick_pll(struct drm_crtc *crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *test_encoder; + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); u32 pll_in_use; int pll; if (ASIC_IS_DCE61(rdev)) { - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc == crtc)) { - struct radeon_encoder *test_radeon_encoder = - to_radeon_encoder(test_encoder); - struct radeon_encoder_atom_dig *dig = - test_radeon_encoder->enc_priv; + struct radeon_encoder_atom_dig *dig = + radeon_encoder->enc_priv; - if ((test_radeon_encoder->encoder_id == - ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && - (dig->linkb == false)) - /* UNIPHY A uses PPLL2 */ - return ATOM_PPLL2; - else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - /* UNIPHY B/C/D/E/F */ - if (rdev->clock.dp_extclk) - /* skip PPLL programming if using ext clock */ - return ATOM_PPLL_INVALID; - else { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - } else { - /* use the same PPLL for all monitors with the same clock */ - pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - break; + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && + (dig->linkb == false)) + /* UNIPHY A uses PPLL2 */ + return ATOM_PPLL2; + else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + /* UNIPHY B/C/D/E/F */ + if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ + return ATOM_PPLL_INVALID; + else { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; } + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; } /* UNIPHY B/C/D/E/F */ pll_in_use = radeon_get_pll_use_mask(crtc); @@ -1696,42 +1653,37 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; } else if (ASIC_IS_DCE4(rdev)) { - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc == crtc)) { - /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, - * depending on the asic: - * DCE4: PPLL or ext clock - * DCE5: PPLL, DCPLL, or ext clock - * DCE6: PPLL, PPLL0, or ext clock - * - * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip - * PPLL/DCPLL programming and only program the DP DTO for the - * crtc virtual pixel clock. - */ - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - if (rdev->clock.dp_extclk) - /* skip PPLL programming if using ext clock */ - return ATOM_PPLL_INVALID; - else if (ASIC_IS_DCE6(rdev)) - /* use PPLL0 for all DP */ - return ATOM_PPLL0; - else if (ASIC_IS_DCE5(rdev)) - /* use DCPLL for all DP */ - return ATOM_DCPLL; - else { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - } else { - /* use the same PPLL for all monitors with the same clock */ - pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - break; + /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, + * depending on the asic: + * DCE4: PPLL or ext clock + * DCE5: PPLL, DCPLL, or ext clock + * DCE6: PPLL, PPLL0, or ext clock + * + * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip + * PPLL/DCPLL programming and only program the DP DTO for the + * crtc virtual pixel clock. + */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ + return ATOM_PPLL_INVALID; + else if (ASIC_IS_DCE6(rdev)) + /* use PPLL0 for all DP */ + return ATOM_PPLL0; + else if (ASIC_IS_DCE5(rdev)) + /* use DCPLL for all DP */ + return ATOM_DCPLL; + else { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; } + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; } /* all other cases */ pll_in_use = radeon_get_pll_use_mask(crtc); @@ -1742,39 +1694,34 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; } else { - /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ - if (!ASIC_IS_AVIVO(rdev)) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + if (ASIC_IS_AVIVO(rdev)) { + /* in DP mode, the DP ref clock can come from either PPLL + * depending on the asic: + * DCE3: PPLL1 or PPLL2 + */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + /* use the same PPLL for all DP monitors */ + pll = radeon_get_shared_dp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } else { + /* use the same PPLL for all monitors with the same clock */ + pll = radeon_get_shared_nondp_ppll(crtc); + if (pll != ATOM_PPLL_INVALID) + return pll; + } + /* all other cases */ + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; + } else { + /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ return radeon_crtc->crtc_id; } - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc == crtc)) { - /* in DP mode, the DP ref clock can come from either PPLL - * depending on the asic: - * DCE3: PPLL1 or PPLL2 - */ - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } else { - /* use the same PPLL for all monitors with the same clock */ - pll = radeon_get_shared_nondp_ppll(crtc, test_encoder); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - break; - } - } - /* all other cases */ - pll_in_use = radeon_get_pll_use_mask(crtc); - if (!(pll_in_use & (1 << ATOM_PPLL2))) - return ATOM_PPLL2; - if (!(pll_in_use & (1 << ATOM_PPLL1))) - return ATOM_PPLL1; - DRM_ERROR("unable to allocate a PPLL\n"); - return ATOM_PPLL_INVALID; } } @@ -1806,18 +1753,13 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); bool is_tvcv = false; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - /* find tv std */ - if (encoder->crtc == crtc) { - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->active_device & - (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) - is_tvcv = true; - } - } + if (radeon_encoder->active_device & + (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + is_tvcv = true; atombios_crtc_set_pll(crtc, adjusted_mode); @@ -1844,6 +1786,19 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_encoder *encoder; + + /* assign the encoder to the radeon crtc to avoid repeated lookups later */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_crtc->encoder = encoder; + break; + } + } + if (radeon_crtc->encoder == NULL) + return false; if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) @@ -1918,6 +1873,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) } done: radeon_crtc->pll_id = ATOM_PPLL_INVALID; + radeon_crtc->encoder = NULL; } static const struct drm_crtc_helper_funcs atombios_helper_funcs = { @@ -1967,5 +1923,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev, radeon_crtc->crtc_offset = 0; } radeon_crtc->pll_id = ATOM_PPLL_INVALID; + radeon_crtc->encoder = NULL; drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 9f45e4bf06e9..2d78645576d7 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -326,6 +326,7 @@ struct radeon_crtc { u32 pll_reference_div; u32 pll_post_div; u32 pll_flags; + struct drm_encoder *encoder; }; struct radeon_encoder_primary_dac { From 9642ac0e645198b62f99279704e829a286f58d96 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Sep 2012 12:43:41 -0400 Subject: [PATCH 62/79] drm/radeon: make non-DP PPLL sharing more robust Compare the adjusted clock as well as the crtc mode clock. This handles cases where the driver adjusts the clock for specific special cases. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 27 +++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 53a3b29d2d9d..721f80e9568d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1547,29 +1547,28 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; - struct radeon_encoder *radeon_encoder = - to_radeon_encoder(radeon_crtc->encoder); struct drm_encoder *test_encoder; + struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; struct radeon_encoder *test_radeon_encoder; - u32 target_clock, test_clock; + u32 adjusted_clock, test_adjusted_clock; - if (radeon_encoder->native_mode.clock) - target_clock = radeon_encoder->native_mode.clock; - else - target_clock = crtc->mode.clock; + adjusted_clock = radeon_crtc->adjusted_clock; + + if (adjusted_clock == 0) + return ATOM_PPLL_INVALID; list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { if (test_encoder->crtc && (test_encoder->crtc != crtc)) { if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { test_radeon_encoder = to_radeon_encoder(test_encoder); - test_radeon_crtc = to_radeon_crtc(test_encoder->crtc); + test_crtc = test_encoder->crtc; + test_radeon_crtc = to_radeon_crtc(test_crtc); /* for non-DP check the clock */ - if (test_radeon_encoder->native_mode.clock) - test_clock = test_radeon_encoder->native_mode.clock; - else - test_clock = test_encoder->crtc->mode.clock; - if ((target_clock == test_clock) && + test_adjusted_clock = test_radeon_crtc->adjusted_clock; + if ((crtc->mode.clock == test_crtc->mode.clock) && + (adjusted_clock == test_adjusted_clock) && + (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) return test_radeon_crtc->pll_id; } @@ -1873,6 +1872,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) } done: radeon_crtc->pll_id = ATOM_PPLL_INVALID; + radeon_crtc->adjusted_clock = 0; radeon_crtc->encoder = NULL; } @@ -1923,6 +1923,7 @@ void radeon_atombios_init_crtc(struct drm_device *dev, radeon_crtc->crtc_offset = 0; } radeon_crtc->pll_id = ATOM_PPLL_INVALID; + radeon_crtc->adjusted_clock = 0; radeon_crtc->encoder = NULL; drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); } From 57b35e29cf4e45eb163631c4ece10dbc259ddf30 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 17 Sep 2012 17:34:45 -0400 Subject: [PATCH 63/79] drm/radeon: work around KMS modeset limitations in PLL allocation (v2) Since the current KMS API sets the mode independantly on each crtc, we may end up with resource conflicts. The PLL allocation is one of those cases. In the following example we have 3 crtcs in use driving 2 DVI connectors and 1 DP connector. On the initial kernel modeset for fbdev, the display topology ends up as follows: crtc0 -> DP-0 crtc1 -> DVI-0 crtc2 -> DVI-1 Because this is the first modeset, all of the PLLs are available as none have been assigned. So we end up with the following: crtc0 uses DCPLL crtc1 uses PPLL2 crtc2 uses PPLL1 When X starts, it assigns a different topology: crtc0 -> DVI-0 crtc1 -> DP-0 crtc2 -> DVI-1 However, since the KMS API is per crtc, we set the mode on each crtc independantly. When it comes time to set the mode on crtc0, the topology for crtc1 and crtc2 are still intact. crtc1 and crtc2 are already assigned PPLL2 and PPLL1 so when it comes time to set the mode on crtc0, crtc1 and crtc2 have not been torn down yet, so there appears to be no PLLs available. In reality, we are reconfiguring the entire display topology, however, since each crtc is handled independantly, we don't know that in the driver at each crtc mode set time. This patch checks to see if the same connector is being driven by another crtc, and if so, uses the PLL already associated with it. v2: store connector in the radeon crtc struct, simplify checking. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 66 +++++++++++++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 721f80e9568d..8e32c5891be1 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1492,16 +1492,16 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_crtc *test_crtc; - struct radeon_crtc *radeon_test_crtc; + struct radeon_crtc *test_radeon_crtc; u32 pll_in_use = 0; list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { if (crtc == test_crtc) continue; - radeon_test_crtc = to_radeon_crtc(test_crtc); - if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) - pll_in_use |= (1 << radeon_test_crtc->pll_id); + test_radeon_crtc = to_radeon_crtc(test_crtc); + if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) + pll_in_use |= (1 << test_radeon_crtc->pll_id); } return pll_in_use; } @@ -1518,17 +1518,18 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_encoder *test_encoder; + struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc != crtc)) { - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - /* for DP use the same PLL for all */ - test_radeon_crtc = to_radeon_crtc(test_encoder->crtc); - if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) - return test_radeon_crtc->pll_id; - } + list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { + if (crtc == test_crtc) + continue; + test_radeon_crtc = to_radeon_crtc(test_crtc); + if (test_radeon_crtc->encoder && + ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { + /* for DP use the same PLL for all */ + if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) + return test_radeon_crtc->pll_id; } } return ATOM_PPLL_INVALID; @@ -1547,10 +1548,8 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_encoder *test_encoder; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; - struct radeon_encoder *test_radeon_encoder; u32 adjusted_clock, test_adjusted_clock; adjusted_clock = radeon_crtc->adjusted_clock; @@ -1558,20 +1557,25 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) if (adjusted_clock == 0) return ATOM_PPLL_INVALID; - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - if (test_encoder->crtc && (test_encoder->crtc != crtc)) { - if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { - test_radeon_encoder = to_radeon_encoder(test_encoder); - test_crtc = test_encoder->crtc; - test_radeon_crtc = to_radeon_crtc(test_crtc); - /* for non-DP check the clock */ - test_adjusted_clock = test_radeon_crtc->adjusted_clock; - if ((crtc->mode.clock == test_crtc->mode.clock) && - (adjusted_clock == test_adjusted_clock) && - (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && - (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) + list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { + if (crtc == test_crtc) + continue; + test_radeon_crtc = to_radeon_crtc(test_crtc); + if (test_radeon_crtc->encoder && + !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { + /* check if we are already driving this connector with another crtc */ + if (test_radeon_crtc->connector == radeon_crtc->connector) { + /* if we are, return that pll */ + if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) return test_radeon_crtc->pll_id; } + /* for non-DP check the clock */ + test_adjusted_clock = test_radeon_crtc->adjusted_clock; + if ((crtc->mode.clock == test_crtc->mode.clock) && + (adjusted_clock == test_adjusted_clock) && + (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && + (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) + return test_radeon_crtc->pll_id; } } return ATOM_PPLL_INVALID; @@ -1793,11 +1797,15 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { radeon_crtc->encoder = encoder; + radeon_crtc->connector = radeon_get_connector_for_encoder(encoder); break; } } - if (radeon_crtc->encoder == NULL) + if ((radeon_crtc->encoder == NULL) || (radeon_crtc->connector == NULL)) { + radeon_crtc->encoder = NULL; + radeon_crtc->connector = NULL; return false; + } if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) @@ -1874,6 +1882,7 @@ done: radeon_crtc->pll_id = ATOM_PPLL_INVALID; radeon_crtc->adjusted_clock = 0; radeon_crtc->encoder = NULL; + radeon_crtc->connector = NULL; } static const struct drm_crtc_helper_funcs atombios_helper_funcs = { @@ -1925,5 +1934,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev, radeon_crtc->pll_id = ATOM_PPLL_INVALID; radeon_crtc->adjusted_clock = 0; radeon_crtc->encoder = NULL; + radeon_crtc->connector = NULL; drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 2d78645576d7..917d02750cf7 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -327,6 +327,7 @@ struct radeon_crtc { u32 pll_post_div; u32 pll_flags; struct drm_encoder *encoder; + struct drm_connector *connector; }; struct radeon_encoder_primary_dac { From c0fd0834aa0ec6b8e3bb97876b842f7b123c54d3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Sep 2012 12:30:51 -0400 Subject: [PATCH 64/79] drm/radeon: validate PPLL in crtc fixup This allows us to bail if we can't support the requested setup from a PPLL perspective. Prevents broken setups from being attempted. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_crtc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8e32c5891be1..96184d02c8d9 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1810,6 +1810,13 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, return false; if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) return false; + /* pick pll */ + radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); + /* if we can't get a PPLL for a non-DP encoder, fail */ + if ((radeon_crtc->pll_id == ATOM_PPLL_INVALID) && + !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) + return false; + return true; } @@ -1820,8 +1827,6 @@ static void atombios_crtc_prepare(struct drm_crtc *crtc) struct radeon_device *rdev = dev->dev_private; radeon_crtc->in_mode_set = true; - /* pick pll */ - radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); /* disable crtc pair power gating before programming */ if (ASIC_IS_DCE6(rdev)) From 2e3b3b105ab3bb5b6a37198da4f193cd13781d13 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Sep 2012 10:59:26 -0400 Subject: [PATCH 65/79] drm/radeon: only adjust default clocks on NI GPUs SI asics store voltage information differently so we don't have a way to deal with it properly yet. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index c15e505a15bc..e024435a856c 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -521,7 +521,9 @@ void radeon_pm_suspend(struct radeon_device *rdev) void radeon_pm_resume(struct radeon_device *rdev) { /* set up the default clocks if the MC ucode is loaded */ - if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); @@ -576,7 +578,9 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_pm_print_states(rdev); radeon_pm_init_profile(rdev); /* set up the default clocks if the MC ucode is loaded */ - if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); From 6d92f81dcf2d40b8ebb947bba5435642b830f649 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Sep 2012 09:59:26 -0400 Subject: [PATCH 66/79] drm/radeon: add get_backlight_level callback Read back the backlight level from the hw. Needed for proper backlight restoration on resume. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 12 ++++++++++++ drivers/gpu/drm/radeon/radeon.h | 3 +++ drivers/gpu/drm/radeon/radeon_asic.c | 19 +++++++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 2 ++ .../gpu/drm/radeon/radeon_legacy_encoders.c | 13 +++++++++++++ 5 files changed, 49 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 266036b10fec..5ce13b8fbe6c 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -72,6 +72,18 @@ radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev, WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); } +u8 +atombios_get_backlight_level(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) + return 0; + + return radeon_atom_get_backlight_level_from_reg(rdev); +} + void atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4d67f0f5a5a3..de86b8e259ce 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1174,6 +1174,8 @@ struct radeon_asic { void (*wait_for_vblank)(struct radeon_device *rdev, int crtc); /* set backlight level */ void (*set_backlight_level)(struct radeon_encoder *radeon_encoder, u8 level); + /* get backlight level */ + u8 (*get_backlight_level)(struct radeon_encoder *radeon_encoder); } display; /* copy functions for bo handling */ struct { @@ -1767,6 +1769,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) #define radeon_set_backlight_level(rdev, e, l) (rdev)->asic->display.set_backlight_level((e), (l)) +#define radeon_get_backlight_level(rdev, e) (rdev)->asic->display.get_backlight_level((e)) #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence)) #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) #define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 2f7adeab049b..6225e1977700 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -199,6 +199,7 @@ static struct radeon_asic r100_asic = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &radeon_legacy_set_backlight_level, + .get_backlight_level = &radeon_legacy_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -274,6 +275,7 @@ static struct radeon_asic r200_asic = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &radeon_legacy_set_backlight_level, + .get_backlight_level = &radeon_legacy_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -349,6 +351,7 @@ static struct radeon_asic r300_asic = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &radeon_legacy_set_backlight_level, + .get_backlight_level = &radeon_legacy_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -424,6 +427,7 @@ static struct radeon_asic r300_asic_pcie = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &radeon_legacy_set_backlight_level, + .get_backlight_level = &radeon_legacy_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -499,6 +503,7 @@ static struct radeon_asic r420_asic = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -574,6 +579,7 @@ static struct radeon_asic rs400_asic = { .get_vblank_counter = &r100_get_vblank_counter, .wait_for_vblank = &r100_wait_for_vblank, .set_backlight_level = &radeon_legacy_set_backlight_level, + .get_backlight_level = &radeon_legacy_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -649,6 +655,7 @@ static struct radeon_asic rs600_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -724,6 +731,7 @@ static struct radeon_asic rs690_asic = { .bandwidth_update = &rs690_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -799,6 +807,7 @@ static struct radeon_asic rv515_asic = { .bandwidth_update = &rv515_bandwidth_update, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -874,6 +883,7 @@ static struct radeon_asic r520_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r100_copy_blit, @@ -948,6 +958,7 @@ static struct radeon_asic r600_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1022,6 +1033,7 @@ static struct radeon_asic rs780_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1096,6 +1108,7 @@ static struct radeon_asic rv770_asic = { .get_vblank_counter = &rs600_get_vblank_counter, .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1170,6 +1183,7 @@ static struct radeon_asic evergreen_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1244,6 +1258,7 @@ static struct radeon_asic sumo_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1318,6 +1333,7 @@ static struct radeon_asic btc_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1422,6 +1438,7 @@ static struct radeon_asic cayman_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1526,6 +1543,7 @@ static struct radeon_asic trinity_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = &r600_copy_blit, @@ -1630,6 +1648,7 @@ static struct radeon_asic si_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, + .get_backlight_level = &atombios_get_backlight_level, }, .copy = { .blit = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 29b3d0545f94..8251b44550b7 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -43,7 +43,9 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); void atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); +u8 atombios_get_backlight_level(struct radeon_encoder *radeon_encoder); void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); +u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder); /* diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index ec00deaab9ca..8ad9c5f16014 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -290,6 +290,19 @@ static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) return level; } +u8 +radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + u8 backlight_level; + + backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> + RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; + + return backlight_level; +} + void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) { From bced76f27165ca7733437715185c3a1aa526f7a1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 14 Sep 2012 09:45:50 -0400 Subject: [PATCH 67/79] drm/radeon: restore backlight level on resume Restore the backlight level on resume. Some systems need to explicitly restore the backlight level on resume. Fixes panel resume on my Trinity laptop and may fix the following bugs: https://bugs.freedesktop.org/show_bug.cgi?id=43829 https://bugzilla.kernel.org/show_bug.cgi?id=46241 Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 4 ++-- drivers/gpu/drm/radeon/radeon_device.c | 7 +++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 1 + drivers/gpu/drm/radeon/radeon_mode.h | 6 ++++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 5ce13b8fbe6c..806cbcc94fdd 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -32,8 +32,6 @@ extern int atom_debug; -#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) - static u8 radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev) { @@ -134,6 +132,8 @@ atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) } } +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) + static u8 radeon_atom_bl_level(struct backlight_device *bd) { u8 level; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 6fca11c64dcd..64a42647f08a 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1282,6 +1282,13 @@ int radeon_resume_kms(struct drm_device *dev) if (rdev->is_atom_bios) { radeon_atom_encoder_init(rdev); radeon_atom_disp_eng_pll_init(rdev); + /* turn on the BL */ + if (rdev->mode_info.bl_encoder) { + u8 bl_level = radeon_get_backlight_level(rdev, + rdev->mode_info.bl_encoder); + radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, + bl_level); + } } /* reset hpd state */ radeon_hpd_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 93b0d64b3f6d..e66c807df9e6 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -179,6 +179,7 @@ radeon_link_encoder_connector(struct drm_device *dev) radeon_atom_backlight_init(radeon_encoder, connector); else radeon_legacy_backlight_init(radeon_encoder, connector); + rdev->mode_info.bl_encoder = radeon_encoder; } } } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 917d02750cf7..527761801590 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -254,12 +254,14 @@ struct radeon_mode_info { struct radeon_fbdev *rfbdev; /* firmware flags */ u16 firmware_flags; + /* pointer to backlight encoder */ + struct radeon_encoder *bl_encoder; }; -#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) - #define RADEON_MAX_BL_LEVEL 0xFF +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) + struct radeon_backlight_privdata { struct radeon_encoder *encoder; uint8_t negative; From af026c5bd14cb57b230a63bdee6f73677a06f010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 20 Sep 2012 10:31:10 +0200 Subject: [PATCH 68/79] drm/radeon: Fix scratch register leak in IB test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure the code to jump out via labels instead of directly returning early. Also make error reporting consistent across all hardware generations. Signed-off-by: Michel Dänzer Reviewed-by: Simon Kitching Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r100.c | 15 +++++++++------ drivers/gpu/drm/radeon/r600.c | 12 ++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index f3892efcf7f4..b41237bf884b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3758,7 +3758,8 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) WREG32(scratch, 0xCAFEDEAD); r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX, &ib, NULL, 256); if (r) { - return r; + DRM_ERROR("radeon: failed to get ib (%d).\n", r); + goto free_scratch; } ib.ptr[0] = PACKET0(scratch, 0); ib.ptr[1] = 0xDEADBEEF; @@ -3771,13 +3772,13 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.length_dw = 8; r = radeon_ib_schedule(rdev, &ib, NULL); if (r) { - radeon_scratch_free(rdev, scratch); - radeon_ib_free(rdev, &ib); - return r; + DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); + goto free_ib; } r = radeon_fence_wait(ib.fence, false); if (r) { - return r; + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + goto free_ib; } for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); @@ -3793,8 +3794,10 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) scratch, tmp); r = -EINVAL; } - radeon_scratch_free(rdev, scratch); +free_ib: radeon_ib_free(rdev, &ib); +free_scratch: + radeon_scratch_free(rdev, scratch); return r; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 48460b4b3e2e..39b743fff791 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2638,7 +2638,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); - return r; + goto free_scratch; } ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1); ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); @@ -2646,15 +2646,13 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.length_dw = 3; r = radeon_ib_schedule(rdev, &ib, NULL); if (r) { - radeon_scratch_free(rdev, scratch); - radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); - return r; + goto free_ib; } r = radeon_fence_wait(ib.fence, false); if (r) { DRM_ERROR("radeon: fence wait failed (%d).\n", r); - return r; + goto free_ib; } for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); @@ -2669,8 +2667,10 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) scratch, tmp); r = -EINVAL; } - radeon_scratch_free(rdev, scratch); +free_ib: radeon_ib_free(rdev, &ib); +free_scratch: + radeon_scratch_free(rdev, scratch); return r; } From dce34bfd633d23ebddb196af8a4fa1c93c90ed07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 17 Sep 2012 19:36:18 +0200 Subject: [PATCH 69/79] drm/radeon: refactor set_page chipset interface v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup the interface in preparation for hierarchical page tables. v2: add incr parameter to set_page for simple scattered PTs uptates added PDE-specific flags to r600_flags and radeon_drm.h removed superfluous value masking with 0xffffffff v3: removed superfluous bo_va->valid checking changed R600_PTE_VALID to R600_ENTRY_VALID to handle PDE too v4 (ck): fix indention style, rework and fix typos in commit message, add documentation for incr parameter, also use incr parameter for system pages v5 (agd5f): use upper_32_bits() and minor white space fixes Signed-off-by: Christian König Signed-off-by: Dmitry Cherkassov Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/ni.c | 45 ++++++++++++++---------- drivers/gpu/drm/radeon/radeon.h | 12 +++---- drivers/gpu/drm/radeon/radeon_asic.h | 6 ++-- drivers/gpu/drm/radeon/radeon_gart.c | 52 ++++++++++------------------ 4 files changed, 54 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index b23821674a95..b0a08330ed32 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1497,7 +1497,7 @@ void cayman_vm_fini(struct radeon_device *rdev) { } -#define R600_PTE_VALID (1 << 0) +#define R600_ENTRY_VALID (1 << 0) #define R600_PTE_SYSTEM (1 << 1) #define R600_PTE_SNOOPED (1 << 2) #define R600_PTE_READABLE (1 << 5) @@ -1506,8 +1506,7 @@ void cayman_vm_fini(struct radeon_device *rdev) uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags) { uint32_t r600_flags = 0; - - r600_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0; + r600_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_ENTRY_VALID : 0; r600_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0; r600_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0; if (flags & RADEON_VM_PAGE_SYSTEM) { @@ -1521,30 +1520,40 @@ uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags) * cayman_vm_set_page - update the page tables using the CP * * @rdev: radeon_device pointer + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: access flags * * Update the page tables using the CP (cayman-si). */ -void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, struct ttm_mem_reg *mem, - unsigned npages, uint32_t flags) +void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) { struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index]; - uint64_t addr, pt = vm->pt_gpu_addr + pfn * 8; + uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); int i; - addr = flags = cayman_vm_page_flags(rdev, flags); + radeon_ring_write(ring, PACKET3(PACKET3_ME_WRITE, 1 + count * 2)); + radeon_ring_write(ring, pe); + radeon_ring_write(ring, upper_32_bits(pe) & 0xff); + for (i = 0; i < count; ++i) { + uint64_t value = 0; + if (flags & RADEON_VM_PAGE_SYSTEM) { + value = radeon_vm_map_gart(rdev, addr); + value &= 0xFFFFFFFFFFFFF000ULL; + addr += incr; - radeon_ring_write(ring, PACKET3(PACKET3_ME_WRITE, 1 + npages * 2)); - radeon_ring_write(ring, pt & 0xffffffff); - radeon_ring_write(ring, (pt >> 32) & 0xff); - for (i = 0; i < npages; ++i) { - if (mem) { - addr = radeon_vm_get_addr(rdev, mem, i); - addr = addr & 0xFFFFFFFFFFFFF000ULL; - addr |= flags; + } else if (flags & RADEON_VM_PAGE_VALID) { + value = addr; + addr += incr; } - radeon_ring_write(ring, addr & 0xffffffff); - radeon_ring_write(ring, (addr >> 32) & 0xffffffff); + + value |= r600_flags; + radeon_ring_write(ring, value); + radeon_ring_write(ring, upper_32_bits(value)); } } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index de86b8e259ce..d0d414df29f3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1141,9 +1141,9 @@ struct radeon_asic { void (*fini)(struct radeon_device *rdev); u32 pt_ring_index; - void (*set_page)(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, struct ttm_mem_reg *mem, - unsigned npages, uint32_t flags); + void (*set_page)(struct radeon_device *rdev, uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); } vm; /* ring specific callbacks */ struct { @@ -1757,7 +1757,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) -#define radeon_asic_vm_set_page(rdev, v, pfn, mem, npages, flags) (rdev)->asic->vm.set_page((rdev), (v), (pfn), (mem), (npages), (flags)) +#define radeon_asic_vm_set_page(rdev, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_page((rdev), (pe), (addr), (count), (incr), (flags))) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp)) #define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp)) #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp)) @@ -1843,9 +1843,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, void radeon_vm_fence(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_fence *fence); -u64 radeon_vm_get_addr(struct radeon_device *rdev, - struct ttm_mem_reg *mem, - unsigned pfn); +uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr); int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_vm *vm, struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 8251b44550b7..9a71f445c36b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -444,9 +444,9 @@ int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); -void cayman_vm_set_page(struct radeon_device *rdev, struct radeon_vm *vm, - unsigned pfn, struct ttm_mem_reg *mem, - unsigned npages, uint32_t flags); +void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); /* DCE6 - SI */ diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2f28ff34c085..bb9fc594779c 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -822,42 +822,26 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, } /** - * radeon_vm_get_addr - get the physical address of the page + * radeon_vm_map_gart - get the physical address of a gart page * * @rdev: radeon_device pointer - * @mem: ttm mem - * @pfn: pfn + * @addr: the unmapped addr * * Look up the physical address of the page that the pte resolves * to (cayman+). * Returns the physical address of the page. */ -u64 radeon_vm_get_addr(struct radeon_device *rdev, - struct ttm_mem_reg *mem, - unsigned pfn) +uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) { - u64 addr = 0; + uint64_t result; - switch (mem->mem_type) { - case TTM_PL_VRAM: - addr = (mem->start << PAGE_SHIFT); - addr += pfn * RADEON_GPU_PAGE_SIZE; - addr += rdev->vm_manager.vram_base_offset; - break; - case TTM_PL_TT: - /* offset inside page table */ - addr = mem->start << PAGE_SHIFT; - addr += pfn * RADEON_GPU_PAGE_SIZE; - addr = addr >> PAGE_SHIFT; - /* page table offset */ - addr = rdev->gart.pages_addr[addr]; - /* in case cpu page size != gpu page size*/ - addr += (pfn * RADEON_GPU_PAGE_SIZE) & (~PAGE_MASK); - break; - default: - break; - } - return addr; + /* page table offset */ + result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; + + /* in case cpu page size != gpu page size*/ + result |= addr & (~PAGE_MASK); + + return result; } /** @@ -883,7 +867,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_semaphore *sem = NULL; struct radeon_bo_va *bo_va; unsigned ngpu_pages, ndw; - uint64_t pfn; + uint64_t pfn, addr; int r; /* nothing to do if vm isn't bound */ @@ -908,21 +892,22 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, ngpu_pages = radeon_bo_ngpu_pages(bo); bo_va->flags &= ~RADEON_VM_PAGE_VALID; bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; + pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; if (mem) { + addr = mem->start << PAGE_SHIFT; if (mem->mem_type != TTM_PL_SYSTEM) { bo_va->flags |= RADEON_VM_PAGE_VALID; bo_va->valid = true; } if (mem->mem_type == TTM_PL_TT) { bo_va->flags |= RADEON_VM_PAGE_SYSTEM; - } - if (!bo_va->valid) { - mem = NULL; + } else { + addr += rdev->vm_manager.vram_base_offset; } } else { + addr = 0; bo_va->valid = false; } - pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; if (vm->fence && radeon_fence_signaled(vm->fence)) { radeon_fence_unref(&vm->fence); @@ -950,7 +935,8 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, radeon_fence_note_sync(vm->fence, ridx); } - radeon_asic_vm_set_page(rdev, vm, pfn, mem, ngpu_pages, bo_va->flags); + radeon_asic_vm_set_page(rdev, vm->pt_gpu_addr + pfn * 8, addr, + ngpu_pages, RADEON_GPU_PAGE_SIZE, bo_va->flags); radeon_fence_unref(&vm->fence); r = radeon_fence_emit(rdev, &vm->fence, ridx); From fa87e62d357ccf73831cd52ed316593d0968020d Mon Sep 17 00:00:00 2001 From: Dmitry Cherkasov Date: Mon, 17 Sep 2012 19:36:19 +0200 Subject: [PATCH 70/79] drm/radeon: add 2-level VM pagetables support v9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PDE/PTE update code uses CP ring for memory writes. All page table entries are preallocated for now in alloc_pt(). It is made as whole because it's hard to divide it to several patches that compile and doesn't break anything being applied separately. Tested on cayman card. v2: rebased on top of "refactor set_page chipset interface v3", code cleanups v3: switched offsets calc macros to inline funcs where possible, remove pd_addr from radeon_vm, switched RADEON_BLOCK_SIZE define, to 9 (and PTE_COUNT to 1 << BLOCK_SIZE) v4 (ck): move "incr" documentation to previous patch, cleanup and document RADEON_VM_* constants, change commit message to our usual format, simplify patch allot by removing everything current not necessary, disable SI workaround. v5: (agd5f): Fix typo in tables_size calculation in radeon_vm_alloc_pt(). Second line should have been '+=' rather than '='. v6: fix npdes calculation. In scenario when pfns to be mapped overlap two PDE spans: +-----------+-------------+ | PDE span | PDE span | +-----------+----+--------+ | | +---------+ | pfns | +---------+ the following npdes calculation gives incorrect result: npdes = (nptes >> RADEON_VM_BLOCK_SIZE) + 1; For the case above picture it should give npdes = 2, but gives one. This patch corrects it by rounding last pfn up to 512 border, first - down to 512 border and then subtracting and dividing by 512. v7: Make npde calculation clearer, fix ndw calculation. v8: (agd5f): reserve enough for 2 full VM PTs, add some additional comments. v9: fix typo in npde calculation Signed-off-by: Dmitry Cherkasov Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/ni.c | 4 +- drivers/gpu/drm/radeon/radeon.h | 12 +++- drivers/gpu/drm/radeon/radeon_gart.c | 91 ++++++++++++++++++++-------- drivers/gpu/drm/radeon/si.c | 4 +- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index b0a08330ed32..f920a2c5ef23 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -782,7 +782,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) (u32)(rdev->dummy_page.addr >> 12)); WREG32(VM_CONTEXT1_CNTL2, 0); WREG32(VM_CONTEXT1_CNTL, 0); - WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | + WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); cayman_pcie_gart_tlb_flush(rdev); @@ -1580,7 +1580,7 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) radeon_ring_write(ring, vm->last_pfn); radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0)); - radeon_ring_write(ring, vm->pt_gpu_addr >> 12); + radeon_ring_write(ring, vm->pd_gpu_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d0d414df29f3..519d8a32aa43 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -648,15 +648,23 @@ struct radeon_ring { * VM */ +/* maximum number of VMIDs */ #define RADEON_NUM_VM 16 +/* defines number of bits in page table versus page directory, + * a page is 4KB so we have 12 bits offset, 9 bits in the page + * table and the remaining 19 bits are in the page directory */ +#define RADEON_VM_BLOCK_SIZE 9 + +/* number of entries in page table */ +#define RADEON_VM_PTE_COUNT (1 << RADEON_VM_BLOCK_SIZE) + struct radeon_vm { struct list_head list; struct list_head va; unsigned id; unsigned last_pfn; - u64 pt_gpu_addr; - u64 *pt; + u64 pd_gpu_addr; struct radeon_sa_bo *sa_bo; struct mutex mutex; /* last fence for cs using this vm */ diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index bb9fc594779c..753b7ca3c807 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -422,6 +422,18 @@ void radeon_gart_fini(struct radeon_device *rdev) * TODO bind a default page at vm initialization for default address */ +/** + * radeon_vm_directory_size - returns the size of the page directory in bytes + * + * @rdev: radeon_device pointer + * + * Calculate the size of the page directory in bytes (cayman+). + */ +static unsigned radeon_vm_directory_size(struct radeon_device *rdev) +{ + return (rdev->vm_manager.max_pfn >> RADEON_VM_BLOCK_SIZE) * 8; +} + /** * radeon_vm_manager_init - init the vm manager * @@ -435,11 +447,15 @@ int radeon_vm_manager_init(struct radeon_device *rdev) struct radeon_vm *vm; struct radeon_bo_va *bo_va; int r; + unsigned size; if (!rdev->vm_manager.enabled) { /* allocate enough for 2 full VM pts */ + size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev)); + size += RADEON_GPU_PAGE_ALIGN(rdev->vm_manager.max_pfn * 8); + size *= 2; r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, - rdev->vm_manager.max_pfn * 8 * 2, + size, RADEON_GEM_DOMAIN_VRAM); if (r) { dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", @@ -490,7 +506,6 @@ static void radeon_vm_free_pt(struct radeon_device *rdev, list_del_init(&vm->list); radeon_sa_bo_free(rdev, &vm->sa_bo, vm->fence); - vm->pt = NULL; list_for_each_entry(bo_va, &vm->va, vm_list) { bo_va->valid = false; @@ -546,11 +561,17 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) { struct radeon_vm *vm_evict; int r; + u64 *pd_addr; + int tables_size; if (vm == NULL) { return -EINVAL; } + /* allocate enough to cover the current VM size */ + tables_size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev)); + tables_size += RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8); + if (vm->sa_bo != NULL) { /* update lru */ list_del_init(&vm->list); @@ -560,8 +581,7 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) retry: r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo, - RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8), - RADEON_GPU_PAGE_SIZE, false); + tables_size, RADEON_GPU_PAGE_SIZE, false); if (r == -ENOMEM) { if (list_empty(&rdev->vm_manager.lru_vm)) { return r; @@ -576,9 +596,9 @@ retry: return r; } - vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo); - vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo); - memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8)); + pd_addr = radeon_sa_bo_cpu_addr(vm->sa_bo); + vm->pd_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo); + memset(pd_addr, 0, tables_size); list_add_tail(&vm->list, &rdev->vm_manager.lru_vm); return radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo, @@ -866,8 +886,9 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[ridx]; struct radeon_semaphore *sem = NULL; struct radeon_bo_va *bo_va; - unsigned ngpu_pages, ndw; - uint64_t pfn, addr; + unsigned nptes, npdes, ndw; + uint64_t pe, addr; + uint64_t pfn; int r; /* nothing to do if vm isn't bound */ @@ -889,10 +910,8 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) return 0; - ngpu_pages = radeon_bo_ngpu_pages(bo); bo_va->flags &= ~RADEON_VM_PAGE_VALID; bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; - pfn = bo_va->soffset / RADEON_GPU_PAGE_SIZE; if (mem) { addr = mem->start << PAGE_SHIFT; if (mem->mem_type != TTM_PL_SYSTEM) { @@ -921,9 +940,26 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, } /* estimate number of dw needed */ + /* reserve space for 32-bit padding */ ndw = 32; - ndw += (ngpu_pages >> 12) * 3; - ndw += ngpu_pages * 2; + + nptes = radeon_bo_ngpu_pages(bo); + + pfn = (bo_va->soffset / RADEON_GPU_PAGE_SIZE); + + /* handle cases where a bo spans several pdes */ + npdes = (ALIGN(pfn + nptes, RADEON_VM_PTE_COUNT) - + (pfn & ~(RADEON_VM_PTE_COUNT - 1))) >> RADEON_VM_BLOCK_SIZE; + + /* reserve space for one header for every 2k dwords */ + ndw += (nptes >> 11) * 3; + /* reserve space for pte addresses */ + ndw += nptes * 2; + + /* reserve space for one header for every 2k dwords */ + ndw += (npdes >> 11) * 3; + /* reserve space for pde addresses */ + ndw += npdes * 2; r = radeon_ring_lock(rdev, ring, ndw); if (r) { @@ -935,8 +971,22 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, radeon_fence_note_sync(vm->fence, ridx); } - radeon_asic_vm_set_page(rdev, vm->pt_gpu_addr + pfn * 8, addr, - ngpu_pages, RADEON_GPU_PAGE_SIZE, bo_va->flags); + /* update page table entries */ + pe = vm->pd_gpu_addr; + pe += radeon_vm_directory_size(rdev); + pe += (bo_va->soffset / RADEON_GPU_PAGE_SIZE) * 8; + + radeon_asic_vm_set_page(rdev, pe, addr, nptes, + RADEON_GPU_PAGE_SIZE, bo_va->flags); + + /* update page directory entries */ + addr = pe; + + pe = vm->pd_gpu_addr; + pe += ((bo_va->soffset / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE) * 8; + + radeon_asic_vm_set_page(rdev, pe, addr, npdes, + RADEON_VM_PTE_COUNT * 8, RADEON_VM_PAGE_VALID); radeon_fence_unref(&vm->fence); r = radeon_fence_emit(rdev, &vm->fence, ridx); @@ -1018,18 +1068,11 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) vm->id = 0; vm->fence = NULL; + vm->last_pfn = 0; mutex_init(&vm->mutex); INIT_LIST_HEAD(&vm->list); INIT_LIST_HEAD(&vm->va); - /* SI requires equal sized PTs for all VMs, so always set - * last_pfn to max_pfn. cayman allows variable sized - * pts so we can grow then as needed. Once we switch - * to two level pts we can unify this again. - */ - if (rdev->family >= CHIP_TAHITI) - vm->last_pfn = rdev->vm_manager.max_pfn; - else - vm->last_pfn = 0; + /* map the ib pool buffer at 0 in virtual address space, set * read only */ diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 2a5c337715de..156c9941e6ca 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2426,7 +2426,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(rdev->dummy_page.addr >> 12)); WREG32(VM_CONTEXT1_CNTL2, 0); - WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) | + WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); si_pcie_gart_tlb_flush(rdev); @@ -2804,7 +2804,7 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) radeon_ring_write(ring, PACKET0(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2), 0)); } - radeon_ring_write(ring, vm->pt_gpu_addr >> 12); + radeon_ring_write(ring, vm->pd_gpu_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); From 46fc8781bf428ce1094a5980ca2b92a49d33a8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Tue, 25 Sep 2012 01:45:33 +0200 Subject: [PATCH 71/79] drm/radeon/kms: allow STRMOUT_BASE_UPDATE on RS780 and RS880 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to make streamout work there. Signed-off-by: Marek Olšák Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/r600_cs.c | 3 ++- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 32fbdf9ff265..853f05ced1b1 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -2180,7 +2180,8 @@ static int r600_packet3_check(struct radeon_cs_parser *p, } break; case PACKET3_STRMOUT_BASE_UPDATE: - if (p->family < CHIP_RV770) { + /* RS780 and RS880 also need this */ + if (p->family < CHIP_RS780) { DRM_ERROR("STRMOUT_BASE_UPDATE only supported on 7xx\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 8c593ea82c41..2c8b0f849e36 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -64,9 +64,10 @@ * 2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query * 2.21.0 - r600-r700: FMASK and CMASK * 2.22.0 - r600 only: RESOLVE_BOX allowed + * 2.23.0 - allow STRMOUT_BASE_UPDATE on RS780 and RS880 */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 22 +#define KMS_DRIVER_MINOR 23 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); From 61051afd3540da71c1ac32f17ed663595a0f7ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Tue, 25 Sep 2012 03:34:01 +0200 Subject: [PATCH 72/79] drm/radeon: allow MIP_ADDRESS=0 for MSAA textures on Evergreen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIP_ADDRESS should point to the resolved FMASK for an MSAA texture. Setting MIP_ADDRESS to 0 means the FMASK pointer is invalid (the GPU won't read the memory then). The userspace has to set MIP_ADDRESS to 0 and *not* emit any relocation for it. Signed-off-by: Marek Olšák Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/evergreen_cs.c | 59 +++++++++++++++++++++++---- drivers/gpu/drm/radeon/radeon_drv.c | 3 +- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 0f32ea4d608b..2ceab2b52d69 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -846,6 +846,16 @@ static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p, return -EINVAL; } + if (!mipmap) { + if (llevel) { + dev_warn(p->dev, "%s:%i got NULL MIP_ADDRESS relocation\n", + __func__, __LINE__); + return -EINVAL; + } else { + return 0; /* everything's ok */ + } + } + /* check mipmap size */ for (i = 1; i <= llevel; i++) { unsigned w, h, d; @@ -1080,6 +1090,27 @@ static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, return 0; } +/** + * evergreen_cs_packet_next_is_pkt3_nop() - test if the next packet is NOP + * @p: structure holding the parser context. + * + * Check if the next packet is a relocation packet3. + **/ +static bool evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet p3reloc; + int r; + + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return false; + } + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + return false; + } + return true; +} + /** * evergreen_cs_packet_next_vline() - parse userspace VLINE packet * @parser: parser structure holding parsing context. @@ -2330,7 +2361,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, for (i = 0; i < (pkt->count / 8); i++) { struct radeon_bo *texture, *mipmap; u32 toffset, moffset; - u32 size, offset; + u32 size, offset, mip_address, tex_dim; switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) { case SQ_TEX_VTX_VALID_TEXTURE: @@ -2359,14 +2390,28 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } texture = reloc->robj; toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + /* tex mip base */ - r = evergreen_cs_packet_next_reloc(p, &reloc); - if (r) { - DRM_ERROR("bad SET_RESOURCE (tex)\n"); - return -EINVAL; + tex_dim = ib[idx+1+(i*8)+0] & 0x7; + mip_address = ib[idx+1+(i*8)+3]; + + if ((tex_dim == SQ_TEX_DIM_2D_MSAA || tex_dim == SQ_TEX_DIM_2D_ARRAY_MSAA) && + !mip_address && + !evergreen_cs_packet_next_is_pkt3_nop(p)) { + /* MIP_ADDRESS should point to FMASK for an MSAA texture. + * It should be 0 if FMASK is disabled. */ + moffset = 0; + mipmap = NULL; + } else { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (tex)\n"); + return -EINVAL; + } + moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + mipmap = reloc->robj; } - moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); - mipmap = reloc->robj; + r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8)); if (r) return r; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 2c8b0f849e36..27ece75b4789 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -65,9 +65,10 @@ * 2.21.0 - r600-r700: FMASK and CMASK * 2.22.0 - r600 only: RESOLVE_BOX allowed * 2.23.0 - allow STRMOUT_BASE_UPDATE on RS780 and RS880 + * 2.24.0 - eg only: allow MIP_ADDRESS=0 for MSAA textures */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 23 +#define KMS_DRIVER_MINOR 24 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); From 3a6d59df80897cc87812b6826d70085905bed013 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 26 Sep 2012 12:31:45 -0400 Subject: [PATCH 73/79] drm/radeon: Add MSI quirk for gateway RS690 Fixes another system on: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index c4e638d6f8af..2da4465e3c6d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -202,6 +202,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x01fd)) return true; + /* Gateway RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x107b) && + (rdev->pdev->subsystem_device == 0x0185)) + return true; + /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. From fb6ca6d154cdcd53e7f27f8dbba513830372699b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 26 Sep 2012 12:40:45 -0400 Subject: [PATCH 74/79] drm/radeon: force MSIs on RS690 asics There are so many quirks, lets just try and force this for all RS690s. See: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 2da4465e3c6d..b06fa5936100 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -208,6 +208,10 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x0185)) return true; + /* try and enable MSIs by default on all RS690s */ + if (rdev->family == CHIP_RS690) + return true; + /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. From eb2c27a02bcf6013cda5d9e6277d50f7b4cfc13d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 1 Oct 2012 18:28:09 -0400 Subject: [PATCH 75/79] drm/radeon: fix radeon power state debug output Driver used to print "default" as the state type regardless of whether it is the default state. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_pm.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index e024435a856c..8d64138b95f3 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -33,7 +33,7 @@ #define RADEON_WAIT_VBLANK_TIMEOUT 200 static const char *radeon_pm_state_type_name[5] = { - "Default", + "", "Powersave", "Battery", "Balanced", @@ -294,17 +294,15 @@ static void radeon_pm_print_states(struct radeon_device *rdev) for (j = 0; j < power_state->num_clock_modes; j++) { clock_info = &(power_state->clock_info[j]); if (rdev->flags & RADEON_IS_IGP) - DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n", - j, - clock_info->sclk * 10, - clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); + DRM_DEBUG_DRIVER("\t\t%d e: %d\n", + j, + clock_info->sclk * 10); else - DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n", - j, - clock_info->sclk * 10, - clock_info->mclk * 10, - clock_info->voltage.voltage, - clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); + DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d\n", + j, + clock_info->sclk * 10, + clock_info->mclk * 10, + clock_info->voltage.voltage); } } } From 27810fb2d2edacf2961dbedfe9e9f8d2e5080ea5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 1 Oct 2012 19:25:11 -0400 Subject: [PATCH 76/79] drm/radeon/pm: fix multi-head profile handling on BTC+ (v2) Starting on BTC, there are no longer separate states for single head and multi-head, we just use the high mclk/voltage for all states for multi-head. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=49981 v2: fix typo Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/evergreen.c | 58 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.c | 4 +- drivers/gpu/drm/radeon/radeon_asic.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 17 +++++++- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ef47879c5d40..c4ded396b78d 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -325,6 +325,64 @@ void sumo_pm_init_profile(struct radeon_device *rdev) rdev->pm.power_state[idx].num_clock_modes - 1; } +/** + * btc_pm_init_profile - Initialize power profiles callback. + * + * @rdev: radeon_device pointer + * + * Initialize the power states used in profile mode + * (BTC, cayman). + * Used for profile mode only. + */ +void btc_pm_init_profile(struct radeon_device *rdev) +{ + int idx; + + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* starting with BTC, there is one state that is used for both + * MH and SH. Difference is that we always use the high clock index for + * mclk. + */ + if (rdev->flags & RADEON_IS_MOBILITY) + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + else + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; +} + /** * evergreen_pm_misc - set additional pm hw parameters callback. * diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 6225e1977700..0f31c43b07b5 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1357,7 +1357,7 @@ static struct radeon_asic btc_asic = { .misc = &evergreen_pm_misc, .prepare = &evergreen_pm_prepare, .finish = &evergreen_pm_finish, - .init_profile = &r600_pm_init_profile, + .init_profile = &btc_pm_init_profile, .get_dynpm_state = &r600_pm_get_dynpm_state, .get_engine_clock = &radeon_atom_get_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock, @@ -1462,7 +1462,7 @@ static struct radeon_asic cayman_asic = { .misc = &evergreen_pm_misc, .prepare = &evergreen_pm_prepare, .finish = &evergreen_pm_finish, - .init_profile = &r600_pm_init_profile, + .init_profile = &btc_pm_init_profile, .get_dynpm_state = &r600_pm_get_dynpm_state, .get_engine_clock = &radeon_atom_get_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 9a71f445c36b..f158c11c9065 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -420,6 +420,7 @@ extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); extern void sumo_pm_init_profile(struct radeon_device *rdev); +extern void btc_pm_init_profile(struct radeon_device *rdev); extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc); extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 8d64138b95f3..bc2e7050a9d8 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -167,8 +167,21 @@ static void radeon_set_power_state(struct radeon_device *rdev) if (sclk > rdev->pm.default_sclk) sclk = rdev->pm.default_sclk; - mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk; + /* starting with BTC, there is one state that is used for both + * MH and SH. Difference is that we always use the high clock index for + * mclk. + */ + if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && + (rdev->family >= CHIP_BARTS) && + rdev->pm.active_crtc_count && + ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || + (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].mclk; + else + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->pm.default_mclk) mclk = rdev->pm.default_mclk; From 76c44f2c0d008b60ce3058c51d85fa36d98c3681 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Oct 2012 14:39:18 -0400 Subject: [PATCH 77/79] drm/radeon: use WRITE_DATA packets for vm flush on SI This is the preferred packet for writing data to memory or registers on SI. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/si.c | 28 +++++++++++++++++++++------- drivers/gpu/drm/radeon/sid.h | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 156c9941e6ca..916d1cb274c0 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2797,21 +2797,35 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) if (vm == NULL) return; + /* write new base address */ + radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + WRITE_DATA_DST_SEL(0))); + if (vm->id < 8) { - radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR - + (vm->id << 2), 0)); + radeon_ring_write(ring, + (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2); } else { - radeon_ring_write(ring, PACKET0(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR - + ((vm->id - 8) << 2), 0)); + radeon_ring_write(ring, + (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); } + radeon_ring_write(ring, 0); radeon_ring_write(ring, vm->pd_gpu_addr >> 12); /* flush hdp cache */ - radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); + radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + WRITE_DATA_DST_SEL(0))); + radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); + radeon_ring_write(ring, 0); radeon_ring_write(ring, 0x1); - /* bits 0-7 are the VM contexts0-7 */ - radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); + /* bits 0-15 are the VM contexts0-15 */ + radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + WRITE_DATA_DST_SEL(0))); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << ib->vm->id); } diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index ef4815c27b1c..7d2a20e56577 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -812,6 +812,21 @@ #define PACKET3_DRAW_INDEX_OFFSET_2 0x35 #define PACKET3_DRAW_INDEX_MULTI_ELEMENT 0x36 #define PACKET3_WRITE_DATA 0x37 +#define WRITE_DATA_DST_SEL(x) ((x) << 8) + /* 0 - register + * 1 - memory (sync - via GRBM) + * 2 - tc/l2 + * 3 - gds + * 4 - reserved + * 5 - memory (async - direct) + */ +#define WR_ONE_ADDR (1 << 16) +#define WR_CONFIRM (1 << 20) +#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30) + /* 0 - me + * 1 - pfp + * 2 - ce + */ #define PACKET3_DRAW_INDEX_INDIRECT_MULTI 0x38 #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A From 498522b455e8867bed5d59234c209b0be8ec4b57 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Oct 2012 14:43:38 -0400 Subject: [PATCH 78/79] drm/radeon: rework the vm_flush interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the vm and ring index rather than an IB. This allows us to use the vm_flush interface for non-IB cases in the future. Signed-off-by: Alex Deucher Reviewed-by: Christian König --- drivers/gpu/drm/radeon/ni.c | 7 +++---- drivers/gpu/drm/radeon/radeon.h | 4 ++-- drivers/gpu/drm/radeon/radeon_asic.h | 4 ++-- drivers/gpu/drm/radeon/radeon_ring.c | 2 +- drivers/gpu/drm/radeon/si.c | 7 +++---- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index f920a2c5ef23..9a46f7d4e61f 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1565,10 +1565,9 @@ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe, * Update the page table base and flush the VM TLB * using the CP (cayman-si). */ -void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) +void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) { - struct radeon_ring *ring = &rdev->ring[ib->ring]; - struct radeon_vm *vm = ib->vm; + struct radeon_ring *ring = &rdev->ring[ridx]; if (vm == NULL) return; @@ -1588,5 +1587,5 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) /* bits 0-7 are the VM contexts0-7 */ radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); - radeon_ring_write(ring, 1 << ib->vm->id); + radeon_ring_write(ring, 1 << vm->id); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 519d8a32aa43..b04c06444d8b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1165,7 +1165,7 @@ struct radeon_asic { int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp); bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp); - void (*vm_flush)(struct radeon_device *rdev, struct radeon_ib *ib); + void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); } ring[RADEON_NUM_RINGS]; /* irqs */ struct { @@ -1772,7 +1772,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib)) #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib)) #define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp)) -#define radeon_ring_vm_flush(rdev, r, ib) (rdev)->asic->ring[(r)].vm_flush((rdev), (ib)) +#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)].vm_flush((rdev), (r), (vm)) #define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev)) #define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index f158c11c9065..5c823e77bc21 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -443,7 +443,7 @@ int cayman_asic_reset(struct radeon_device *rdev); void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); -void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); +void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe, uint64_t addr, unsigned count, @@ -470,7 +470,7 @@ int si_irq_set(struct radeon_device *rdev); int si_irq_process(struct radeon_device *rdev); int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); -void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib); +void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); uint64_t si_get_gpu_clock(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index d90b0bc6f072..028508859a3b 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -162,7 +162,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, } /* if we can't remember our last VM flush then flush now! */ if (ib->vm && !ib->vm->last_flush) { - radeon_ring_vm_flush(rdev, ib->ring, ib); + radeon_ring_vm_flush(rdev, ib->ring, ib->vm); } if (const_ib) { radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 916d1cb274c0..3319a9a53d8e 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2789,10 +2789,9 @@ void si_vm_fini(struct radeon_device *rdev) { } -void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) +void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) { - struct radeon_ring *ring = &rdev->ring[ib->ring]; - struct radeon_vm *vm = ib->vm; + struct radeon_ring *ring = &rdev->ring[ridx]; if (vm == NULL) return; @@ -2826,7 +2825,7 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ib *ib) WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); - radeon_ring_write(ring, 1 << ib->vm->id); + radeon_ring_write(ring, 1 << vm->id); } /* From 82ffd92b162ece87c863c075d993c65333e8e78b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Oct 2012 14:47:46 -0400 Subject: [PATCH 79/79] drm/radeon: add vm set_page() callback for SI Use the new WRITE_DATA packet rather than the legacy ME_WRITE packet. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_asic.c | 2 +- drivers/gpu/drm/radeon/radeon_asic.h | 3 ++ drivers/gpu/drm/radeon/si.c | 41 ++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 0f31c43b07b5..654520b95ab7 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1602,7 +1602,7 @@ static struct radeon_asic si_asic = { .init = &si_vm_init, .fini = &si_vm_fini, .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, - .set_page = &cayman_vm_set_page, + .set_page = &si_vm_set_page, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 5c823e77bc21..5e3a0e5c6be1 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -470,6 +470,9 @@ int si_irq_set(struct radeon_device *rdev); int si_irq_process(struct radeon_device *rdev); int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); +void si_vm_set_page(struct radeon_device *rdev, uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); uint64_t si_get_gpu_clock(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 3319a9a53d8e..c76825ffa37f 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2789,6 +2789,47 @@ void si_vm_fini(struct radeon_device *rdev) { } +/** + * si_vm_set_page - update the page tables using the CP + * + * @rdev: radeon_device pointer + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: access flags + * + * Update the page tables using the CP (cayman-si). + */ +void si_vm_set_page(struct radeon_device *rdev, uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) +{ + struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index]; + uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); + int i; + uint64_t value; + + radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 2 + count * 2)); + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + WRITE_DATA_DST_SEL(1))); + radeon_ring_write(ring, pe); + radeon_ring_write(ring, upper_32_bits(pe)); + for (i = 0; i < count; ++i) { + if (flags & RADEON_VM_PAGE_SYSTEM) { + value = radeon_vm_map_gart(rdev, addr); + value &= 0xFFFFFFFFFFFFF000ULL; + } else if (flags & RADEON_VM_PAGE_VALID) + value = addr; + else + value = 0; + addr += incr; + value |= r600_flags; + radeon_ring_write(ring, value); + radeon_ring_write(ring, upper_32_bits(value)); + } +} + void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) { struct radeon_ring *ring = &rdev->ring[ridx];