radeon_cs: add relocate hook for mm and non-mm relocations

main
Dave Airlie 2008-07-29 16:51:47 +10:00
parent 42e373e903
commit 4234f82acc
3 changed files with 124 additions and 12 deletions

View File

@ -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:

View File

@ -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;
}

View File

@ -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;