diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2012-12-03 19:03:23 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-12-12 17:16:49 -0500 |
commit | 6830f585724e1db5609dab0b059ea2e338bd9cc2 (patch) | |
tree | 051ee0e6d81b5f66db783a1d650d11ef35fdd474 /drivers/gpu/drm/radeon/r600_cs.c | |
parent | b997a8ba26377895506a26a3f2b8f1e7abc4ed22 (diff) | |
download | linux-6830f585724e1db5609dab0b059ea2e338bd9cc2.tar.bz2 |
drm/radeon: add support for CP DMA packet to r6xx/r7xx CS checker
Currently only memory to memory transfers are allowed.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_cs.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600_cs.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 211c40252fe0..5d6e7f959e75 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -1949,6 +1949,78 @@ static int r600_packet3_check(struct radeon_cs_parser *p, ib[idx+2] = upper_32_bits(offset) & 0xff; } break; + case PACKET3_CP_DMA: + { + u32 command, size; + u64 offset, tmp; + if (pkt->count != 4) { + DRM_ERROR("bad CP DMA\n"); + return -EINVAL; + } + command = radeon_get_ib_value(p, idx+4); + size = command & 0x1fffff; + if (command & PACKET3_CP_DMA_CMD_SAS) { + /* src address space is register */ + DRM_ERROR("CP DMA SAS not supported\n"); + return -EINVAL; + } else { + if (command & PACKET3_CP_DMA_CMD_SAIC) { + DRM_ERROR("CP DMA SAIC only supported for registers\n"); + return -EINVAL; + } + /* src address space is memory */ + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad CP DMA SRC\n"); + return -EINVAL; + } + + tmp = radeon_get_ib_value(p, idx) + + ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32); + + offset = reloc->lobj.gpu_offset + tmp; + + if ((tmp + size) > radeon_bo_size(reloc->robj)) { + dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n", + tmp + size, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + + ib[idx] = offset; + ib[idx+1] = (ib[idx+1] & 0xffffff00) | (upper_32_bits(offset) & 0xff); + } + if (command & PACKET3_CP_DMA_CMD_DAS) { + /* dst address space is register */ + DRM_ERROR("CP DMA DAS not supported\n"); + return -EINVAL; + } else { + /* dst address space is memory */ + if (command & PACKET3_CP_DMA_CMD_DAIC) { + DRM_ERROR("CP DMA DAIC only supported for registers\n"); + return -EINVAL; + } + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad CP DMA DST\n"); + return -EINVAL; + } + + tmp = radeon_get_ib_value(p, idx+2) + + ((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32); + + offset = reloc->lobj.gpu_offset + tmp; + + if ((tmp + size) > radeon_bo_size(reloc->robj)) { + dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n", + tmp + size, radeon_bo_size(reloc->robj)); + return -EINVAL; + } + + ib[idx+2] = offset; + ib[idx+3] = upper_32_bits(offset) & 0xff; + } + break; + } case PACKET3_SURFACE_SYNC: if (pkt->count != 3) { DRM_ERROR("bad SURFACE_SYNC\n"); |