Hello Vladimir,
I've attached a patch which implements the RADOEN_CMD_DMA_DISCARD ioctl from
the radeon/r200 drm. I thought I'd post here before commiting to cvs in case I've
done something bad.
Without this, eventually r300AllocDmaRegion will get stuck in a loop continually calling
drmDMA (r300_ioctl.c::r300RefillCurrentDmaRegion).
It seems that the drm buffer management code depends on having a scratch register
containing the "age" of a buffer. I'm not sure of the details, I just know that it stops
the infinite drmDMA loop.
Is this the correct way of fixing this? Or have I completely missed something?
Regards, Ben Skeggs.
diff -Nur drm.old/shared-core/r300_cmdbuf.c drm/shared-core/r300_cmdbuf.c
--- drm.old/shared-core/r300_cmdbuf.c 2005-01-08 13:46:34.000000000 +1100
+++ drm/shared-core/r300_cmdbuf.c 2005-02-06 20:20:06.910617312 +1100
@@ -354,16 +354,37 @@
return 0;
}
+static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+ RING_LOCALS;
+
+ buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
+
+ /* Emit the vertex buffer age */
+ BEGIN_RING(2);
+ RADEON_DISPATCH_AGE(buf_priv->age);
+ ADVANCE_RING();
+
+ buf->pending = 1;
+ buf->used = 0;
+}
+
+
/**
* Parses and validates a user-supplied command buffer and emits appropriate
* commands on the DMA ring buffer.
* Called by the ioctl handler function radeon_cp_cmdbuf.
*/
int r300_do_cp_cmdbuf(drm_device_t* dev,
+ DRMFILE filp,
drm_file_t* filp_priv,
drm_radeon_cmd_buffer_t* cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf = NULL;
int ret;
DRM_DEBUG("\n");
@@ -375,6 +396,7 @@
}
while(cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) {
+ int idx;
drm_r300_cmd_header_t header;
if (DRM_GET_USER_UNCHECKED(header.u, (int __user*)cmdbuf->buf))
{
@@ -431,6 +453,26 @@
ADVANCE_RING();
}
return 0;
+
+ case R300_CMD_DMA_DISCARD:
+ DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
+ idx = header.dma.buf_idx;
+ if (idx < 0 || idx >= dma->buf_count) {
+ DRM_ERROR("buffer index %d (of %d max)\n",
+ idx, dma->buf_count - 1);
+ return DRM_ERR(EINVAL);
+ }
+
+ buf = dma->buflist[idx];
+ if (buf->filp != filp || buf->pending) {
+ DRM_ERROR("bad buffer %p %p %d\n",
+ buf->filp, filp, buf->pending);
+ return DRM_ERR(EINVAL);
+ }
+
+ r300_discard_buffer(dev, buf);
+ break;
+
default:
DRM_ERROR("bad cmd_type %i at %p\n",
header.header.cmd_type,
diff -Nur drm.old/shared-core/radeon_drm.h drm/shared-core/radeon_drm.h
--- drm.old/shared-core/radeon_drm.h 2005-01-02 05:32:52.000000000 +1100
+++ drm/shared-core/radeon_drm.h 2005-02-06 20:20:06.910617312 +1100
@@ -199,6 +199,7 @@
#define R300_CMD_PACKET3 3 /* emit a packet3 */
#define R300_CMD_END3D 4 /* emit sequence ending 3d rendering
*/
#define R300_CMD_CP_DELAY 5
+#define R300_CMD_DMA_DISCARD 6
typedef union {
unsigned int u;
@@ -218,6 +219,9 @@
unsigned char cmd_type, packet;
unsigned short count; /* amount of packet2 to emit */
} delay;
+ struct {
+ unsigned char cmd_type, buf_idx, pad0, pad1;
+ } dma;
} drm_r300_cmd_header_t;
#define RADEON_FRONT 0x1
diff -Nur drm.old/shared-core/radeon_drv.h drm/shared-core/radeon_drv.h
--- drm.old/shared-core/radeon_drv.h 2004-12-28 07:44:39.000000000 +1100
+++ drm/shared-core/radeon_drv.h 2005-02-06 20:20:06.910617312 +1100
@@ -310,6 +310,7 @@
/* r300_cmdbuf.c */
extern int r300_do_cp_cmdbuf( drm_device_t* dev,
+ DRMFILE filp,
drm_file_t* filp_priv,
drm_radeon_cmd_buffer_t* cmdbuf );
diff -Nur drm.old/shared-core/radeon_state.c drm/shared-core/radeon_state.c
--- drm.old/shared-core/radeon_state.c 2005-01-31 13:33:24.000000000 +1100
+++ drm/shared-core/radeon_state.c 2005-02-06 20:20:06.909617464 +1100
@@ -2469,7 +2469,7 @@
return DRM_ERR(EFAULT);
if ( IS_FAMILY_R300(dev_priv) )
- return r300_do_cp_cmdbuf(dev, filp_priv, &cmdbuf);
+ return r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
else
return radeon_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
}
