diff options
-rw-r--r-- | linux-core/radeon_gem.c | 47 | ||||
-rw-r--r-- | shared-core/radeon_cs.c | 52 |
2 files changed, 74 insertions, 25 deletions
diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 7899490f..851a95d3 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1242,21 +1242,58 @@ static int radeon_gem_ib_destroy(struct drm_device *dev) return 0; } +static int radeon_gem_find_reloc(struct drm_radeon_cs_parser *parser, + uint32_t offset, uint32_t *handle, + uint32_t *read_domains, uint32_t *write_domain) +{ + struct drm_device *dev = parser->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index]; + + if (!reloc_chunk->kdata) + return -EINVAL; + + if (offset > reloc_chunk->length_dw){ + DRM_ERROR("Offset larger than chunk %d %d\n", offset, reloc_chunk->length_dw); + return -EINVAL; + } + + *handle = reloc_chunk->kdata[offset]; + *read_domains = reloc_chunk->kdata[offset + 1]; + *write_domain = reloc_chunk->kdata[offset + 2]; + return 0; +} + static int radeon_gem_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint32_t *offset) { struct drm_device *dev = parser->dev; drm_radeon_private_t *dev_priv = dev->dev_private; /* relocate the handle */ - uint32_t read_domains = reloc[2]; - uint32_t write_domain = reloc[3]; + uint32_t read_domains, write_domain; struct drm_gem_object *obj; int flags = 0; + int ret; struct drm_radeon_gem_object *obj_priv; - obj = drm_gem_object_lookup(dev, parser->file_priv, reloc[1]); - if (!obj) - return -EINVAL; + if (parser->reloc_index == -1) { + obj = drm_gem_object_lookup(dev, parser->file_priv, reloc[1]); + if (!obj) + return -EINVAL; + read_domains = reloc[2]; + write_domain = reloc[3]; + } else { + uint32_t handle; + + /* have to lookup handle in other chunk */ + ret = radeon_gem_find_reloc(parser, reloc[1], &handle, &read_domains, &write_domain); + if (ret < 0) + return ret; + + obj = drm_gem_object_lookup(dev, parser->file_priv, handle); + if (!obj) + return -EINVAL; + } obj_priv = obj->driver_private; radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 14f3dcd9..31cd53db 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -68,6 +68,8 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) goto out; } + parser.dev = dev; + parser.file_priv = fpriv; parser.reloc_index = -1; parser.ib_index = -1; parser.num_chunks = cs->num_chunks; @@ -103,24 +105,29 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data; parser.chunks[i].kdata = NULL; + size = parser.chunks[i].length_dw * sizeof(uint32_t); switch(parser.chunks[i].chunk_id) { - case RADEON_CHUNK_ID_RELOCS: case RADEON_CHUNK_ID_IB: - case RADEON_CHUNK_ID_OLD: { - /* copy from user the relocs chunk */ - int size = parser.chunks[i].length_dw * sizeof(uint32_t); - parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); - if (!parser.chunks[i].kdata) { - r = -ENOMEM; + case RADEON_CHUNK_ID_OLD: + if (size == 0) { + r = -EINVAL; goto out; } - - if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { - r = -EFAULT; - goto out; - } - } + case RADEON_CHUNK_ID_RELOCS: + if (size) { + parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); + if (!parser.chunks[i].kdata) { + r = -ENOMEM; + goto out; + } + + if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { + r = -EFAULT; + goto out; + } + } else + parser.chunks[i].kdata = NULL; break; default: break; @@ -266,6 +273,7 @@ static int radeon_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *r return 0; } #define RELOC_SIZE 2 +#define RELOC_SIZE_NEW 0 #define RADEON_2D_OFFSET_MASK 0x3fffff static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) @@ -288,9 +296,17 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa /* this is too strict we may want to expand the length in the future and have old kernels ignore it. */ - if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { - DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); - return -EINVAL; + if (parser->reloc_index == -1) { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); + return -EINVAL; + } + } else { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16), reg); + return -EINVAL; + + } } switch(reg) { @@ -371,9 +387,7 @@ static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) { - drm_radeon_private_t *dev_priv = parser->dev->dev_private; uint32_t hdr, num_dw, reg; - int need_reloc = 0; int count_dw = 1; int ret; @@ -422,8 +436,6 @@ int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) int radeon_cs_parse(struct drm_radeon_cs_parser *parser) { - struct drm_device *dev = parser->dev; - drm_radeon_private_t *dev_priv = parser->dev->dev_private; volatile int rb; struct drm_radeon_kernel_chunk *ib_chunk; /* scan the packet for various things */ |