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