summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/radeon_gem.c38
-rw-r--r--shared-core/radeon_cs.c90
-rw-r--r--shared-core/radeon_drv.h8
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;