diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
24 files changed, 673 insertions, 141 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f95d7fc1f5e0..061fa0a28900 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2306,22 +2306,20 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin return radeon_ring_test_lockup(rdev, ring); } -static int evergreen_gpu_soft_reset(struct radeon_device *rdev) +static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev) { - struct evergreen_mc_save save; u32 grbm_reset = 0; if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - return 0; + return; - dev_info(rdev->dev, "GPU softreset \n"); - dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", RREG32(GRBM_STATUS)); - dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", RREG32(GRBM_STATUS_SE0)); - dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n", RREG32(GRBM_STATUS_SE1)); - dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", RREG32(SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -2331,10 +2329,7 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); - evergreen_mc_stop(rdev, &save); - if (evergreen_mc_wait_for_idle(rdev)) { - dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); - } + /* Disable CP parsing/prefetching */ WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); @@ -2358,15 +2353,14 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); - /* Wait a little for things to settle down */ - udelay(50); - dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + + dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", RREG32(GRBM_STATUS)); - dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", RREG32(GRBM_STATUS_SE0)); - dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n", RREG32(GRBM_STATUS_SE1)); - dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", RREG32(SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -2376,13 +2370,65 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); +} + +static void evergreen_gpu_soft_reset_dma(struct radeon_device *rdev) +{ + u32 tmp; + + if (RREG32(DMA_STATUS_REG) & DMA_IDLE) + return; + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + + /* Reset dma */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); + RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); +} + +static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) +{ + struct evergreen_mc_save save; + + if (reset_mask == 0) + return 0; + + dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); + + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) + evergreen_gpu_soft_reset_gfx(rdev); + + if (reset_mask & RADEON_RESET_DMA) + evergreen_gpu_soft_reset_dma(rdev); + + /* Wait a little for things to settle down */ + udelay(50); + evergreen_mc_resume(rdev, &save); return 0; } int evergreen_asic_reset(struct radeon_device *rdev) { - return evergreen_gpu_soft_reset(rdev); + return evergreen_gpu_soft_reset(rdev, (RADEON_RESET_GFX | + RADEON_RESET_COMPUTE | + RADEON_RESET_DMA)); } /* Interrupts */ @@ -3215,7 +3261,7 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0)); /* flush HDP */ radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); - radeon_ring_write(ring, (0xf << 16) | HDP_MEM_COHERENCY_FLUSH_CNTL); + radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2)); radeon_ring_write(ring, 1); } diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 74c6b42d2597..7a445666e71f 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -2654,6 +2654,35 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, ib[idx+4] = upper_32_bits(offset) & 0xff; } break; + case PACKET3_MEM_WRITE: + { + u64 offset; + + if (pkt->count != 3) { + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+0); + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; + if (offset & 0x7) { + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); + return -EINVAL; + } + if ((offset + 8) > radeon_bo_size(reloc->robj)) { + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", + offset + 8, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + offset += reloc->lobj.gpu_offset; + ib[idx+0] = offset; + ib[idx+1] = upper_32_bits(offset) & 0xff; + break; + } case PACKET3_COPY_DW: if (pkt->count != 4) { DRM_ERROR("bad COPY_DW (invalid count)\n"); @@ -3287,6 +3316,7 @@ static bool evergreen_vm_reg_valid(u32 reg) /* check config regs */ switch (reg) { + case WAIT_UNTIL: case GRBM_GFX_INDEX: case CP_STRMOUT_CNTL: case CP_COHER_CNTL: diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index cb9baaac9e85..0bfd0e9e469b 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -742,8 +742,9 @@ #define SOFT_RESET_ROM (1 << 14) #define SOFT_RESET_SEM (1 << 15) #define SOFT_RESET_VMC (1 << 17) +#define SOFT_RESET_DMA (1 << 20) #define SOFT_RESET_TST (1 << 21) -#define SOFT_RESET_REGBB (1 << 22) +#define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) /* display watermarks */ @@ -2027,4 +2028,15 @@ /* cayman packet3 addition */ #define CAYMAN_PACKET3_DEALLOC_STATE 0x14 +/* DMA regs common on r6xx/r7xx/evergreen/ni */ +#define DMA_RB_CNTL 0xd000 +# define DMA_RB_ENABLE (1 << 0) +# define DMA_RB_SIZE(x) ((x) << 1) /* log2 */ +# define DMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */ +# define DMA_RPTR_WRITEBACK_ENABLE (1 << 12) +# define DMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */ +# define DMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */ +#define DMA_STATUS_REG 0xd034 +# define DMA_IDLE (1 << 0) + #endif diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7bdbcb00aaf2..896f1cbc58a5 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1306,22 +1306,20 @@ void cayman_dma_fini(struct radeon_device *rdev) radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]); } -static int cayman_gpu_soft_reset(struct radeon_device *rdev) +static void cayman_gpu_soft_reset_gfx(struct radeon_device *rdev) { - struct evergreen_mc_save save; u32 grbm_reset = 0; if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - return 0; + return; - dev_info(rdev->dev, "GPU softreset \n"); - dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", RREG32(GRBM_STATUS)); - dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", RREG32(GRBM_STATUS_SE0)); - dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n", RREG32(GRBM_STATUS_SE1)); - dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", RREG32(SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -1331,19 +1329,7 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); - dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(0x14F8)); - dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(0x14D8)); - dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(0x14FC)); - dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(0x14DC)); - evergreen_mc_stop(rdev, &save); - if (evergreen_mc_wait_for_idle(rdev)) { - dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); - } /* Disable CP parsing/prefetching */ WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); @@ -1368,16 +1354,14 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev) udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); - /* Wait a little for things to settle down */ - udelay(50); - dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n", RREG32(GRBM_STATUS)); - dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n", RREG32(GRBM_STATUS_SE0)); - dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n", RREG32(GRBM_STATUS_SE1)); - dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n", RREG32(SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -1387,13 +1371,81 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); + +} + +static void cayman_gpu_soft_reset_dma(struct radeon_device *rdev) +{ + u32 tmp; + + if (RREG32(DMA_STATUS_REG) & DMA_IDLE) + return; + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + + /* dma0 */ + tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp); + + /* dma1 */ + tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp); + + /* Reset dma */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); + RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + +} + +static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) +{ + struct evergreen_mc_save save; + + if (reset_mask == 0) + return 0; + + dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); + + dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_ADDR 0x%08X\n", + RREG32(0x14F8)); + dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n", + RREG32(0x14D8)); + dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", + RREG32(0x14FC)); + dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", + RREG32(0x14DC)); + + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) + cayman_gpu_soft_reset_gfx(rdev); + + if (reset_mask & RADEON_RESET_DMA) + cayman_gpu_soft_reset_dma(rdev); + + /* Wait a little for things to settle down */ + udelay(50); + evergreen_mc_resume(rdev, &save); return 0; } int cayman_asic_reset(struct radeon_device *rdev) { - return cayman_gpu_soft_reset(rdev); + return cayman_gpu_soft_reset(rdev, (RADEON_RESET_GFX | + RADEON_RESET_COMPUTE | + RADEON_RESET_DMA)); } /** diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index b93186b8ee4b..48e5022ee921 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -65,7 +65,7 @@ #define SOFT_RESET_VMC (1 << 17) #define SOFT_RESET_DMA (1 << 20) #define SOFT_RESET_TST (1 << 21) -#define SOFT_RESET_REGBB (1 << 22) +#define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) #define VM_CONTEXT0_REQUEST_RESPONSE 0x1470 @@ -675,4 +675,3 @@ #define DMA_PACKET_NOP 0xf #endif - diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2aaf147969bd..537e259b3837 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1258,9 +1258,8 @@ 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. */ -static int r600_gpu_soft_reset(struct radeon_device *rdev) +static void r600_gpu_soft_reset_gfx(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) | S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) | S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) | @@ -1280,14 +1279,13 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev) u32 tmp; if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - return 0; + return; - dev_info(rdev->dev, "GPU softreset \n"); - dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " R_008010_GRBM_STATUS = 0x%08X\n", RREG32(R_008010_GRBM_STATUS)); - dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", + dev_info(rdev->dev, " R_008014_GRBM_STATUS2 = 0x%08X\n", RREG32(R_008014_GRBM_STATUS2)); - dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " R_000E50_SRBM_STATUS = 0x%08X\n", RREG32(R_000E50_SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -1297,12 +1295,10 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); - rv515_mc_stop(rdev, &save); - if (r600_mc_wait_for_idle(rdev)) { - dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); - } + /* Disable CP parsing/prefetching */ WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); + /* Check if any of the rendering block is busy and reset it */ if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) || (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) { @@ -1332,13 +1328,12 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev) RREG32(R_008020_GRBM_SOFT_RESET); mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); - /* Wait a little for things to settle down */ - mdelay(1); - dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", + + dev_info(rdev->dev, " R_008010_GRBM_STATUS = 0x%08X\n", RREG32(R_008010_GRBM_STATUS)); - dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", + dev_info(rdev->dev, " R_008014_GRBM_STATUS2 = 0x%08X\n", RREG32(R_008014_GRBM_STATUS2)); - dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", + dev_info(rdev->dev, " R_000E50_SRBM_STATUS = 0x%08X\n", RREG32(R_000E50_SRBM_STATUS)); dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", RREG32(CP_STALLED_STAT1)); @@ -1348,6 +1343,60 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev) RREG32(CP_BUSY_STAT)); dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", RREG32(CP_STAT)); + +} + +static void r600_gpu_soft_reset_dma(struct radeon_device *rdev) +{ + u32 tmp; + + if (RREG32(DMA_STATUS_REG) & DMA_IDLE) + return; + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + + /* Reset dma */ + if (rdev->family >= CHIP_RV770) + WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA); + else + WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); + RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + + dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); +} + +static int r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) +{ + struct rv515_mc_save save; + + if (reset_mask == 0) + return 0; + + dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); + + rv515_mc_stop(rdev, &save); + if (r600_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) + r600_gpu_soft_reset_gfx(rdev); + + if (reset_mask & RADEON_RESET_DMA) + r600_gpu_soft_reset_dma(rdev); + + /* Wait a little for things to settle down */ + mdelay(1); + rv515_mc_resume(rdev, &save); return 0; } @@ -1395,7 +1444,9 @@ bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) int r600_asic_reset(struct radeon_device *rdev) { - return r600_gpu_soft_reset(rdev); + return r600_gpu_soft_reset(rdev, (RADEON_RESET_GFX | + RADEON_RESET_COMPUTE | + RADEON_RESET_DMA)); } u32 r6xx_remap_render_backend(struct radeon_device *rdev, @@ -2595,7 +2646,7 @@ int r600_copy_blit(struct radeon_device *rdev, * @num_gpu_pages: number of GPU pages to xfer * @fence: radeon fence object * - * Copy GPU paging using the DMA engine (r6xx-r7xx). + * Copy GPU paging using the DMA engine (r6xx). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ @@ -2618,8 +2669,8 @@ int r600_copy_dma(struct radeon_device *rdev, } size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; - num_loops = DIV_ROUND_UP(size_in_dw, 0xffff); - r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8); + num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE); + r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); @@ -2636,14 +2687,14 @@ int r600_copy_dma(struct radeon_device *rdev, for (i = 0; i < num_loops; i++) { cur_size_in_dw = size_in_dw; - if (cur_size_in_dw > 0xFFFF) - cur_size_in_dw = 0xFFFF; + if (cur_size_in_dw > 0xFFFE) + cur_size_in_dw = 0xFFFE; size_in_dw -= cur_size_in_dw; radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); radeon_ring_write(ring, dst_offset & 0xfffffffc); radeon_ring_write(ring, src_offset & 0xfffffffc); - radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff); - radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff); + radeon_ring_write(ring, (((upper_32_bits(dst_offset) & 0xff) << 16) | + (upper_32_bits(src_offset) & 0xff))); src_offset += cur_size_in_dw * 4; dst_offset += cur_size_in_dw * 4; } diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0be768be530c..03191a56eb44 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -2294,6 +2294,35 @@ static int r600_packet3_check(struct radeon_cs_parser *p, ib[idx+4] = upper_32_bits(offset) & 0xff; } break; + case PACKET3_MEM_WRITE: + { + u64 offset; + + if (pkt->count != 3) { + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); + return -EINVAL; + } + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+0); + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; + if (offset & 0x7) { + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); + return -EINVAL; + } + if ((offset + 8) > radeon_bo_size(reloc->robj)) { + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", + offset + 8, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + offset += reloc->lobj.gpu_offset; + ib[idx+0] = offset; + ib[idx+1] = upper_32_bits(offset) & 0xff; + break; + } case PACKET3_COPY_DW: if (pkt->count != 4) { DRM_ERROR("bad COPY_DW (invalid count)\n"); @@ -2648,16 +2677,29 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) } p->idx += 7; } else { - src_offset = ib[idx+2]; - src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; - dst_offset = ib[idx+1]; - dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; + if (p->family >= CHIP_RV770) { + src_offset = ib[idx+2]; + src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; + dst_offset = ib[idx+1]; + dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; - ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); - ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); - ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; - ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; - p->idx += 5; + ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); + ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); + ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; + ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; + p->idx += 5; + } else { + src_offset = ib[idx+2]; + src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; + dst_offset = ib[idx+1]; + dst_offset |= ((u64)(ib[idx+3] & 0xff0000)) << 16; + + ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); + ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); + ib[idx+3] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; + ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff) << 16; + p->idx += 4; + } } if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { dev_warn(p->dev, "DMA copy src buffer too small (%llu %lu)\n", diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5dc744d43d12..34e52304a525 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -132,6 +132,11 @@ extern int radeon_lockup_timeout; #define RADEON_VA_RESERVED_SIZE (8 << 20) #define RADEON_IB_VM_MAX_SIZE (64 << 10) +/* reset flags */ +#define RADEON_RESET_GFX (1 << 0) +#define RADEON_RESET_COMPUTE (1 << 1) +#define RADEON_RESET_DMA (1 << 2) + /* * Errata workarounds. */ @@ -225,12 +230,13 @@ struct radeon_fence { int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); int radeon_fence_driver_init(struct radeon_device *rdev); void radeon_fence_driver_fini(struct radeon_device *rdev); +void radeon_fence_driver_force_completion(struct radeon_device *rdev); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); -void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); int radeon_fence_wait_any(struct radeon_device *rdev, struct radeon_fence **fences, bool intr); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 596bcbe80ed0..9056fafb00ea 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1140,9 +1140,9 @@ static struct radeon_asic rv770_asic = { .copy = { .blit = &r600_copy_blit, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, - .dma = &r600_copy_dma, + .dma = &rv770_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, + .copy = &rv770_copy_dma, .copy_ring_index = R600_RING_TYPE_DMA_INDEX, }, .surface = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 5f4882cc2152..15d70e613076 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -403,6 +403,10 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); void r700_cp_stop(struct radeon_device *rdev); void r700_cp_fini(struct radeon_device *rdev); +int rv770_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence **fence); /* * evergreen diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 4af89126e223..33a56a09ff10 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1548,6 +1548,9 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) of_machine_is_compatible("PowerBook6,7")) { /* ibook */ rdev->mode_info.connector_table = CT_IBOOK; + } else if (of_machine_is_compatible("PowerMac3,5")) { + /* PowerMac G4 Silver radeon 7500 */ + rdev->mode_info.connector_table = CT_MAC_G4_SILVER; } else if (of_machine_is_compatible("PowerMac4,4")) { /* emac */ rdev->mode_info.connector_table = CT_EMAC; @@ -2212,6 +2215,54 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_SVIDEO, &hpd); break; + case CT_MAC_G4_SILVER: + DRM_INFO("Connector Table: %d (mac g4 silver)\n", + rdev->mode_info.connector_table); + /* DVI-I - tv dac, int tmds */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); + hpd.hpd = RADEON_HPD_1; /* ??? */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c, + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, + &hpd); + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); + hpd.hpd = RADEON_HPD_NONE; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c, + CONNECTOR_OBJECT_ID_VGA, + &hpd); + /* TV - TV DAC */ + ddc_i2c.valid = false; + hpd.hpd = RADEON_HPD_NONE; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c, + CONNECTOR_OBJECT_ID_SVIDEO, + &hpd); + break; default: DRM_INFO("Connector table: %d (invalid)\n", rdev->mode_info.connector_table); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 47bf162ab9c6..2399f25ec037 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -741,7 +741,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -947,7 +947,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) return connector->status; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -1401,7 +1401,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (encoder) { /* setup ddc on the bridge */ radeon_atom_ext_encoder_setup_ddc(encoder); - if (radeon_ddc_probe(radeon_connector)) /* try DDC */ + /* bridge chips are always aux */ + if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */ ret = connector_status_connected; else if (radeon_connector->dac_load_detect) { /* try load detection */ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -1419,7 +1420,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector)) + /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */ + if (radeon_ddc_probe(radeon_connector, false)) ret = connector_status_connected; } } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 49b06590001e..edfc54e41842 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -897,6 +897,25 @@ static void radeon_check_arguments(struct radeon_device *rdev) } /** + * radeon_switcheroo_quirk_long_wakeup - return true if longer d3 delay is + * needed for waking up. + * + * @pdev: pci dev pointer + */ +static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) +{ + + /* 6600m in a macbook pro */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + pdev->subsystem_device == 0x00e2) { + printk(KERN_INFO "radeon: quirking longer d3 wakeup delay\n"); + return true; + } + + return false; +} + +/** * radeon_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer @@ -910,10 +929,19 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero struct drm_device *dev = pci_get_drvdata(pdev); pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { + unsigned d3_delay = dev->pdev->d3_delay; + printk(KERN_INFO "radeon: switched on\n"); /* don't suspend or resume card normally */ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + + if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev)) + dev->pdev->d3_delay = 20; + radeon_resume_kms(dev); + + dev->pdev->d3_delay = d3_delay; + dev->switch_power_state = DRM_SWITCH_POWER_ON; drm_kms_helper_poll_enable(dev); } else { @@ -1164,6 +1192,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) struct drm_crtc *crtc; struct drm_connector *connector; int i, r; + bool force_completion = false; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1206,8 +1235,16 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) mutex_lock(&rdev->ring_lock); /* wait for gpu to finish processing current batch */ - for (i = 0; i < RADEON_NUM_RINGS; i++) - radeon_fence_wait_empty_locked(rdev, i); + for (i = 0; i < RADEON_NUM_RINGS; i++) { + r = radeon_fence_wait_empty_locked(rdev, i); + if (r) { + /* delay GPU reset to resume */ + force_completion = true; + } + } + if (force_completion) { + radeon_fence_driver_force_completion(rdev); + } mutex_unlock(&rdev->ring_lock); radeon_save_bios_scratch_regs(rdev); @@ -1338,7 +1375,6 @@ retry: } radeon_restore_bios_scratch_regs(rdev); - drm_helper_resume_force_mode(rdev->ddev); if (!r) { for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -1358,11 +1394,14 @@ retry: } } } else { + radeon_fence_driver_force_completion(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { kfree(ring_data[i]); } } + drm_helper_resume_force_mode(rdev->ddev); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); if (r) { /* bad news, how to tell it to userspace ? */ diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 310c0e5254ba..1da2386d7cf7 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -699,10 +699,15 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); - if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || - (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != - ENCODER_OBJECT_ID_NONE)) { + if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != + ENCODER_OBJECT_ID_NONE) { + struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + + if (dig->dp_i2c_bus) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &dig->dp_i2c_bus->adapter); + } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 9b1a727d3c9e..dff6cf77f953 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -68,9 +68,10 @@ * 2.25.0 - eg+: new info request for num SE and num SH * 2.26.0 - r600-eg: fix htile size computation * 2.27.0 - r600-SI: Add CS ioctl support for async DMA + * 2.28.0 - r600-eg: Add MEM_WRITE packet support */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 27 +#define KMS_DRIVER_MINOR 28 #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); @@ -305,8 +306,8 @@ static int radeon_kick_out_firmware_fb(struct pci_dev *pdev) return 0; } -static int __devinit -radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int radeon_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { int ret; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 410a975a8eec..34356252567a 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -609,26 +609,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) * Returns 0 if the fences have passed, error for all other cases. * Caller must hold ring lock. */ -void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) { uint64_t seq = rdev->fence_drv[ring].sync_seq[ring]; + int r; - while(1) { - int r; - r = radeon_fence_wait_seq(rdev, seq, ring, false, false); + r = radeon_fence_wait_seq(rdev, seq, ring, false, false); + if (r) { if (r == -EDEADLK) { - mutex_unlock(&rdev->ring_lock); - r = radeon_gpu_reset(rdev); - mutex_lock(&rdev->ring_lock); - if (!r) - continue; - } - if (r) { - dev_err(rdev->dev, "error waiting for ring to become" - " idle (%d)\n", r); + return -EDEADLK; } - return; + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", + ring, r); } + return 0; } /** @@ -854,13 +848,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev) */ void radeon_fence_driver_fini(struct radeon_device *rdev) { - int ring; + int ring, r; mutex_lock(&rdev->ring_lock); for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { if (!rdev->fence_drv[ring].initialized) continue; - radeon_fence_wait_empty_locked(rdev, ring); + r = radeon_fence_wait_empty_locked(rdev, ring); + if (r) { + /* no need to trigger GPU reset as we are unloading */ + radeon_fence_driver_force_completion(rdev); + } wake_up_all(&rdev->fence_queue); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); rdev->fence_drv[ring].initialized = false; @@ -868,6 +866,25 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) mutex_unlock(&rdev->ring_lock); } +/** + * radeon_fence_driver_force_completion - force all fence waiter to complete + * + * @rdev: radeon device pointer + * + * In case of GPU reset failure make sure no process keep waiting on fence + * that will never complete. + */ +void radeon_fence_driver_force_completion(struct radeon_device *rdev) +{ + int ring; + + for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { + if (!rdev->fence_drv[ring].initialized) + continue; + radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); + } +} + /* * Fence debugfs diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index c5bddd630eb9..fc60b74ee304 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -39,7 +39,7 @@ extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap); * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux) { u8 out = 0x0; u8 buf[8]; @@ -63,7 +63,13 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector) if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); - ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + if (use_aux) { + struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2); + } else { + ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + } + if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index d818b503b42f..4003f5a68c09 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -209,7 +209,8 @@ enum radeon_connector_table { CT_RN50_POWER, CT_MAC_X800, CT_MAC_G5_9600, - CT_SAM440EP + CT_SAM440EP, + CT_MAC_G4_SILVER }; enum radeon_dvo_chip { @@ -558,7 +559,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index aa14dbb7e4fb..0bfa656aa87d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -234,7 +234,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) static void radeon_pm_set_clocks(struct radeon_device *rdev) { - int i; + int i, r; /* no need to take locks, etc. if nothing's going to change */ if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && @@ -248,8 +248,17 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) /* 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); + if (!ring->ready) { + continue; + } + r = radeon_fence_wait_empty_locked(rdev, i); + if (r) { + /* needs a GPU reset dont reset here */ + mutex_unlock(&rdev->ring_lock); + up_write(&rdev->pm.mclk_lock); + mutex_unlock(&rdev->ddev->struct_mutex); + return; + } } radeon_unmap_vram_bos(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c index e09521858f64..26c23bb651c6 100644 --- a/drivers/gpu/drm/radeon/radeon_prime.c +++ b/drivers/gpu/drm/radeon/radeon_prime.c @@ -194,6 +194,7 @@ struct drm_gem_object *radeon_gem_prime_import(struct drm_device *dev, bo = dma_buf->priv; if (bo->gem_base.dev == dev) { drm_gem_object_reference(&bo->gem_base); + dma_buf_put(dma_buf); return &bo->gem_base; } } diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index ebd69562ef6c..141f2b6a9cf2 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -770,22 +770,28 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) int ridx = *(int*)node->info_ent->data; struct radeon_ring *ring = &rdev->ring[ridx]; unsigned count, i, j; + u32 tmp; radeon_ring_free_size(rdev, ring); count = (ring->ring_size / 4) - ring->ring_free_dw; - seq_printf(m, "wptr(0x%04x): 0x%08x\n", ring->wptr_reg, RREG32(ring->wptr_reg)); - seq_printf(m, "rptr(0x%04x): 0x%08x\n", ring->rptr_reg, RREG32(ring->rptr_reg)); + tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift; + seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp); + tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift; + seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp); if (ring->rptr_save_reg) { seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg, RREG32(ring->rptr_save_reg)); } - seq_printf(m, "driver's copy of the wptr: 0x%08x\n", ring->wptr); - seq_printf(m, "driver's copy of the rptr: 0x%08x\n", ring->rptr); + seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); + seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr); seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u dwords in ring\n", count); - i = ring->rptr; - for (j = 0; j <= count; j++) { - seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]); + /* print 8 dw before current rptr as often it's the last executed + * packet that is the root issue + */ + i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; + for (j = 0; j <= (count + 32); j++) { + seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]); i = (i + 1) & ring->ptr_mask; } return 0; @@ -794,11 +800,15 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) static int radeon_ring_type_gfx_index = RADEON_RING_TYPE_GFX_INDEX; static int cayman_ring_type_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX; static int cayman_ring_type_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; +static int radeon_ring_type_dma1_index = R600_RING_TYPE_DMA_INDEX; +static int radeon_ring_type_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; static struct drm_info_list radeon_debugfs_ring_info_list[] = { {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_ring_type_gfx_index}, {"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp1_index}, {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index}, + {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma1_index}, + {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma2_index}, }; static int radeon_debugfs_sa_info(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 87c979c4f721..1b2444f4d8f4 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -887,6 +887,80 @@ static int rv770_mc_init(struct radeon_device *rdev) return 0; } +/** + * rv770_copy_dma - copy pages using the DMA engine + * + * @rdev: radeon_device pointer + * @src_offset: src GPU address + * @dst_offset: dst GPU address + * @num_gpu_pages: number of GPU pages to xfer + * @fence: radeon fence object + * + * Copy GPU paging using the DMA engine (r7xx). + * Used by the radeon ttm implementation to move pages if + * registered as the asic copy callback. + */ +int rv770_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence **fence) +{ + struct radeon_semaphore *sem = NULL; + int ring_index = rdev->asic->copy.dma_ring_index; + struct radeon_ring *ring = &rdev->ring[ring_index]; + u32 size_in_dw, cur_size_in_dw; + int i, num_loops; + int r = 0; + + r = radeon_semaphore_create(rdev, &sem); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + return r; + } + + size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; + num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF); + r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + radeon_semaphore_free(rdev, &sem, NULL); + return r; + } + + if (radeon_fence_need_sync(*fence, ring->idx)) { + radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, + ring->idx); + radeon_fence_note_sync(*fence, ring->idx); + } else { + radeon_semaphore_free(rdev, &sem, NULL); + } + + for (i = 0; i < num_loops; i++) { + cur_size_in_dw = size_in_dw; + if (cur_size_in_dw > 0xFFFF) + cur_size_in_dw = 0xFFFF; + size_in_dw -= cur_size_in_dw; + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw)); + radeon_ring_write(ring, dst_offset & 0xfffffffc); + radeon_ring_write(ring, src_offset & 0xfffffffc); + radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff); + radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff); + src_offset += cur_size_in_dw * 4; + dst_offset += cur_size_in_dw * 4; + } + + r = radeon_fence_emit(rdev, fence, ring->idx); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } + + radeon_ring_unlock_commit(rdev, ring); + radeon_semaphore_free(rdev, &sem, *fence); + + return r; +} + static int rv770_startup(struct radeon_device *rdev) { struct radeon_ring *ring; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index ef683653f0b7..3240a3d64f30 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2126,15 +2126,13 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return radeon_ring_test_lockup(rdev, ring); } -static int si_gpu_soft_reset(struct radeon_device *rdev) +static void si_gpu_soft_reset_gfx(struct radeon_device *rdev) { - struct evergreen_mc_save save; u32 grbm_reset = 0; if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) - return 0; + return; - dev_info(rdev->dev, "GPU softreset \n"); dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", RREG32(GRBM_STATUS)); dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n", @@ -2145,10 +2143,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev) RREG32(GRBM_STATUS_SE1)); dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", RREG32(SRBM_STATUS)); - evergreen_mc_stop(rdev, &save); - if (radeon_mc_wait_for_idle(rdev)) { - dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); - } + /* Disable CP parsing/prefetching */ WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); @@ -2173,8 +2168,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev) udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); - /* Wait a little for things to settle down */ - udelay(50); + dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", RREG32(GRBM_STATUS)); dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n", @@ -2185,13 +2179,75 @@ static int si_gpu_soft_reset(struct radeon_device *rdev) RREG32(GRBM_STATUS_SE1)); dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", RREG32(SRBM_STATUS)); +} + +static void si_gpu_soft_reset_dma(struct radeon_device *rdev) +{ + u32 tmp; + + if (RREG32(DMA_STATUS_REG) & DMA_IDLE) + return; + + dev_info(rdev->dev, " DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); + + /* dma0 */ + tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp); + + /* dma1 */ + tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp); + + /* Reset dma */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); + RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + + dev_info(rdev->dev, " DMA_STATUS_REG = 0x%08X\n", + RREG32(DMA_STATUS_REG)); +} + +static int si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) +{ + struct evergreen_mc_save save; + + if (reset_mask == 0) + return 0; + + dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask); + + dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", + RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", + RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + + evergreen_mc_stop(rdev, &save); + if (radeon_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE)) + si_gpu_soft_reset_gfx(rdev); + + if (reset_mask & RADEON_RESET_DMA) + si_gpu_soft_reset_dma(rdev); + + /* Wait a little for things to settle down */ + udelay(50); + evergreen_mc_resume(rdev, &save); return 0; } int si_asic_reset(struct radeon_device *rdev) { - return si_gpu_soft_reset(rdev); + return si_gpu_soft_reset(rdev, (RADEON_RESET_GFX | + RADEON_RESET_COMPUTE | + RADEON_RESET_DMA)); } /* MC */ diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 62b46215d423..c056aae814f0 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -62,6 +62,22 @@ #define SRBM_STATUS 0xE50 +#define SRBM_SOFT_RESET 0x0E60 +#define SOFT_RESET_BIF (1 << 1) +#define SOFT_RESET_DC (1 << 5) +#define SOFT_RESET_DMA1 (1 << 6) +#define SOFT_RESET_GRBM (1 << 8) +#define SOFT_RESET_HDP (1 << 9) +#define SOFT_RESET_IH (1 << 10) +#define SOFT_RESET_MC (1 << 11) +#define SOFT_RESET_ROM (1 << 14) +#define SOFT_RESET_SEM (1 << 15) +#define SOFT_RESET_VMC (1 << 17) +#define SOFT_RESET_DMA (1 << 20) +#define SOFT_RESET_TST (1 << 21) +#define SOFT_RESET_REGBB (1 << 22) +#define SOFT_RESET_ORB (1 << 23) + #define CC_SYS_RB_BACKEND_DISABLE 0xe80 #define GC_USER_SYS_RB_BACKEND_DISABLE 0xe84 @@ -1013,6 +1029,8 @@ # define DATA_SWAP_ENABLE (1 << 3) # define FENCE_SWAP_ENABLE (1 << 4) # define CTXEMPTY_INT_ENABLE (1 << 28) +#define DMA_STATUS_REG 0xd034 +# define DMA_IDLE (1 << 0) #define DMA_TILING_CONFIG 0xd0b8 #define DMA_PACKET(cmd, b, t, s, n) ((((cmd) & 0xF) << 28) | \ |