diff options
-rw-r--r-- | linux-core/radeon_gem.c | 38 | ||||
-rw-r--r-- | shared-core/radeon_cs.c | 90 | ||||
-rw-r--r-- | shared-core/radeon_drv.h | 8 |
3 files changed, 124 insertions, 12 deletions
diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 021bb9f9..859c1656 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -805,10 +805,45 @@ static int radeon_gem_ib_destroy(struct drm_device *dev) return 0; } +static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *reloc, uint32_t *offset) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + /* relocate the handle */ + int domains = reloc[2]; + struct drm_gem_object *obj; + int flags = 0; + int ret; + struct drm_radeon_gem_object *obj_priv; + + obj = drm_gem_object_lookup(dev, file_priv, reloc[1]); + if (!obj) + return false; + + obj_priv = obj->driver_private; + if (domains == RADEON_GEM_DOMAIN_VRAM) { + flags = DRM_BO_FLAG_MEM_VRAM; + } else { + flags = DRM_BO_FLAG_MEM_TT; + } + + ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM, 0, 0, NULL); + if (ret) + return ret; + + if (flags == DRM_BO_FLAG_MEM_VRAM) + *offset = obj_priv->bo->offset + dev_priv->fb_location; + else + *offset = obj_priv->bo->offset + dev_priv->gart_vm_start; + + /* BAD BAD BAD - LINKED LIST THE OBJS and UNREF ONCE IB is SUBMITTED */ + drm_gem_object_unreference(obj); + return 0; +} + /* allocate 1MB of 64k IBs the the kernel can keep mapped */ static int radeon_gem_ib_init(struct drm_device *dev) { - drm_radeon_private_t *dev_priv = dev->dev_private; int i; int ret; @@ -843,6 +878,7 @@ static int radeon_gem_ib_init(struct drm_device *dev) dev_priv->cs.ib_free = radeon_gem_ib_free; radeon_cs_init(dev); + dev_priv->cs.relocate = radeon_gem_relocate; return 0; free_all: diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 5cfe85be..f01334bc 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -74,7 +74,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) } /* now parse command stream */ - r = radeon->cs.parse(dev, ib, packets, cs->dwords); + r = radeon->cs.parse(dev, fpriv, ib, packets, cs->dwords); if (r) { goto out; } @@ -88,6 +88,69 @@ out: return r; } +/* for non-mm */ +static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset) +{ + *offset = reloc[1]; + return 0; +} +#define RELOC_SIZE 2 +#define RADEON_2D_OFFSET_MASK 0x3fffff + +static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t hdr = packets[offset_dw]; + uint32_t reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + uint32_t val = packets[offset_dw + 1]; + uint32_t packet3_hdr = packets[offset_dw+2]; + uint32_t tmp, offset; + int ret; + + /* 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\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16)); + return -EINVAL; + } + + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + /* pass in the start of the reloc */ + ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + if (ret) + return ret; + tmp = (val & RADEON_2D_OFFSET_MASK) << 10; + val &= ~RADEON_2D_OFFSET_MASK; + offset += tmp; + offset >>= 10; + val |= offset; + break; + case R300_RB3D_COLOROFFSET0: + case R300_RB3D_DEPTHOFFSET: + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + offset = packets[offset_dw + 3]; + + ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + if (ret) + return ret; + + offset &= 0xffffffe0; + val += offset; + break; + default: + break; + } + + + DRM_ERROR("New offset %x %x %x\n", packets[offset_dw+1], val, offset); + packets[offset_dw + 1] = val; + + return 0; +} static __inline__ int radeon_cs_check_offset(struct drm_device *dev, uint32_t reg, uint32_t val) { @@ -113,11 +176,11 @@ static __inline__ int radeon_cs_check_offset(struct drm_device *dev, return 0; } -int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, - uint32_t offset_dw) +int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) { drm_radeon_private_t *dev_priv = dev->dev_private; - int hdr = packets[offset_dw]; + uint32_t hdr = packets[offset_dw]; int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; int need_reloc = 0; int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; @@ -139,9 +202,16 @@ int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, case 1: flags = r300_get_reg_flags(reg); if (flags == MARK_CHECK_OFFSET) { - radeon_cs_check_offset(dev, reg, packets[offset_dw+count_dw]); - + if (num_dw > 2) { + DRM_ERROR("Cannot relocate inside type stream of reg0 packets\n"); + return -EINVAL; + } + + ret = radeon_cs_relocate_offset(dev, file_priv, packets, offset_dw); + if (ret) + return ret; DRM_DEBUG("need to relocate %x %d\n", reg, flags); + /* okay it should be followed by a NOP */ } else if (flags == MARK_CHECK_SCISSOR) { DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); } else { @@ -156,8 +226,8 @@ int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, return 0; } -int radeon_cs_parse(struct drm_device *dev, void *ib, - uint32_t *packets, uint32_t dwords) +int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, + void *ib, uint32_t *packets, uint32_t dwords) { drm_radeon_private_t *dev_priv = dev->dev_private; volatile int rb; @@ -173,7 +243,7 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, switch (hdr & RADEON_CP_PACKET_MASK) { case RADEON_CP_PACKET0: - ret = radeon_cs_packet0(dev, packets, count_dw); + ret = radeon_cs_packet0(dev, file_priv, packets, count_dw); break; case RADEON_CP_PACKET1: case RADEON_CP_PACKET2: @@ -191,6 +261,7 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, offset = packets[count_dw+2] & ((1 << 22) - 1); offset <<= 10; DRM_ERROR("Offset check for Packet 3 %x %x\n", reg, offset); + /* okay it should be followed by a NOP */ break; } case RADEON_CNTL_BITBLT_MULTI: @@ -302,5 +373,6 @@ int radeon_cs_init(struct drm_device *dev) dev_priv->cs.parse = radeon_cs_parse; /* ib get depends on memory manager or not so memory manager */ + dev_priv->cs.relocate = radeon_nomm_relocate; return 0; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 232102d5..f79eade5 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -293,8 +293,8 @@ struct drm_radeon_cs_priv { uint32_t id_last_wcnt; uint32_t id_last_scnt; - int (*parse)(struct drm_device *dev, void *ib, - uint32_t *packets, uint32_t dwords); + int (*parse)(struct drm_device *dev, struct drm_file *file_priv, + void *ib, uint32_t *packets, uint32_t dwords); void (*id_emit)(struct drm_device *dev, uint32_t *id); uint32_t (*id_last_get)(struct drm_device *dev); /* this ib handling callback are for hidding memory manager drm @@ -303,6 +303,9 @@ struct drm_radeon_cs_priv { int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords); uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); void (*ib_free)(struct drm_device *dev, void *ib, uint32_t dwords); + /* do a relocation either MM or non-MM */ + bool (*relocate)(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *reloc, uint32_t *offset); }; typedef struct drm_radeon_private { @@ -391,6 +394,7 @@ typedef struct drm_radeon_private { int num_gb_pipes; + int mm_disabled; /* on OSes with no MM this will be 1*/ struct radeon_mm_info mm; drm_local_map_t *mmio; |