From: <ma...@ke...> - 2006-10-14 22:07:34
|
bsd-core/drmP.h | 6 bsd-core/drm_drawable.c | 52 ------- bsd-core/drm_drv.c | 3 libdrm/xf86drm.c | 16 ++ libdrm/xf86drm.h | 8 - linux-core/Makefile | 4 linux-core/drmP.h | 39 +++++ linux-core/drm_bufs.c | 10 - linux-core/drm_core.h | 8 - linux-core/drm_drawable.c | 57 ------- linux-core/drm_drv.c | 14 + linux-core/drm_irq.c | 155 +++++++++++++++++---- linux-core/drm_lock.c | 11 + linux-core/drm_stub.c | 4 linux-core/drm_vm.c | 16 ++ linux-core/i915_drv.c | 4 linux-core/radeon_drv.c | 2 shared-core/drm.h | 33 ++++ shared-core/drm_drawable.c | 330 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/drm_pciids.txt | 177 ++++++++++++------------ shared-core/i915_dma.c | 10 - shared-core/i915_drm.h | 19 ++ shared-core/i915_drv.h | 22 ++- shared-core/i915_irq.c | 265 ++++++++++++++++++++++++++++++++++-- shared-core/mach64_dma.c | 232 ++++++++++++++++--------------- shared-core/mach64_drm.h | 2 shared-core/mach64_drv.h | 7 shared-core/mach64_state.c | 209 +++++++++++++--------------- shared-core/r300_cmdbuf.c | 33 ++++ shared-core/radeon_cp.c | 46 +++--- shared-core/radeon_drv.h | 23 +-- shared-core/radeon_state.c | 134 ++++++++++++++++-- 32 files changed, 1428 insertions(+), 523 deletions(-) New commits: diff-tree 93fee5cf222ad6d97e0dcb85e13a8d8b84dba81f (from parents) Merge: 2c5b91aecf3d21684ffca758c034cd9a8ed2155d a9f57a2b9c5897cbf568bf75342204b780566de0 Author: Stephane Marchesin <mar...@ic...> Date: Sun Oct 15 00:12:13 2006 +0200 Merge branch 'master' of git://anongit.freedesktop.org/git/mesa/drm into nouveau-1 diff-tree a9f57a2b9c5897cbf568bf75342204b780566de0 (from c9e3aa961eb90265ec024ff57013786e4d47d0e7) Author: Roland Scheidegger <rsc...@hi...> Date: Tue Oct 10 02:24:19 2006 +0200 only allow specific type-3 packets to pass the verifier instead of all for r100/r200 as others might be unsafe (r300 already does this), and add checking for these we need but aren't safe. Check the RADEON_CP_INDX_BUFFER packet on both r200 and r300 as it isn't safe neither. diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index dc86682..c65ffd5 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_m return 0; } +static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) +{ + u32 *cmd = (u32 *) cmdbuf->buf; + int count, ret; + RING_LOCALS; + + count=(cmd[0]>>16) & 0x3fff; + + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + ret = r300_check_offset(dev_priv, cmd[2]); + if (ret) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + + BEGIN_RING(count+2); + OUT_RING(cmd[0]); + OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1); + ADVANCE_RING(); + + cmdbuf->buf += (count+2)*4; + cmdbuf->bufsz -= (count+2)*4; + + return 0; +} + static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { @@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_pack case RADEON_CNTL_BITBLT_MULTI: return r300_emit_bitblt_multi(dev_priv, cmdbuf); + case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ + return r300_emit_indx_buffer(dev_priv, cmdbuf); case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ - case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: /* these packets are safe */ diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index b447801..bf5e3d2 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_f unsigned int *cmdsz) { u32 *cmd = (u32 *) cmdbuf->buf; + u32 offset, narrays; + int count, i, k; *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); @@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_f return DRM_ERR(EINVAL); } - /* Check client state and fix it up if necessary */ - if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ - u32 offset; + switch(cmd[0] & 0xff00) { + /* XXX Are there old drivers needing other packets? */ + case RADEON_3D_DRAW_IMMD: + case RADEON_3D_DRAW_VBUF: + case RADEON_3D_DRAW_INDX: + case RADEON_WAIT_FOR_IDLE: + case RADEON_CP_NOP: + case RADEON_3D_CLEAR_ZMASK: +/* case RADEON_CP_NEXT_CHAR: + case RADEON_CP_PLY_NEXTSCAN: + case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ + /* these packets are safe */ + break; + + case RADEON_CP_3D_DRAW_IMMD_2: + case RADEON_CP_3D_DRAW_VBUF_2: + case RADEON_CP_3D_DRAW_INDX_2: + case RADEON_3D_CLEAR_HIZ: + /* safe but r200 only */ + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_LOAD_VBPNTR: + count = (cmd[0] >> 16) & 0x3fff; + + if (count > 18) { /* 12 arrays max */ + DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", + count); + return DRM_ERR(EINVAL); + } + + /* carefully check packet contents */ + narrays = cmd[1] & ~0xc000; + k = 0; + i = 2; + while ((k < narrays) && (i < (count + 2))) { + i++; /* skip attribute field */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + if (k == narrays) + break; + /* have one more to process, they come in pairs */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + } + /* do the counts match what we expect ? */ + if ((k != narrays) || (i != (count + 2))) { + DRM_ERROR + ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", + k, i, narrays, count + 1); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_RNDR_GEN_INDX_PRIM: + if (dev_priv->microcode_version != UCODE_R100) { + DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) { + DRM_ERROR("Invalid rndr_gen_indx offset\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CP_INDX_BUFFER: + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CNTL_HOSTDATA_BLT: + case RADEON_CNTL_PAINT_MULTI: + case RADEON_CNTL_BITBLT_MULTI: + /* MSB of opcode: next DWORD GUI_CNTL */ if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; @@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_f } cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; } + break; + + default: + DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); + return DRM_ERR(EINVAL); } return 0; diff-tree c9e3aa961eb90265ec024ff57013786e4d47d0e7 (from f3deef730d52c94ce21ada7e4ceb63aa28a8601b) Author: George Sapountzis <gs...@ya...> Date: Mon Oct 2 06:13:38 2006 +0300 Bug 6242: [mach64] Use private DMA buffers, part #4. mach64_state.c: convert the DRM_MACH64_BLIT ioctl to submit a pointer to user-space memory rather than a DMA buffer index, similar to DRM_MACH64_VERTEX. This change allows the DDX to map the DMA buffers read-only and eliminate a security problem where a client can alter the contents of the DMA buffer after submission to the DRM. This change also affects the DRI/DRM interface. Performace-wise, it basically affects PCI mode where I get a ~12% speedup for some Mesa demos I tested. This is mainly due to eliminating an ioctl for allocating the DMA buffer. mach64_dma.c: move the responsibility for allocating memory for the DMA ring in PCI mode to the DDX. This change affects the DDX/DRM interface and unifies a couple of PCI/AGP code paths for ring memory in the DRM. Bump the mach64 DRM version major and date. diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 7cba8ad..3a5fdee 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -815,17 +815,18 @@ static int mach64_do_dma_init(drm_device return DRM_ERR(EINVAL); } + dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); + if (!dev_priv->ring_map) { + DRM_ERROR("can not find ring map!\n"); + dev->dev_private = (void *)dev_priv; + mach64_do_cleanup_dma(dev); + return DRM_ERR(EINVAL); + } + dev_priv->sarea_priv = (drm_mach64_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); if (!dev_priv->is_pci) { - dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); - if (!dev_priv->ring_map) { - DRM_ERROR("can not find ring map!\n"); - dev->dev_private = (void *)dev_priv; - mach64_do_cleanup_dma(dev); - return DRM_ERR(EINVAL); - } drm_core_ioremap(dev_priv->ring_map, dev); if (!dev_priv->ring_map->handle) { DRM_ERROR("can not ioremap virtual address for" @@ -891,27 +892,9 @@ static int mach64_do_dma_init(drm_device } } - /* allocate descriptor memory from pci pool */ - DRM_DEBUG("Allocating dma descriptor ring\n"); dev_priv->ring.size = 0x4000; /* 16KB */ - - if (dev_priv->is_pci) { - dev_priv->ring.dmah = drm_pci_alloc(dev, dev_priv->ring.size, - dev_priv->ring.size, - 0xfffffffful); - - if (!dev_priv->ring.dmah) { - DRM_ERROR("Allocating dma descriptor ring failed\n"); - return DRM_ERR(ENOMEM); - } else { - dev_priv->ring.start = dev_priv->ring.dmah->vaddr; - dev_priv->ring.start_addr = - (u32) dev_priv->ring.dmah->busaddr; - } - } else { - dev_priv->ring.start = dev_priv->ring_map->handle; - dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; - } + dev_priv->ring.start = dev_priv->ring_map->handle; + dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; memset(dev_priv->ring.start, 0, dev_priv->ring.size); DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n", @@ -1149,18 +1132,14 @@ int mach64_do_cleanup_dma(drm_device_t * if (dev->dev_private) { drm_mach64_private_t *dev_priv = dev->dev_private; - if (dev_priv->is_pci) { - if (dev_priv->ring.dmah) { - drm_pci_free(dev, dev_priv->ring.dmah); - } - } else { + if (!dev_priv->is_pci) { if (dev_priv->ring_map) drm_core_ioremapfree(dev_priv->ring_map, dev); - } - if (dev->agp_buffer_map) { - drm_core_ioremapfree(dev->agp_buffer_map, dev); - dev->agp_buffer_map = NULL; + if (dev->agp_buffer_map) { + drm_core_ioremapfree(dev->agp_buffer_map, dev); + dev->agp_buffer_map = NULL; + } } mach64_destroy_freelist(dev); diff --git a/shared-core/mach64_drm.h b/shared-core/mach64_drm.h index 1fd8c00..083f959 100644 --- a/shared-core/mach64_drm.h +++ b/shared-core/mach64_drm.h @@ -237,7 +237,7 @@ typedef struct drm_mach64_vertex { } drm_mach64_vertex_t; typedef struct drm_mach64_blit { - int idx; + void *buf; int pitch; int offset; int format; diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h index e8dc71e..bb8b309 100644 --- a/shared-core/mach64_drv.h +++ b/shared-core/mach64_drv.h @@ -42,9 +42,9 @@ #define DRIVER_NAME "mach64" #define DRIVER_DESC "DRM module for the ATI Rage Pro" -#define DRIVER_DATE "20020904" +#define DRIVER_DATE "20060718" -#define DRIVER_MAJOR 1 +#define DRIVER_MAJOR 2 #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0 @@ -61,7 +61,6 @@ typedef struct drm_mach64_freelist { } drm_mach64_freelist_t; typedef struct drm_mach64_descriptor_ring { - drm_dma_handle_t *dmah; /* Handle to pci dma memory */ void *start; /* write pointer (cpu address) to start of descriptor ring */ u32 start_addr; /* bus address of beginning of descriptor ring */ int size; /* size of ring in bytes */ diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c index 31e3b56..38cefca 100644 --- a/shared-core/mach64_state.c +++ b/shared-core/mach64_state.c @@ -480,16 +480,16 @@ static int mach64_do_get_frames_queued(d /* Copy and verify a client submited buffer. * FIXME: Make an assembly optimized version */ -static __inline__ int copy_and_verify_from_user(u32 *to, - const u32 __user *ufrom, - unsigned long bytes) +static __inline__ int copy_from_user_vertex(u32 *to, + const u32 __user *ufrom, + unsigned long bytes) { unsigned long n = bytes; /* dwords remaining in buffer */ u32 *from, *orig_from; from = drm_alloc(bytes, DRM_MEM_DRIVER); if (from == NULL) - return ENOMEM; + return DRM_ERR(ENOMEM); if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { drm_free(from, bytes, DRM_MEM_DRIVER); @@ -571,7 +571,7 @@ static int mach64_dma_dispatch_vertex(DR return DRM_ERR(EAGAIN); } - verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used); + verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used); if (verify_ret != 0) { mach64_freelist_put(dev_priv, copy_buf); @@ -627,13 +627,27 @@ _vertex_done: return verify_ret; } +static __inline__ int copy_from_user_blit(u32 *to, + const u32 __user *ufrom, + unsigned long bytes) +{ + to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); + + if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { + return DRM_ERR(EFAULT); + } + + return 0; +} + static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, drm_mach64_blit_t * blit) { drm_mach64_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; int dword_shift, dwords; - drm_buf_t *buf; + unsigned long used; + drm_buf_t *copy_buf; + int verify_ret = 0; DMALOCALS; /* The compiler won't optimize away a division by a variable, @@ -660,34 +674,34 @@ static int mach64_dma_dispatch_blit(DRMF return DRM_ERR(EINVAL); } - /* Dispatch the blit buffer. - */ - buf = dma->buflist[blit->idx]; - - if (buf->filp != filp) { - DRM_ERROR("process %d (filp %p) using buffer with filp %p\n", - DRM_CURRENTPID, filp, buf->filp); - return DRM_ERR(EINVAL); - } - - if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", blit->idx); - return DRM_ERR(EINVAL); - } - /* Set buf->used to the bytes of blit data based on the blit dimensions * and verify the size. When the setup is emitted to the buffer with * the DMA* macros below, buf->used is incremented to include the bytes * used for setup as well as the blit data. */ dwords = (blit->width * blit->height) >> dword_shift; - buf->used = dwords << 2; - if (buf->used <= 0 || - buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { - DRM_ERROR("Invalid blit size: %d bytes\n", buf->used); + used = dwords << 2; + if (used <= 0 || + used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { + DRM_ERROR("Invalid blit size: %lu bytes\n", used); return DRM_ERR(EINVAL); } + copy_buf = mach64_freelist_get(dev_priv); + if (copy_buf == NULL) { + DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__); + return DRM_ERR(EAGAIN); + } + + verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used); + + if (verify_ret != 0) { + mach64_freelist_put(dev_priv, copy_buf); + goto _blit_done; + } + + copy_buf->used = used; + /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, * continuation buffers? */ @@ -696,7 +710,7 @@ static int mach64_dma_dispatch_blit(DRMF * a register command every 16 dwords. State setup is added at the start of the * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET */ - DMASETPTR(buf); + DMASETPTR(copy_buf); DMAOUTREG(MACH64_Z_CNTL, 0); DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); @@ -726,12 +740,13 @@ static int mach64_dma_dispatch_blit(DRMF DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); - DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used); + DRM_DEBUG("%s: %lu bytes\n", __FUNCTION__, used); /* Add the buffer to the queue */ DMAADVANCEHOSTDATA(dev_priv); - return 0; +_blit_done: + return verify_ret; } /* ================================================================ @@ -829,7 +844,6 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS) int mach64_dma_blit(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_device_dma_t *dma = dev->dma; drm_mach64_private_t *dev_priv = dev->dev_private; drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mach64_blit_t blit; @@ -840,15 +854,6 @@ int mach64_dma_blit(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data, sizeof(blit)); - DRM_DEBUG("%s: pid=%d index=%d\n", - __FUNCTION__, DRM_CURRENTPID, blit.idx); - - if (blit.idx < 0 || blit.idx >= dma->buf_count) { - DRM_ERROR("buffer index %d (of %d max)\n", - blit.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); - } - ret = mach64_dma_dispatch_blit(filp, dev, &blit); /* Make sure we restore the 3D state next time. diff-tree f3deef730d52c94ce21ada7e4ceb63aa28a8601b (from 25760c30d4aedb370423d0bb03c014cab47b5d4f) Author: George Sapountzis <gs...@ya...> Date: Mon Oct 2 05:46:42 2006 +0300 Bug 6242: [mach64] Use private DMA buffers, part #3. Add DRM_PCI_BUFFER_RO flag for mapping PCI DMA buffer read-only. An additional flag is needed, since PCI DMA buffers do not have an associated map. diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 2ad7080..d58baa7 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -149,7 +149,8 @@ typedef enum { DRM_PAGE_ALIGN = 0x01, DRM_AGP_BUFFER = 0x02, DRM_SG_BUFFER = 0x04, - DRM_FB_BUFFER = 0x08 + DRM_FB_BUFFER = 0x08, + DRM_PCI_BUFFER_RO = 0x10 } drmBufDescFlags; typedef enum { diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5c9644e..2bbec70 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -449,7 +449,8 @@ typedef struct drm_device_dma { enum { _DRM_DMA_USE_AGP = 0x01, _DRM_DMA_USE_SG = 0x02, - _DRM_DMA_USE_FB = 0x04 + _DRM_DMA_USE_FB = 0x04, + _DRM_DMA_USE_PCI_RO = 0x08 } flags; } drm_device_dma_t; diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index abd7c82..a2a3dbf 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -942,6 +942,9 @@ int drm_addbufs_pci(drm_device_t * dev, request->count = entry->buf_count; request->size = size; + if (request->flags & _DRM_PCI_BUFFER_RO) + dma->flags = _DRM_DMA_USE_PCI_RO; + atomic_dec(&dev->buf_alloc); return 0; @@ -1528,9 +1531,10 @@ int drm_freebufs(struct inode *inode, st * \param arg pointer to a drm_buf_map structure. * \return zero on success or a negative number on failure. * - * Maps the AGP or SG buffer region with do_mmap(), and copies information - * about each buffer into user space. The PCI buffers are already mapped on the - * addbufs_pci() call. + * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information + * about each buffer into user space. For PCI buffers, it calls do_mmap() with + * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls + * drm_mmap_dma(). */ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 9672269..adff7d1 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -506,6 +506,22 @@ static int drm_mmap_dma(struct file *fil } unlock_kernel(); + if (!capable(CAP_SYS_ADMIN) && + (dma->flags & _DRM_DMA_USE_PCI_RO)) { + vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); +#if defined(__i386__) || defined(__x86_64__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; +#else + /* Ye gads this is ugly. With more thought + we could move this up higher and use + `protection_map' instead. */ + vma->vm_page_prot = + __pgprot(pte_val + (pte_wrprotect + (__pte(pgprot_val(vma->vm_page_prot))))); +#endif + } + vma->vm_ops = &drm_vm_dma_ops; #if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ diff --git a/shared-core/drm.h b/shared-core/drm.h index 7f90a96..8c0c5d2 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -416,7 +416,8 @@ typedef struct drm_buf_desc { _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ _DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */ - _DRM_FB_BUFFER = 0x08 /**< Buffer is in frame buffer */ + _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ + _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */ } flags; unsigned long agp_start; /**< * Start address of where the AGP buffers are diff-tree 25760c30d4aedb370423d0bb03c014cab47b5d4f (from eea150e776657faca7d5b76aca75a33dc74fbc9d) Author: George Sapountzis <gs...@ya...> Date: Mon Aug 28 05:44:37 2006 +0300 Bug 6242: [mach64] Use private DMA buffers, part #2. Factor out from mach64_dma_dispatch_vertex() the code to reclaim an unsed buffer, in preperation for using it in mach64_dma_dispatch_blit() also. diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 3f4394c..7cba8ad 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -1449,6 +1449,33 @@ drm_buf_t *mach64_freelist_get(drm_mach6 return entry->buf; } +int mach64_freelist_put(drm_mach64_private_t * dev_priv, drm_buf_t * copy_buf) +{ + struct list_head *ptr; + drm_mach64_freelist_t *entry; + +#if MACH64_EXTRA_CHECKING + list_for_each(ptr, &dev_priv->pending) { + entry = list_entry(ptr, drm_mach64_freelist_t, list); + if (copy_buf == entry->buf) { + DRM_ERROR("%s: Trying to release a pending buf\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + } +#endif + ptr = dev_priv->placeholders.next; + entry = list_entry(ptr, drm_mach64_freelist_t, list); + copy_buf->pending = 0; + copy_buf->used = 0; + entry->buf = copy_buf; + entry->discard = 1; + list_del(ptr); + list_add_tail(ptr, &dev_priv->free_list); + + return 0; +} + /*@}*/ diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h index 2a5f2ff..e8dc71e 100644 --- a/shared-core/mach64_drv.h +++ b/shared-core/mach64_drv.h @@ -123,6 +123,8 @@ extern void mach64_driver_lastclose(drm_ extern int mach64_init_freelist(drm_device_t * dev); extern void mach64_destroy_freelist(drm_device_t * dev); extern drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv); +extern int mach64_freelist_put(drm_mach64_private_t * dev_priv, + drm_buf_t * copy_buf); extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv, int entries); diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c index ce44f0d..31e3b56 100644 --- a/shared-core/mach64_state.c +++ b/shared-core/mach64_state.c @@ -546,12 +546,15 @@ static __inline__ int copy_and_verify_fr } static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev, - int prim, void *buf, unsigned long used, - int discard) + drm_mach64_vertex_t * vertex) { drm_mach64_private_t *dev_priv = dev->dev_private; drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_buf_t *copy_buf; + void *buf = vertex->buf; + unsigned long used = vertex->used; + int ret = 0; + int i = 0; int done = 0; int verify_ret = 0; DMALOCALS; @@ -559,87 +562,65 @@ static int mach64_dma_dispatch_vertex(DR DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n", __FUNCTION__, buf, used, sarea_priv->nbox); - if (used) { - int ret = 0; - int i = 0; - - copy_buf = mach64_freelist_get(dev_priv); - if (copy_buf == NULL) { - DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n", - __FUNCTION__); - return DRM_ERR(EAGAIN); - } + if (!used) + goto _vertex_done; - if ((verify_ret = - copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, - used)) == 0) { - - copy_buf->used = used; - - DMASETPTR(copy_buf); - - if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { - ret = mach64_emit_state(filp, dev_priv); - if (ret < 0) - return ret; - } + copy_buf = mach64_freelist_get(dev_priv); + if (copy_buf == NULL) { + DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__); + return DRM_ERR(EAGAIN); + } + + verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used); + + if (verify_ret != 0) { + mach64_freelist_put(dev_priv, copy_buf); + goto _vertex_done; + } - do { - /* Emit the next cliprect */ - if (i < sarea_priv->nbox) { - ret = - mach64_emit_cliprect(filp, dev_priv, - &sarea_priv-> - boxes[i]); - if (ret < 0) { - /* failed to get buffer */ - return ret; - } else if (ret != 0) { - /* null intersection with scissor */ - continue; - } - } - if ((i >= sarea_priv->nbox - 1)) - done = 1; + copy_buf->used = used; - /* Add the buffer to the DMA queue */ - DMAADVANCE(dev_priv, done); + DMASETPTR(copy_buf); - } while (++i < sarea_priv->nbox); + if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { + ret = mach64_emit_state(filp, dev_priv); + if (ret < 0) + return ret; + } + + do { + /* Emit the next cliprect */ + if (i < sarea_priv->nbox) { + ret = mach64_emit_cliprect(filp, dev_priv, + &sarea_priv->boxes[i]); + if (ret < 0) { + /* failed to get buffer */ + return ret; + } else if (ret != 0) { + /* null intersection with scissor */ + continue; + } } + if ((i >= sarea_priv->nbox - 1)) + done = 1; - if (copy_buf->pending && !done) { + /* Add the buffer to the DMA queue */ + DMAADVANCE(dev_priv, done); + + } while (++i < sarea_priv->nbox); + + if (!done) { + if (copy_buf->pending) { DMADISCARDBUF(); - } else if (!done) { - /* This buffer wasn't used (no cliprects or verify failed), so place it back - * on the free list + } else { + /* This buffer wasn't used (no cliprects), so place it + * back on the free list */ - struct list_head *ptr; - drm_mach64_freelist_t *entry; -#if MACH64_EXTRA_CHECKING - list_for_each(ptr, &dev_priv->pending) { - entry = - list_entry(ptr, drm_mach64_freelist_t, - list); - if (copy_buf == entry->buf) { - DRM_ERROR - ("%s: Trying to release a pending buf\n", - __FUNCTION__); - return DRM_ERR(EFAULT); - } - } -#endif - ptr = dev_priv->placeholders.next; - entry = list_entry(ptr, drm_mach64_freelist_t, list); - copy_buf->pending = 0; - copy_buf->used = 0; - entry->buf = copy_buf; - entry->discard = 1; - list_del(ptr); - list_add_tail(ptr, &dev_priv->free_list); + mach64_freelist_put(dev_priv, copy_buf); } } +_vertex_done: sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; sarea_priv->nbox = 0; @@ -842,8 +823,7 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS) if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; - return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf, - vertex.used, vertex.discard); + return mach64_dma_dispatch_vertex(filp, dev, &vertex); } int mach64_dma_blit(DRM_IOCTL_ARGS) diff-tree eea150e776657faca7d5b76aca75a33dc74fbc9d (from d1b31a228b72b8dd8e588f0a0cc8eeabc3845f70) Author: George Sapountzis <gs...@ya...> Date: Sun Jul 16 02:15:02 2006 +0300 Bug 6242: [mach64] Use private DMA buffers, part #1. Factor out from mach64_freelist_get() the code to reclaim a completed buffer, this is to improve readability for me. diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 36fddf0..3f4394c 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -1329,17 +1329,88 @@ int mach64_do_release_used_buffers(drm_m return 0; } +static int mach64_do_reclaim_completed(drm_mach64_private_t * dev_priv) +{ + drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; + struct list_head *ptr; + struct list_head *tmp; + drm_mach64_freelist_t *entry; + u32 head, tail, ofs; + + mach64_ring_tick(dev_priv, ring); + head = ring->head; + tail = ring->tail; + + if (head == tail) { +#if MACH64_EXTRA_CHECKING + if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) { + DRM_ERROR("Empty ring with non-idle engine!\n"); + mach64_dump_ring_info(dev_priv); + return -1; + } +#endif + /* last pass is complete, so release everything */ + mach64_do_release_used_buffers(dev_priv); + DRM_DEBUG("%s: idle engine, freed all buffers.\n", + __FUNCTION__); + if (list_empty(&dev_priv->free_list)) { + DRM_ERROR("Freelist empty with idle engine\n"); + return -1; + } + return 0; + } + /* Look for a completed buffer and bail out of the loop + * as soon as we find one -- don't waste time trying + * to free extra bufs here, leave that to do_release_used_buffers + */ + list_for_each_safe(ptr, tmp, &dev_priv->pending) { + entry = list_entry(ptr, drm_mach64_freelist_t, list); + ofs = entry->ring_ofs; + if (entry->discard && + ((head < tail && (ofs < head || ofs >= tail)) || + (head > tail && (ofs < head && ofs >= tail)))) { +#if MACH64_EXTRA_CHECKING + int i; + + for (i = head; i != tail; i = (i + 4) & ring->tail_mask) + { + u32 o1 = le32_to_cpu(((u32 *) ring-> + start)[i + 1]); + u32 o2 = GETBUFADDR(entry->buf); + + if (o1 == o2) { + DRM_ERROR + ("Attempting to free used buffer: " + "i=%d buf=0x%08x\n", + i, o1); + mach64_dump_ring_info(dev_priv); + return -1; + } + } +#endif + /* found a processed buffer */ + entry->buf->pending = 0; + list_del(ptr); + list_add_tail(ptr, &dev_priv->free_list); + DRM_DEBUG + ("%s: freed processed buffer (head=%d tail=%d " + "buf ring ofs=%d).\n", + __FUNCTION__, head, tail, ofs); + return 0; + } + } + + return 1; +} + drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv) { drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; drm_mach64_freelist_t *entry; struct list_head *ptr; - struct list_head *tmp; int t; if (list_empty(&dev_priv->free_list)) { - u32 head, tail, ofs; - if (list_empty(&dev_priv->pending)) { DRM_ERROR ("Couldn't get buffer - pending and free lists empty\n"); @@ -1351,81 +1422,15 @@ drm_buf_t *mach64_freelist_get(drm_mach6 return NULL; } - tail = ring->tail; for (t = 0; t < dev_priv->usec_timeout; t++) { - mach64_ring_tick(dev_priv, ring); - head = ring->head; + int ret; - if (head == tail) { -#if MACH64_EXTRA_CHECKING - if (MACH64_READ(MACH64_GUI_STAT) & - MACH64_GUI_ACTIVE) { - DRM_ERROR - ("Empty ring with non-idle engine!\n"); - mach64_dump_ring_info(dev_priv); - return NULL; - } -#endif - /* last pass is complete, so release everything */ - mach64_do_release_used_buffers(dev_priv); - DRM_DEBUG - ("%s: idle engine, freed all buffers.\n", - __FUNCTION__); - if (list_empty(&dev_priv->free_list)) { - DRM_ERROR - ("Freelist empty with idle engine\n"); - return NULL; - } + ret = mach64_do_reclaim_completed(dev_priv); + if (ret == 0) goto _freelist_entry_found; - } - /* Look for a completed buffer and bail out of the loop - * as soon as we find one -- don't waste time trying - * to free extra bufs here, leave that to do_release_used_buffers - */ - list_for_each_safe(ptr, tmp, &dev_priv->pending) { - entry = - list_entry(ptr, drm_mach64_freelist_t, - list); - ofs = entry->ring_ofs; - if (entry->discard && - ((head < tail - && (ofs < head || ofs >= tail)) - || (head > tail - && (ofs < head && ofs >= tail)))) { -#if MACH64_EXTRA_CHECKING - int i; + if (ret < 0) + return NULL; - for (i = head; i != tail; - i = (i + 4) & ring->tail_mask) { - u32 o1 = - le32_to_cpu(((u32 *) ring-> - start)[i + 1]); - u32 o2 = GETBUFADDR(entry->buf); - - if (o1 == o2) { - DRM_ERROR - ("Attempting to free used buffer: " - "i=%d buf=0x%08x\n", - i, o1); - mach64_dump_ring_info - (dev_priv); - return NULL; - } - } -#endif - /* found a processed buffer */ - entry->buf->pending = 0; - list_del(ptr); - entry->buf->used = 0; - list_add_tail(ptr, - &dev_priv->placeholders); - DRM_DEBUG - ("%s: freed processed buffer (head=%d tail=%d " - "buf ring ofs=%d).\n", - __FUNCTION__, head, tail, ofs); - return entry->buf; - } - } DRM_UDELAY(1); } mach64_dump_ring_info(dev_priv); diff-tree d1b31a228b72b8dd8e588f0a0cc8eeabc3845f70 (from f6238cf6244b32bd84e3d2819963d7f5473867c8) Author: George Sapountzis <gs...@ya...> Date: Sun Jul 16 01:02:06 2006 +0300 Bug 6209: [mach64] AGP DMA buffers not mapped correctly. Map the DMA buffers from the same linear address as the vertex bufs. If dev->agp_buffer_token is not set, mach64 drm maps the DMA buffers from linear address 0x0. diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 4c8edea..36fddf0 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -834,6 +834,7 @@ static int mach64_do_dma_init(drm_device mach64_do_cleanup_dma(dev); return DRM_ERR(ENOMEM); } + dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { diff-tree f6238cf6244b32bd84e3d2819963d7f5473867c8 (from 3a16e615cabfed18b1891a732e7243ef41dc0ad0) Author: Michel Dänzer <mi...@tu...> Date: Mon Oct 2 15:33:19 2006 +0200 Fix type of second argument to spin_lock_irqsave(). diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 41038fd..4d8e4a2 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -416,7 +416,7 @@ EXPORT_SYMBOL(drm_vbl_send_signals); static void drm_locked_tasklet_func(unsigned long data) { drm_device_t *dev = (drm_device_t*)data; - unsigned int irqflags; + unsigned long irqflags; spin_lock_irqsave(&dev->tasklet_lock, irqflags); @@ -454,7 +454,7 @@ static void drm_locked_tasklet_func(unsi */ void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) { - unsigned int irqflags; + unsigned long irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) || diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index fa677ba..d1b85a1 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -152,7 +152,7 @@ int drm_unlock(struct inode *inode, stru drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; - unsigned int irqflags; + unsigned long irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index d203b24..0817e32 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -43,7 +43,7 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; - unsigned int irqflags; + unsigned long irqflags; int i, j; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -134,7 +134,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) drm_draw_t draw; int id, idx; unsigned int shift; - unsigned int irqflags; + unsigned long irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t **info = dev->drw_info; @@ -220,9 +220,9 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, shift; + unsigned int id, idx, shift, bitfield_length = dev->drw_bitfield_length; u32 *bitfield = dev->drw_bitfield; - unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; + unsigned long irqflags; drm_drawable_info_t *info; drm_clip_rect_t *rects; int err; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 76c3a81..feb7acc 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned int irqflags; + unsigned long irqflags; struct list_head *list, *tmp; DRM_DEBUG("\n"); @@ -388,7 +388,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, irqflags, curseq; + unsigned int pipe, seqtype, curseq; + unsigned long irqflags; struct list_head *list; if (!dev_priv) { diff-tree 3a16e615cabfed18b1891a732e7243ef41dc0ad0 (from d58389968124191a546a14b42ef84edc224be23d) Author: Michel Dänzer <mi...@tu...> Date: Mon Oct 2 11:04:42 2006 +0200 Make locked tasklet handling more robust. Initialize the spinlock unconditionally when struct drm_device is filled in, and return early in drm_locked_tasklet() if the driver doesn't support IRQs. diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d1a6a6b..41038fd 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -118,7 +118,6 @@ static int drm_irq_install(drm_device_t init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); - spin_lock_init(&dev->tasklet_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs2.head); @@ -458,7 +457,8 @@ void drm_locked_tasklet(drm_device_t *de unsigned int irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); - if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) || + test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) return; spin_lock_irqsave(&dev->tasklet_lock, irqflags); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index ad78dcf..839cf44 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); + spin_lock_init(&dev->tasklet_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff-tree d58389968124191a546a14b42ef84edc224be23d (from 7af93dd9849442270ec89cb4bbeef5bfd4f9e424) Author: Felix Kühling <fx...@gm...> Date: Mon Oct 2 10:50:40 2006 +0200 drm_rmdraw: Declare id and idx as signed so testing for < 0 works as intended. diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 5e2fc86..d203b24 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -132,7 +132,8 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int id, idx, shift; + int id, idx; + unsigned int shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; diff-tree 7af93dd9849442270ec89cb4bbeef5bfd4f9e424 (from 881ba569929ceafd42e3c86228b0172099083d1d) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 29 10:27:29 2006 +0200 i915: Only schedule vblank tasklet if there are scheduled swaps pending. This fixes issues on X server startup with versions of xf86-video-intel that enable the IRQ before they have a context ID. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index fbc6674..76c3a81 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -171,7 +171,8 @@ irqreturn_t i915_driver_irq_handler(DRM_ DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); - drm_locked_tasklet(dev, i915_vblank_tasklet); + if (dev_priv->swaps_pending > 0) + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; diff-tree 881ba569929ceafd42e3c86228b0172099083d1d (from 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b) Author: Michel Dänzer <mi...@tu...> Date: Wed Sep 27 18:22:10 2006 +0200 i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A. It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled. So we only increase dev->vbl_received if the corresponding bit is also set in dev->vblank_pipe. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9db3870..fbc6674 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -153,14 +153,19 @@ irqreturn_t i915_driver_irq_handler(DRM_ DRM_WAKEUP(&dev_priv->irq_queue); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - if ((dev_priv->vblank_pipe & + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { if (temp & VSYNC_PIPEA_FLAG) atomic_inc(&dev->vbl_received); if (temp & VSYNC_PIPEB_FLAG) atomic_inc(&dev->vbl_received2); - } else + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); diff-tree 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b (from 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30) Author: Michel Dänzer <mi...@tu...> Date: Mon Sep 18 12:15:38 2006 +0200 i915: Bump minor for swap scheduling ioctl and secondary vblank support. diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index dc9bbc5..de7f822 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -46,9 +46,11 @@ * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy * 1.5: Add vblank pipe configuration + * 1.6: - New ioctl for scheduling buffer swaps on vertical blank + * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 typedef struct _drm_i915_ring_buffer { diff-tree 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 (from 50a0284a61d4415c0ebdb02decee76ef3115007a) Author: Michel Dänzer <mi...@tu...> Date: Wed Sep 13 08:59:35 2006 +0200 i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d32f592..9db3870 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -399,7 +399,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -408,11 +408,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { - DRM_DEBUG("Not scheduling swap for current sequence\n"); - return DRM_ERR(EINVAL); - } - if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); @@ -430,21 +425,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); - - switch (seqtype) { - case _DRM_VBLANK_RELATIVE: + if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; - break; - case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) <= (1<<23)) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + if ((curseq - swap.sequence) <= (1<<23)) { + if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { + swap.sequence = curseq + 1; + } else { DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); } - break; } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); diff-tree 50a0284a61d4415c0ebdb02decee76ef3115007a (from cf6b2c5299e9be3542d4deddfd05d5811f11d2ef) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:48:07 2006 +0200 Only return EBUSY after we've established we need to schedule a new swap. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9cd8ece..d32f592 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -395,11 +395,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); - } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); @@ -464,6 +459,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { diff-tree cf6b2c5299e9be3542d4deddfd05d5811f11d2ef (from 89e323e4900af84cc33219ad24eb0b435a039d23) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:35:31 2006 +0200 Core vsync: Don't clobber target sequence number when scheduling signal. It looks like this would have caused signals to always get sent on the next vertical blank, regardless of the sequence number. diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index bd8a9c8..d1a6a6b 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -295,8 +295,6 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = seq; - spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -309,6 +307,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) && vbl_sig->task == current) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + vblwait.reply.sequence = seq; goto done; } } @@ -339,6 +338,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + vblwait.reply.sequence = seq; } else { if (flags & _DRM_VBLANK_SECONDARY) { if (dev->driver->vblank_wait2) diff-tree 89e323e4900af84cc33219ad24eb0b435a039d23 (from 7f09f957d9a61ac107f8fd29128d7899a3e8a228) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:27:14 2006 +0200 Core vsync: Add flag DRM_VBLANK_NEXTONMISS. When this flag is set and the target sequence is missed, wait for the next vertical blank instead of returning immediately. diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index cda570d..2ad7080 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index fef0e8d..bd8a9c8 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags; - atomic_t *seq; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : - &dev->vbl_received; + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(seq); + vblwait.request.sequence += seq; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait.request.sequence) <= (1<<23)) { + vblwait.request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(seq); + vblwait.reply.sequence = seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); diff --git a/shared-core/drm.h b/shared-core/drm.h index 614422b..7f90a96 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -551,12 +551,14 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ + _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; diff-tree 7f09f957d9a61ac107f8fd29128d7899a3e8a228 (from c2bdb76814755c9ac6e66a8815f23af0fe4f3a91) Author: Michel Dänzer <mi...@tu...> Date: Fri Sep 1 11:24:38 2006 +0200 Fix 'sequence has passed' condition in i915_vblank_swap(). diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 68e7c66..9cd8ece 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -442,7 +442,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence += curseq; break; case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) > (1<<23)) { + if ((curseq - swap.sequence) <= (1<<23)) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); diff-tree c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 (from 84b38b63f05e04ade8b1ddfb770047fd86de0d64) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:33:04 2006 +0200 Add SAREA fileds for determining which pipe to sync window buffer swaps to. diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 3a39d53..358b11e 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Flags for perf_boxes diff-tree 84b38b63f05e04ade8b1ddfb770047fd86de0d64 (from 87c57cba1a70221fc570b253bf3b24682ef6b894) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:32:08 2006 +0200 Add definition of DRM_VBLANK_SECONDARY. diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 9e71eb6..cda570d 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff-tree 87c57cba1a70221fc570b253bf3b24682ef6b894 (from d5a0f107511e128658e2d5e15bd7e6215c507f29) Author: Michel Dänzer <mi...@tu...> Date: Thu Aug 31 18:30:55 2006 +0200 Make handling of dev_priv->vblank_pipe more robust. Initialize it to default value if it hasn't been set by the X server yet. In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call i915_enable_interrupt() if the argument passed from userspace is valid to avoid corrupting dev_priv->vblank_pipe on invalid arguments. diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6f00feb..68e7c66 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -307,7 +307,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static int i915_enable_interrupt (drm_device_t *dev) +static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 flag; @@ -317,13 +317,8 @@ static int i915_enable_interrupt (drm_de flag |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) flag |= VSYNC_PIPEB_FLAG; - if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, dev_priv->vblank_pipe); - return DRM_ERR(EINVAL); - } + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); - return 0; } /* Set the vblank monitor pipe @@ -342,8 +337,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, sizeof(pipe)); + if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, pipe.pipe); + return DRM_ERR(EINVAL); + } + dev_priv->vblank_pipe = pipe.pipe; - return i915_enable_interrupt (dev); + + i915_enable_interrupt (dev); + + return 0; } int i915_vblank_pipe_get(DRM_IOCTL_ARGS) @@ -505,6 +509,8 @@ void i915_driver_irq_postinstall(drm_dev INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } diff-tree d5a0f107511e128658e2d5e15bd7e6215c507f29 (from df7551ef7334d728ec0371423661bb403d3e270a) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 30 19:33:28 2006 +0200 DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number. Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 7e4ba13..3a39d53 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -149,6 +149,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying @@ -249,7 +250,7 @@ typedef struct drm_i915_vblank_pipe { */ typedef struct drm_i915_vblank_swap { drm_drawable_t drawable; - unsigned int pipe; + drm_vblank_seq_type_t seqtype; unsigned int sequence; } drm_i915_vblank_swap_t; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 39d8c38..6f00feb 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -378,7 +378,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int irqflags; + unsigned int pipe, seqtype, irqflags, curseq; struct list_head *list; if (!dev_priv) { @@ -399,8 +399,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); - if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { - DRM_ERROR("Invalid pipe %d\n", swap.pipe); + if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); + return DRM_ERR(EINVAL); + } + + pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + + seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { + DRM_DEBUG("Not scheduling swap for current sequence\n"); + return DRM_ERR(EINVAL); + } + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); } @@ -414,13 +429,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + switch (seqtype) { + case _DRM_VBLANK_RELATIVE: + swap.sequence += curseq; + break; + case _DRM_VBLANK_ABSOLUTE: + if ((curseq - swap.sequence) > (1<<23)) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Missed target sequence\n"); + return DRM_ERR(EINVAL); + } + break; + } + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap.drawable && - vbl_swap->pipe == swap.pipe && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); @@ -440,7 +470,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); vbl_swap->drw_id = swap.drawable; - vbl_swap->pipe = swap.pipe; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -450,6 +480,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, + sizeof(swap)); + return 0; } diff-tree df7551ef7334d728ec0371423661bb403d3e270a (from d04751facea36cb888c7510b126658fdbc4277d5) Author: Michel Dänzer <mi...@tu...> Date: Wed Aug 30 19:24:04 2006 +0200 Change first valid DRM drawable ID to be 1 instead of 0. This makes it easier for userspace to know when it needs to allocate an ID. Also free drawable information memory when it's no longer needed. diff --git a/linux-core/drm_drv.c b/linux... [truncated message content] |