diff options
author | Jose Fonseca <jrfonseca@users.sourceforge.net> | 2003-06-21 12:49:34 +0000 |
---|---|---|
committer | Jose Fonseca <jrfonseca@users.sourceforge.net> | 2003-06-21 12:49:34 +0000 |
commit | c83761e041c5d91394f5590bb8c79d66b2d6cc7a (patch) | |
tree | b3658c5006545670630ab8d15146ca35de468605 | |
parent | a37956947f9e1b2920c3fe7a1cb4f6953a9d7da8 (diff) |
Janitorial of drm_dma.h.
-rw-r--r-- | linux-core/drmP.h | 53 | ||||
-rw-r--r-- | linux-core/drm_dma.c | 520 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 4 | ||||
-rw-r--r-- | linux-core/i810_drv.c | 2 | ||||
-rw-r--r-- | linux-core/i830_drv.c | 2 | ||||
-rw-r--r-- | linux-core/i830_irq.c | 2 | ||||
-rw-r--r-- | linux-core/mga_drv.c | 2 | ||||
-rw-r--r-- | linux-core/r128_drv.c | 2 | ||||
-rw-r--r-- | linux-core/radeon_drv.c | 2 | ||||
-rw-r--r-- | linux-core/sis_drv.c | 2 | ||||
-rw-r--r-- | linux-core/tdfx_drv.c | 2 | ||||
-rw-r--r-- | linux/drmP.h | 53 | ||||
-rw-r--r-- | linux/drm_dma.h | 520 | ||||
-rw-r--r-- | linux/drm_dma_tmp.h | 529 | ||||
-rw-r--r-- | linux/drm_drv.h | 4 | ||||
-rw-r--r-- | linux/gamma_drv.c | 2 | ||||
-rw-r--r-- | linux/i810_drv.c | 2 | ||||
-rw-r--r-- | linux/i830_drv.c | 2 | ||||
-rw-r--r-- | linux/i830_irq.c | 2 | ||||
-rw-r--r-- | linux/mga_drv.c | 2 | ||||
-rw-r--r-- | linux/r128_drv.c | 2 | ||||
-rw-r--r-- | linux/radeon_drv.c | 2 | ||||
-rw-r--r-- | linux/sis_drv.c | 2 | ||||
-rw-r--r-- | linux/tdfx_drv.c | 2 |
24 files changed, 636 insertions, 1081 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 15775342d..1f5f83e61 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -117,6 +117,7 @@ typedef struct drm_device drm_device_t; #include "drm_sg.h" #include "drm_bufs.h" #include "drm_lock.h" +#include "drm_dma.h" /***********************************************************************/ @@ -497,17 +498,6 @@ typedef struct drm_map_list { typedef drm_map_t drm_local_map_t; -#if __HAVE_VBL_IRQ - -typedef struct drm_vbl_sig { - struct list_head head; - unsigned int sequence; - struct siginfo info; - struct task_struct *task; -} drm_vbl_sig_t; - -#endif - /** * DRM device structure. */ @@ -589,16 +579,8 @@ struct drm_device { #else struct work_struct work; #endif - /** \name VBLANK IRQ support */ - /*@{*/ -#if __HAVE_VBL_IRQ - wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t vbl_received; - spinlock_t vbl_lock; - drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ - unsigned int vbl_pending; -#endif - /*@}*/ + drm_vbl_data_t vbl; /**< VBLANK IRQ support */ + cycles_t ctx_start; cycles_t lck_start; @@ -760,35 +742,6 @@ extern int DRM(getmagic)(struct inode *inode, struct file *filp, extern int DRM(authmagic)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); - /* DMA support (drm_dma.h) */ -#if __HAVE_DMA -extern int DRM(dma_setup)(drm_device_t *dev); -extern void DRM(dma_takedown)(drm_device_t *dev); -extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)( struct file *filp ); -#if __HAVE_DMA_IRQ -extern int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(irq_install)( drm_device_t *dev, int irq ); -extern int DRM(irq_uninstall)( drm_device_t *dev ); -extern void DRM(dma_service)( int irq, void *device, - struct pt_regs *regs ); -extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); -extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); -extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); -#if __HAVE_VBL_IRQ -extern int DRM(wait_vblank)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); -extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#endif -#if __HAVE_DMA_IRQ_BH -extern void DRM(dma_immediate_bh)( void *dev ); -#endif -#endif -#endif /* __HAVE_DMA */ - - /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, struct file_operations *fops, diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c index 8e0ec95ec..8daa2ba25 100644 --- a/linux-core/drm_dma.c +++ b/linux-core/drm_dma.c @@ -1,14 +1,12 @@ /** * \file drm_dma.h - * DMA IOCTL and function support + * DMA ioctl and function support * * \author Rickard E. (Rik) Faith <faith@valinux.com> * \author Gareth Hughes <gareth@valinux.com> */ /* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -33,499 +31,61 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#define __NO_VERSION__ -#include "drmP.h" - -#include <linux/interrupt.h> /* For task queue support */ - -#ifndef __HAVE_DMA_WAITQUEUE -#define __HAVE_DMA_WAITQUEUE 0 -#endif -#ifndef __HAVE_DMA_RECLAIM -#define __HAVE_DMA_RECLAIM 0 -#endif -#ifndef __HAVE_SHARED_IRQ -#define __HAVE_SHARED_IRQ 0 -#endif - -#if __HAVE_SHARED_IRQ -#define DRM_IRQ_TYPE SA_SHIRQ -#else -#define DRM_IRQ_TYPE 0 -#endif - -#if __HAVE_DMA - -/** - * Initialize the DMA data. - * - * \param dev DRM device. - * \return zero on success or a negative value on failure. - * - * Allocate and initialize a drm_device_dma structure. - */ -int DRM(dma_setup)( drm_device_t *dev ) -{ - int i; - - dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER ); - if ( !dev->dma ) - return -ENOMEM; - - memset( dev->dma, 0, sizeof(*dev->dma) ); +#ifndef _DRM_DMA_H_ +#define _DRM_DMA_H_ - for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ ) - memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); - - return 0; -} - -/** - * Cleanup the DMA resources. - * - * \param dev DRM device. - * - * Free all pages associated with DMA buffers, the buffers and pages lists, and - * finally the the drm_device::dma structure itself. - */ -void DRM(dma_takedown)(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - int i, j; - - if (!dma) return; - - /* Clear dma buffers */ - for (i = 0; i <= DRM_MAX_ORDER; i++) { - if (dma->bufs[i].seg_count) { - DRM_DEBUG("order %d: buf_count = %d," - " seg_count = %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].seg_count); - for (j = 0; j < dma->bufs[i].seg_count; j++) { - if (dma->bufs[i].seglist[j]) { - DRM(free_pages)(dma->bufs[i].seglist[j], - dma->bufs[i].page_order, - DRM_MEM_DMA); - } - } - DRM(free)(dma->bufs[i].seglist, - dma->bufs[i].seg_count - * sizeof(*dma->bufs[0].seglist), - DRM_MEM_SEGS); - } - if (dma->bufs[i].buf_count) { - for (j = 0; j < dma->bufs[i].buf_count; j++) { - if (dma->bufs[i].buflist[j].dev_private) { - DRM(free)(dma->bufs[i].buflist[j].dev_private, - dma->bufs[i].buflist[j].dev_priv_size, - DRM_MEM_BUFS); - } - } - DRM(free)(dma->bufs[i].buflist, - dma->bufs[i].buf_count * - sizeof(*dma->bufs[0].buflist), - DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&dma->bufs[i].freelist); -#endif - } - } - - if (dma->buflist) { - DRM(free)(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - DRM_MEM_BUFS); - } - - if (dma->pagelist) { - DRM(free)(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - } - DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); - dev->dma = NULL; -} - - -/** - * Free a buffer. - * - * \param dev DRM device. - * \param buf buffer to free. - * - * Resets the fields of \p buf. - */ -void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) -{ - if (!buf) return; - buf->waiting = 0; - buf->pending = 0; - buf->filp = 0; - buf->used = 0; +#if __HAVE_VBL_IRQ - if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { - wake_up_interruptible(&buf->dma_wait); - } -#if __HAVE_DMA_FREELIST - else { - drm_device_dma_t *dma = dev->dma; - /* If processes are waiting, the last one - to wake will put the buffer on the free - list. If no processes are waiting, we - put the buffer on the freelist here. */ - DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); - } -#endif -} +typedef struct drm_vbl_sig { + struct list_head head; + unsigned int sequence; + struct siginfo info; + struct task_struct *task; +} drm_vbl_sig_t; -#if !__HAVE_DMA_RECLAIM /** - * Reclaim the buffers. - * - * \param filp file pointer. - * - * Frees each buffer associated with \p filp not already on the hardware. + * VBLANK IRQ data */ -void DRM(reclaim_buffers)( struct file *filp ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int i; +typedef struct drm_vbl_data { + wait_queue_head_t queue; /**< VBLANK wait queue */ + atomic_t received; + spinlock_t lock; + drm_vbl_sig_t sigs; /**< signal list to send on VBLANK */ + unsigned int pending; +} drm_vbl_data_t; - if (!dma) return; - for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->filp == filp) { - switch (dma->buflist[i]->list) { - case DRM_LIST_NONE: - DRM(free_buffer)(dev, dma->buflist[i]); - break; - case DRM_LIST_WAIT: - dma->buflist[i]->list = DRM_LIST_RECLAIM; - break; - default: - /* Buffer already on hardware. */ - break; - } - } - } -} #endif +/** \name Prototypes */ +/*@{*/ - +#if __HAVE_DMA +extern int DRM(dma_setup)(drm_device_t *dev); +extern void DRM(dma_takedown)(drm_device_t *dev); +extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); +extern void DRM(reclaim_buffers)( struct file *filp ); #if __HAVE_DMA_IRQ - -/** - * Install IRQ handler. - * - * \param dev DRM device. - * \param irq IRQ number. - * - * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver - * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions - * before and after the installation. - */ -int DRM(irq_install)( drm_device_t *dev, int irq ) -{ - int ret; - - if ( !irq ) - return -EINVAL; - - down( &dev->struct_sem ); - - /* Driver must have been initialized */ - if ( !dev->dev_private ) { - up( &dev->struct_sem ); - return -EINVAL; - } - - if ( dev->irq ) { - up( &dev->struct_sem ); - return -EBUSY; - } - dev->irq = irq; - up( &dev->struct_sem ); - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - dev->context_flag = 0; - dev->interrupt_flag = 0; - dev->dma_flag = 0; - - dev->dma->next_buffer = NULL; - dev->dma->next_queue = NULL; - dev->dma->this_buffer = NULL; - +extern int DRM(control_ioctl)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +extern int DRM(irq_install)( drm_device_t *dev, int irq ); +extern int DRM(irq_uninstall)( drm_device_t *dev ); +extern void DRM(dma_service)( int irq, void *device, struct pt_regs *regs ); +extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); +extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); +extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); +#if __HAVE_VBL_IRQ +extern int DRM(wait_vblank_ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); +extern void DRM(vbl_send_signals)( drm_device_t *dev ); +#endif #if __HAVE_DMA_IRQ_BH -#if !HAS_WORKQUEUE - INIT_LIST_HEAD( &dev->tq.list ); - dev->tq.sync = 0; - dev->tq.routine = DRM(dma_immediate_bh); - dev->tq.data = dev; -#else - INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev); +extern void DRM(dma_immediate_bh)( void *dev ); #endif #endif - -#if __HAVE_VBL_IRQ - init_waitqueue_head(&dev->vbl_queue); - - spin_lock_init( &dev->vbl_lock ); - - INIT_LIST_HEAD( &dev->vbl_sigs.head ); - - dev->vbl_pending = 0; #endif - /* Before installing handler */ - DRM(driver_irq_preinstall)(dev); - - /* Install handler */ - ret = request_irq( dev->irq, DRM(dma_service), - DRM_IRQ_TYPE, dev->devname, dev ); - if ( ret < 0 ) { - down( &dev->struct_sem ); - dev->irq = 0; - up( &dev->struct_sem ); - return ret; - } - - /* After installing handler */ - DRM(driver_irq_postinstall)(dev); - - return 0; -} - -/** - * Uninstall the IRQ handler. - * - * \param dev DRM device. - * - * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. - */ -int DRM(irq_uninstall)( drm_device_t *dev ) -{ - int irq; - - down( &dev->struct_sem ); - irq = dev->irq; - dev->irq = 0; - up( &dev->struct_sem ); - - if ( !irq ) - return -EINVAL; - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - DRM(driver_irq_uninstall)( dev ); - - free_irq( irq, dev ); - - return 0; -} - -/** - * IRQ control ioctl. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg user argument, pointing to a drm_control structure. - * \return zero on success or a negative number on failure. - * - * Calls irq_install() or irq_uninstall() according to \p arg. - */ -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - return DRM(irq_install)( dev, ctl.irq ); - case DRM_UNINST_HANDLER: - return DRM(irq_uninstall)( dev ); - default: - return -EINVAL; - } -} - -#if __HAVE_VBL_IRQ - -/** - * Wait for VBLANK. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param data user argument, pointing to a drm_wait_vblank structure. - * \return zero on success or a negative number on failure. - * - * Verifies the IRQ is installed. - * - * If a signal is requested checks if this task has already scheduled the same signal - * for the same vblank sequence number - nothing to be done in - * that case. If the number of tasks waiting for the interrupt exceeds 100 the - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this - * task. - * - * If a signal is not requested, then calls vblank_wait(). - */ -int DRM(wait_vblank)( DRM_IOCTL_ARGS ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_wait_vblank_t vblwait; - struct timeval now; - int ret = 0; - unsigned int flags; - - if (!dev->irq) - return -EINVAL; - - DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, - sizeof(vblwait) ); - - switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { - case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read( &dev->vbl_received ); - vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; - case _DRM_VBLANK_ABSOLUTE: - break; - default: - return -EINVAL; - } - - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - - if ( flags & _DRM_VBLANK_SIGNAL ) { - unsigned long irqflags; - drm_vbl_sig_t *vbl_sig; - - vblwait.reply.sequence = atomic_read( &dev->vbl_received ); - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); +/*@}*/ - /* Check if this task has already scheduled the same signal - * for the same vblank sequence number; nothing to be done in - * that case - */ - list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { - if (vbl_sig->sequence == vblwait.request.sequence - && vbl_sig->info.si_signo == vblwait.request.signal - && vbl_sig->task == current) - { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - goto done; - } - } - if ( dev->vbl_pending >= 100 ) { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - return -EBUSY; - } - - dev->vbl_pending++; - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - - if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { - return -ENOMEM; - } - - memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); - - vbl_sig->sequence = vblwait.request.sequence; - vbl_sig->info.si_signo = vblwait.request.signal; - vbl_sig->task = current; - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); - - list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head ); - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - } else { - ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); - - do_gettimeofday( &now ); - vblwait.reply.tval_sec = now.tv_sec; - vblwait.reply.tval_usec = now.tv_usec; - } - -done: - DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, - sizeof(vblwait) ); - - return ret; -} - -/** - * Send the VBLANK signals. - * - * \param dev DRM device. - * - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. - * - * If a signal is not requested, then calls vblank_wait(). - */ -void DRM(vbl_send_signals)( drm_device_t *dev ) -{ - struct list_head *list, *tmp; - drm_vbl_sig_t *vbl_sig; - unsigned int vbl_seq = atomic_read( &dev->vbl_received ); - unsigned long flags; - - spin_lock_irqsave( &dev->vbl_lock, flags ); - - list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { - vbl_sig = list_entry( list, drm_vbl_sig_t, head ); - if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - - list_del( list ); - - DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); - - dev->vbl_pending--; - } - } - - spin_unlock_irqrestore( &dev->vbl_lock, flags ); -} - -#endif /* __HAVE_VBL_IRQ */ - -#else - -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - case DRM_UNINST_HANDLER: - return 0; - default: - return -EINVAL; - } -} - -#endif /* __HAVE_DMA_IRQ */ - -#endif /* __HAVE_DMA */ +#endif diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 57b521f77..8cc8a77ca 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -221,7 +221,7 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control_ioctl), 1, 1 }, #endif #if __REALLY_HAVE_AGP @@ -241,7 +241,7 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { #endif #if __HAVE_VBL_IRQ - [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank_ioctl), 0, 0 }, #endif DRIVER_IOCTLS diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index 058f0c35c..e7160eb96 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -41,7 +41,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux-core/i830_drv.c b/linux-core/i830_drv.c index 8cc4a8d31..dd2af6985 100644 --- a/linux-core/i830_drv.c +++ b/linux-core/i830_drv.c @@ -43,7 +43,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux-core/i830_irq.c b/linux-core/i830_irq.c index 1fcd9f0a8..c1658d10e 100644 --- a/linux-core/i830_irq.c +++ b/linux-core/i830_irq.c @@ -177,7 +177,7 @@ int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd, } -/* drm_dma.h hooks +/* drm_dma_tmp.h hooks */ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { drm_i830_private_t *dev_priv = diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 8a69d684b..9f7abab3b 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -39,7 +39,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index 4d895b7f5..d2e37231d 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -41,7 +41,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 5635d7516..716f0ee40 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -42,7 +42,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index e916e4e9f..5aece8f96 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -35,7 +35,7 @@ #include "drm_agp_tmp.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index 2e9721b53..36fdb35e1 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -78,7 +78,7 @@ static drm_pci_list_t DRM(idlist)[] = { #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux/drmP.h b/linux/drmP.h index 15775342d..1f5f83e61 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -117,6 +117,7 @@ typedef struct drm_device drm_device_t; #include "drm_sg.h" #include "drm_bufs.h" #include "drm_lock.h" +#include "drm_dma.h" /***********************************************************************/ @@ -497,17 +498,6 @@ typedef struct drm_map_list { typedef drm_map_t drm_local_map_t; -#if __HAVE_VBL_IRQ - -typedef struct drm_vbl_sig { - struct list_head head; - unsigned int sequence; - struct siginfo info; - struct task_struct *task; -} drm_vbl_sig_t; - -#endif - /** * DRM device structure. */ @@ -589,16 +579,8 @@ struct drm_device { #else struct work_struct work; #endif - /** \name VBLANK IRQ support */ - /*@{*/ -#if __HAVE_VBL_IRQ - wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t vbl_received; - spinlock_t vbl_lock; - drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ - unsigned int vbl_pending; -#endif - /*@}*/ + drm_vbl_data_t vbl; /**< VBLANK IRQ support */ + cycles_t ctx_start; cycles_t lck_start; @@ -760,35 +742,6 @@ extern int DRM(getmagic)(struct inode *inode, struct file *filp, extern int DRM(authmagic)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); - /* DMA support (drm_dma.h) */ -#if __HAVE_DMA -extern int DRM(dma_setup)(drm_device_t *dev); -extern void DRM(dma_takedown)(drm_device_t *dev); -extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)( struct file *filp ); -#if __HAVE_DMA_IRQ -extern int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(irq_install)( drm_device_t *dev, int irq ); -extern int DRM(irq_uninstall)( drm_device_t *dev ); -extern void DRM(dma_service)( int irq, void *device, - struct pt_regs *regs ); -extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); -extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); -extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); -#if __HAVE_VBL_IRQ -extern int DRM(wait_vblank)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); -extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#endif -#if __HAVE_DMA_IRQ_BH -extern void DRM(dma_immediate_bh)( void *dev ); -#endif -#endif -#endif /* __HAVE_DMA */ - - /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, struct file_operations *fops, diff --git a/linux/drm_dma.h b/linux/drm_dma.h index 8e0ec95ec..8daa2ba25 100644 --- a/linux/drm_dma.h +++ b/linux/drm_dma.h @@ -1,14 +1,12 @@ /** * \file drm_dma.h - * DMA IOCTL and function support + * DMA ioctl and function support * * \author Rickard E. (Rik) Faith <faith@valinux.com> * \author Gareth Hughes <gareth@valinux.com> */ /* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -33,499 +31,61 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#define __NO_VERSION__ -#include "drmP.h" - -#include <linux/interrupt.h> /* For task queue support */ - -#ifndef __HAVE_DMA_WAITQUEUE -#define __HAVE_DMA_WAITQUEUE 0 -#endif -#ifndef __HAVE_DMA_RECLAIM -#define __HAVE_DMA_RECLAIM 0 -#endif -#ifndef __HAVE_SHARED_IRQ -#define __HAVE_SHARED_IRQ 0 -#endif - -#if __HAVE_SHARED_IRQ -#define DRM_IRQ_TYPE SA_SHIRQ -#else -#define DRM_IRQ_TYPE 0 -#endif - -#if __HAVE_DMA - -/** - * Initialize the DMA data. - * - * \param dev DRM device. - * \return zero on success or a negative value on failure. - * - * Allocate and initialize a drm_device_dma structure. - */ -int DRM(dma_setup)( drm_device_t *dev ) -{ - int i; - - dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER ); - if ( !dev->dma ) - return -ENOMEM; - - memset( dev->dma, 0, sizeof(*dev->dma) ); +#ifndef _DRM_DMA_H_ +#define _DRM_DMA_H_ - for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ ) - memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); - - return 0; -} - -/** - * Cleanup the DMA resources. - * - * \param dev DRM device. - * - * Free all pages associated with DMA buffers, the buffers and pages lists, and - * finally the the drm_device::dma structure itself. - */ -void DRM(dma_takedown)(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - int i, j; - - if (!dma) return; - - /* Clear dma buffers */ - for (i = 0; i <= DRM_MAX_ORDER; i++) { - if (dma->bufs[i].seg_count) { - DRM_DEBUG("order %d: buf_count = %d," - " seg_count = %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].seg_count); - for (j = 0; j < dma->bufs[i].seg_count; j++) { - if (dma->bufs[i].seglist[j]) { - DRM(free_pages)(dma->bufs[i].seglist[j], - dma->bufs[i].page_order, - DRM_MEM_DMA); - } - } - DRM(free)(dma->bufs[i].seglist, - dma->bufs[i].seg_count - * sizeof(*dma->bufs[0].seglist), - DRM_MEM_SEGS); - } - if (dma->bufs[i].buf_count) { - for (j = 0; j < dma->bufs[i].buf_count; j++) { - if (dma->bufs[i].buflist[j].dev_private) { - DRM(free)(dma->bufs[i].buflist[j].dev_private, - dma->bufs[i].buflist[j].dev_priv_size, - DRM_MEM_BUFS); - } - } - DRM(free)(dma->bufs[i].buflist, - dma->bufs[i].buf_count * - sizeof(*dma->bufs[0].buflist), - DRM_MEM_BUFS); -#if __HAVE_DMA_FREELIST - DRM(freelist_destroy)(&dma->bufs[i].freelist); -#endif - } - } - - if (dma->buflist) { - DRM(free)(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - DRM_MEM_BUFS); - } - - if (dma->pagelist) { - DRM(free)(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - } - DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); - dev->dma = NULL; -} - - -/** - * Free a buffer. - * - * \param dev DRM device. - * \param buf buffer to free. - * - * Resets the fields of \p buf. - */ -void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) -{ - if (!buf) return; - buf->waiting = 0; - buf->pending = 0; - buf->filp = 0; - buf->used = 0; +#if __HAVE_VBL_IRQ - if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { - wake_up_interruptible(&buf->dma_wait); - } -#if __HAVE_DMA_FREELIST - else { - drm_device_dma_t *dma = dev->dma; - /* If processes are waiting, the last one - to wake will put the buffer on the free - list. If no processes are waiting, we - put the buffer on the freelist here. */ - DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); - } -#endif -} +typedef struct drm_vbl_sig { + struct list_head head; + unsigned int sequence; + struct siginfo info; + struct task_struct *task; +} drm_vbl_sig_t; -#if !__HAVE_DMA_RECLAIM /** - * Reclaim the buffers. - * - * \param filp file pointer. - * - * Frees each buffer associated with \p filp not already on the hardware. + * VBLANK IRQ data */ -void DRM(reclaim_buffers)( struct file *filp ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_device_dma_t *dma = dev->dma; - int i; +typedef struct drm_vbl_data { + wait_queue_head_t queue; /**< VBLANK wait queue */ + atomic_t received; + spinlock_t lock; + drm_vbl_sig_t sigs; /**< signal list to send on VBLANK */ + unsigned int pending; +} drm_vbl_data_t; - if (!dma) return; - for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->filp == filp) { - switch (dma->buflist[i]->list) { - case DRM_LIST_NONE: - DRM(free_buffer)(dev, dma->buflist[i]); - break; - case DRM_LIST_WAIT: - dma->buflist[i]->list = DRM_LIST_RECLAIM; - break; - default: - /* Buffer already on hardware. */ - break; - } - } - } -} #endif +/** \name Prototypes */ +/*@{*/ - +#if __HAVE_DMA +extern int DRM(dma_setup)(drm_device_t *dev); +extern void DRM(dma_takedown)(drm_device_t *dev); +extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); +extern void DRM(reclaim_buffers)( struct file *filp ); #if __HAVE_DMA_IRQ - -/** - * Install IRQ handler. - * - * \param dev DRM device. - * \param irq IRQ number. - * - * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver - * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions - * before and after the installation. - */ -int DRM(irq_install)( drm_device_t *dev, int irq ) -{ - int ret; - - if ( !irq ) - return -EINVAL; - - down( &dev->struct_sem ); - - /* Driver must have been initialized */ - if ( !dev->dev_private ) { - up( &dev->struct_sem ); - return -EINVAL; - } - - if ( dev->irq ) { - up( &dev->struct_sem ); - return -EBUSY; - } - dev->irq = irq; - up( &dev->struct_sem ); - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - dev->context_flag = 0; - dev->interrupt_flag = 0; - dev->dma_flag = 0; - - dev->dma->next_buffer = NULL; - dev->dma->next_queue = NULL; - dev->dma->this_buffer = NULL; - +extern int DRM(control_ioctl)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +extern int DRM(irq_install)( drm_device_t *dev, int irq ); +extern int DRM(irq_uninstall)( drm_device_t *dev ); +extern void DRM(dma_service)( int irq, void *device, struct pt_regs *regs ); +extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); +extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); +extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); +#if __HAVE_VBL_IRQ +extern int DRM(wait_vblank_ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); +extern void DRM(vbl_send_signals)( drm_device_t *dev ); +#endif #if __HAVE_DMA_IRQ_BH -#if !HAS_WORKQUEUE - INIT_LIST_HEAD( &dev->tq.list ); - dev->tq.sync = 0; - dev->tq.routine = DRM(dma_immediate_bh); - dev->tq.data = dev; -#else - INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev); +extern void DRM(dma_immediate_bh)( void *dev ); #endif #endif - -#if __HAVE_VBL_IRQ - init_waitqueue_head(&dev->vbl_queue); - - spin_lock_init( &dev->vbl_lock ); - - INIT_LIST_HEAD( &dev->vbl_sigs.head ); - - dev->vbl_pending = 0; #endif - /* Before installing handler */ - DRM(driver_irq_preinstall)(dev); - - /* Install handler */ - ret = request_irq( dev->irq, DRM(dma_service), - DRM_IRQ_TYPE, dev->devname, dev ); - if ( ret < 0 ) { - down( &dev->struct_sem ); - dev->irq = 0; - up( &dev->struct_sem ); - return ret; - } - - /* After installing handler */ - DRM(driver_irq_postinstall)(dev); - - return 0; -} - -/** - * Uninstall the IRQ handler. - * - * \param dev DRM device. - * - * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. - */ -int DRM(irq_uninstall)( drm_device_t *dev ) -{ - int irq; - - down( &dev->struct_sem ); - irq = dev->irq; - dev->irq = 0; - up( &dev->struct_sem ); - - if ( !irq ) - return -EINVAL; - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - DRM(driver_irq_uninstall)( dev ); - - free_irq( irq, dev ); - - return 0; -} - -/** - * IRQ control ioctl. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg user argument, pointing to a drm_control structure. - * \return zero on success or a negative number on failure. - * - * Calls irq_install() or irq_uninstall() according to \p arg. - */ -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - return DRM(irq_install)( dev, ctl.irq ); - case DRM_UNINST_HANDLER: - return DRM(irq_uninstall)( dev ); - default: - return -EINVAL; - } -} - -#if __HAVE_VBL_IRQ - -/** - * Wait for VBLANK. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param data user argument, pointing to a drm_wait_vblank structure. - * \return zero on success or a negative number on failure. - * - * Verifies the IRQ is installed. - * - * If a signal is requested checks if this task has already scheduled the same signal - * for the same vblank sequence number - nothing to be done in - * that case. If the number of tasks waiting for the interrupt exceeds 100 the - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this - * task. - * - * If a signal is not requested, then calls vblank_wait(). - */ -int DRM(wait_vblank)( DRM_IOCTL_ARGS ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_wait_vblank_t vblwait; - struct timeval now; - int ret = 0; - unsigned int flags; - - if (!dev->irq) - return -EINVAL; - - DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, - sizeof(vblwait) ); - - switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { - case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read( &dev->vbl_received ); - vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; - case _DRM_VBLANK_ABSOLUTE: - break; - default: - return -EINVAL; - } - - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - - if ( flags & _DRM_VBLANK_SIGNAL ) { - unsigned long irqflags; - drm_vbl_sig_t *vbl_sig; - - vblwait.reply.sequence = atomic_read( &dev->vbl_received ); - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); +/*@}*/ - /* Check if this task has already scheduled the same signal - * for the same vblank sequence number; nothing to be done in - * that case - */ - list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { - if (vbl_sig->sequence == vblwait.request.sequence - && vbl_sig->info.si_signo == vblwait.request.signal - && vbl_sig->task == current) - { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - goto done; - } - } - if ( dev->vbl_pending >= 100 ) { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - return -EBUSY; - } - - dev->vbl_pending++; - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - - if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { - return -ENOMEM; - } - - memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); - - vbl_sig->sequence = vblwait.request.sequence; - vbl_sig->info.si_signo = vblwait.request.signal; - vbl_sig->task = current; - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); - - list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head ); - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - } else { - ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); - - do_gettimeofday( &now ); - vblwait.reply.tval_sec = now.tv_sec; - vblwait.reply.tval_usec = now.tv_usec; - } - -done: - DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, - sizeof(vblwait) ); - - return ret; -} - -/** - * Send the VBLANK signals. - * - * \param dev DRM device. - * - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. - * - * If a signal is not requested, then calls vblank_wait(). - */ -void DRM(vbl_send_signals)( drm_device_t *dev ) -{ - struct list_head *list, *tmp; - drm_vbl_sig_t *vbl_sig; - unsigned int vbl_seq = atomic_read( &dev->vbl_received ); - unsigned long flags; - - spin_lock_irqsave( &dev->vbl_lock, flags ); - - list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { - vbl_sig = list_entry( list, drm_vbl_sig_t, head ); - if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - - list_del( list ); - - DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); - - dev->vbl_pending--; - } - } - - spin_unlock_irqrestore( &dev->vbl_lock, flags ); -} - -#endif /* __HAVE_VBL_IRQ */ - -#else - -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - case DRM_UNINST_HANDLER: - return 0; - default: - return -EINVAL; - } -} - -#endif /* __HAVE_DMA_IRQ */ - -#endif /* __HAVE_DMA */ +#endif diff --git a/linux/drm_dma_tmp.h b/linux/drm_dma_tmp.h new file mode 100644 index 000000000..13d768463 --- /dev/null +++ b/linux/drm_dma_tmp.h @@ -0,0 +1,529 @@ +/** + * \file drm_dma.h + * DMA IOCTL and function support + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#include <linux/interrupt.h> /* For task queue support */ + +#ifndef __HAVE_DMA_WAITQUEUE +#define __HAVE_DMA_WAITQUEUE 0 +#endif +#ifndef __HAVE_DMA_RECLAIM +#define __HAVE_DMA_RECLAIM 0 +#endif +#ifndef __HAVE_SHARED_IRQ +#define __HAVE_SHARED_IRQ 0 +#endif + +#if __HAVE_SHARED_IRQ +#define DRM_IRQ_TYPE SA_SHIRQ +#else +#define DRM_IRQ_TYPE 0 +#endif + +#if __HAVE_DMA + +/** + * Initialize the DMA data. + * + * \param dev DRM device. + * \return zero on success or a negative value on failure. + * + * Allocate and initialize a drm_device_dma structure. + */ +int DRM(dma_setup)( drm_device_t *dev ) +{ + int i; + + dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER ); + if ( !dev->dma ) + return -ENOMEM; + + memset( dev->dma, 0, sizeof(*dev->dma) ); + + for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ ) + memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); + + return 0; +} + +/** + * Cleanup the DMA resources. + * + * \param dev DRM device. + * + * Free all pages associated with DMA buffers, the buffers and pages lists, and + * finally the the drm_device::dma structure itself. + */ +void DRM(dma_takedown)(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i, j; + + if (!dma) return; + + /* Clear dma buffers */ + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].seg_count) { + DRM_DEBUG("order %d: buf_count = %d," + " seg_count = %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].seg_count); + for (j = 0; j < dma->bufs[i].seg_count; j++) { + if (dma->bufs[i].seglist[j]) { + DRM(free_pages)(dma->bufs[i].seglist[j], + dma->bufs[i].page_order, + DRM_MEM_DMA); + } + } + DRM(free)(dma->bufs[i].seglist, + dma->bufs[i].seg_count + * sizeof(*dma->bufs[0].seglist), + DRM_MEM_SEGS); + } + if (dma->bufs[i].buf_count) { + for (j = 0; j < dma->bufs[i].buf_count; j++) { + if (dma->bufs[i].buflist[j].dev_private) { + DRM(free)(dma->bufs[i].buflist[j].dev_private, + dma->bufs[i].buflist[j].dev_priv_size, + DRM_MEM_BUFS); + } + } + DRM(free)(dma->bufs[i].buflist, + dma->bufs[i].buf_count * + sizeof(*dma->bufs[0].buflist), + DRM_MEM_BUFS); +#if __HAVE_DMA_FREELIST + DRM(freelist_destroy)(&dma->bufs[i].freelist); +#endif + } + } + + if (dma->buflist) { + DRM(free)(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + DRM_MEM_BUFS); + } + + if (dma->pagelist) { + DRM(free)(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = NULL; +} + + +/** + * Free a buffer. + * + * \param dev DRM device. + * \param buf buffer to free. + * + * Resets the fields of \p buf. + */ +void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) +{ + if (!buf) return; + + buf->waiting = 0; + buf->pending = 0; + buf->filp = 0; + buf->used = 0; + + if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { + wake_up_interruptible(&buf->dma_wait); + } +#if __HAVE_DMA_FREELIST + else { + drm_device_dma_t *dma = dev->dma; + /* If processes are waiting, the last one + to wake will put the buffer on the free + list. If no processes are waiting, we + put the buffer on the freelist here. */ + DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); + } +#endif +} + +#if !__HAVE_DMA_RECLAIM +/** + * Reclaim the buffers. + * + * \param filp file pointer. + * + * Frees each buffer associated with \p filp not already on the hardware. + */ +void DRM(reclaim_buffers)( struct file *filp ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + for (i = 0; i < dma->buf_count; i++) { + if (dma->buflist[i]->filp == filp) { + switch (dma->buflist[i]->list) { + case DRM_LIST_NONE: + DRM(free_buffer)(dev, dma->buflist[i]); + break; + case DRM_LIST_WAIT: + dma->buflist[i]->list = DRM_LIST_RECLAIM; + break; + default: + /* Buffer already on hardware. */ + break; + } + } + } +} +#endif + + + + +#if __HAVE_DMA_IRQ + +/** + * Install IRQ handler. + * + * \param dev DRM device. + * \param irq IRQ number. + * + * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver + * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions + * before and after the installation. + */ +int DRM(irq_install)( drm_device_t *dev, int irq ) +{ + int ret; + + if ( !irq ) + return -EINVAL; + + down( &dev->struct_sem ); + + /* Driver must have been initialized */ + if ( !dev->dev_private ) { + up( &dev->struct_sem ); + return -EINVAL; + } + + if ( dev->irq ) { + up( &dev->struct_sem ); + return -EBUSY; + } + dev->irq = irq; + up( &dev->struct_sem ); + + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; + +#if __HAVE_DMA_IRQ_BH +#if !HAS_WORKQUEUE + INIT_LIST_HEAD( &dev->tq.list ); + dev->tq.sync = 0; + dev->tq.routine = DRM(dma_immediate_bh); + dev->tq.data = dev; +#else + INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev); +#endif +#endif + +#if __HAVE_VBL_IRQ + init_waitqueue_head(&dev->vbl.queue); + + spin_lock_init( &dev->vbl.lock ); + + INIT_LIST_HEAD( &dev->vbl.sigs.head ); + + dev->vbl.pending = 0; +#endif + + /* Before installing handler */ + DRM(driver_irq_preinstall)(dev); + + /* Install handler */ + ret = request_irq( dev->irq, DRM(dma_service), + DRM_IRQ_TYPE, dev->devname, dev ); + if ( ret < 0 ) { + down( &dev->struct_sem ); + dev->irq = 0; + up( &dev->struct_sem ); + return ret; + } + + /* After installing handler */ + DRM(driver_irq_postinstall)(dev); + + return 0; +} + +/** + * Uninstall the IRQ handler. + * + * \param dev DRM device. + * + * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. + */ +int DRM(irq_uninstall)( drm_device_t *dev ) +{ + int irq; + + down( &dev->struct_sem ); + irq = dev->irq; + dev->irq = 0; + up( &dev->struct_sem ); + + if ( !irq ) + return -EINVAL; + + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); + + DRM(driver_irq_uninstall)( dev ); + + free_irq( irq, dev ); + + return 0; +} + +/** + * IRQ control ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_control structure. + * \return zero on success or a negative number on failure. + * + * Calls irq_install() or irq_uninstall() according to \p arg. + */ +int DRM(control_ioctl)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_control_t ctl; + + if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) + return -EFAULT; + + switch ( ctl.func ) { + case DRM_INST_HANDLER: + return DRM(irq_install)( dev, ctl.irq ); + case DRM_UNINST_HANDLER: + return DRM(irq_uninstall)( dev ); + default: + return -EINVAL; + } +} + +#if __HAVE_VBL_IRQ + +/** + * Wait for VBLANK. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param data user argument, pointing to a drm_wait_vblank structure. + * \return zero on success or a negative number on failure. + * + * Verifies the IRQ is installed. + * + * If a signal is requested checks if this task has already scheduled the same signal + * for the same vblank sequence number - nothing to be done in + * that case. If the number of tasks waiting for the interrupt exceeds 100 the + * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this + * task. + * + * If a signal is not requested, then calls vblank_wait(). + */ +int DRM(wait_vblank_ioctl)( DRM_IOCTL_ARGS ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_wait_vblank_t vblwait; + struct timeval now; + int ret = 0; + unsigned int flags; + + if (!dev->irq) + return -EINVAL; + + DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, + sizeof(vblwait) ); + + switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { + case _DRM_VBLANK_RELATIVE: + vblwait.request.sequence += atomic_read( &dev->vbl.received ); + vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; + case _DRM_VBLANK_ABSOLUTE: + break; + default: + return -EINVAL; + } + + flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + + if ( flags & _DRM_VBLANK_SIGNAL ) { + unsigned long irqflags; + drm_vbl_sig_t *vbl_sig; + + vblwait.reply.sequence = atomic_read( &dev->vbl.received ); + + spin_lock_irqsave( &dev->vbl.lock, irqflags ); + + /* Check if this task has already scheduled the same signal + * for the same vblank sequence number; nothing to be done in + * that case + */ + list_for_each_entry( vbl_sig, &dev->vbl.sigs.head, head ) { + if (vbl_sig->sequence == vblwait.request.sequence + && vbl_sig->info.si_signo == vblwait.request.signal + && vbl_sig->task == current) + { + spin_unlock_irqrestore( &dev->vbl.lock, irqflags ); + goto done; + } + } + + if ( dev->vbl.pending >= 100 ) { + spin_unlock_irqrestore( &dev->vbl.lock, irqflags ); + return -EBUSY; + } + + dev->vbl.pending++; + + spin_unlock_irqrestore( &dev->vbl.lock, irqflags ); + + if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { + return -ENOMEM; + } + + memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); + + vbl_sig->sequence = vblwait.request.sequence; + vbl_sig->info.si_signo = vblwait.request.signal; + vbl_sig->task = current; + + spin_lock_irqsave( &dev->vbl.lock, irqflags ); + + list_add_tail( (struct list_head *) vbl_sig, &dev->vbl.sigs.head ); + + spin_unlock_irqrestore( &dev->vbl.lock, irqflags ); + } else { + ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); + + do_gettimeofday( &now ); + vblwait.reply.tval_sec = now.tv_sec; + vblwait.reply.tval_usec = now.tv_usec; + } + +done: + DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, + sizeof(vblwait) ); + + return ret; +} + +/** + * Send the VBLANK signals. + * + * \param dev DRM device. + * + * Sends a signal for each task in drm_device::vbl_sigs and empties the list. + * + * If a signal is not requested, then calls vblank_wait(). + */ +void DRM(vbl_send_signals)( drm_device_t *dev ) +{ + struct list_head *list, *tmp; + drm_vbl_sig_t *vbl_sig; + unsigned int vbl_seq = atomic_read( &dev->vbl.received ); + unsigned long flags; + + spin_lock_irqsave( &dev->vbl.lock, flags ); + + list_for_each_safe( list, tmp, &dev->vbl.sigs.head ) { + vbl_sig = list_entry( list, drm_vbl_sig_t, head ); + if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { + vbl_sig->info.si_code = vbl_seq; + send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); + + list_del( list ); + + DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); + + dev->vbl.pending--; + } + } + + spin_unlock_irqrestore( &dev->vbl.lock, flags ); +} + +#endif /* __HAVE_VBL_IRQ */ + +#else + +int DRM(control_ioctl)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_control_t ctl; + + if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) + return -EFAULT; + + switch ( ctl.func ) { + case DRM_INST_HANDLER: + case DRM_UNINST_HANDLER: + return 0; + default: + return -EINVAL; + } +} + +#endif /* __HAVE_DMA_IRQ */ + +#endif /* __HAVE_DMA */ diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 57b521f77..8cc8a77ca 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -221,7 +221,7 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control_ioctl), 1, 1 }, #endif #if __REALLY_HAVE_AGP @@ -241,7 +241,7 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { #endif #if __HAVE_VBL_IRQ - [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank_ioctl), 0, 0 }, #endif DRIVER_IOCTLS diff --git a/linux/gamma_drv.c b/linux/gamma_drv.c index 74b554f62..7b10ed95c 100644 --- a/linux/gamma_drv.c +++ b/linux/gamma_drv.c @@ -40,7 +40,7 @@ #include "drm_agp_tmp.h" #include "drm_bufs.h" #include "gamma_context.h" /* NOTE! */ -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "gamma_old_dma.h" /* NOTE */ #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux/i810_drv.c b/linux/i810_drv.c index 058f0c35c..e7160eb96 100644 --- a/linux/i810_drv.c +++ b/linux/i810_drv.c @@ -41,7 +41,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux/i830_drv.c b/linux/i830_drv.c index 8cc4a8d31..dd2af6985 100644 --- a/linux/i830_drv.c +++ b/linux/i830_drv.c @@ -43,7 +43,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" diff --git a/linux/i830_irq.c b/linux/i830_irq.c index 1fcd9f0a8..c1658d10e 100644 --- a/linux/i830_irq.c +++ b/linux/i830_irq.c @@ -177,7 +177,7 @@ int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd, } -/* drm_dma.h hooks +/* drm_dma_tmp.h hooks */ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { drm_i830_private_t *dev_priv = diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 8a69d684b..9f7abab3b 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -39,7 +39,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux/r128_drv.c b/linux/r128_drv.c index 4d895b7f5..d2e37231d 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -41,7 +41,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux/radeon_drv.c b/linux/radeon_drv.c index 5635d7516..716f0ee40 100644 --- a/linux/radeon_drv.c +++ b/linux/radeon_drv.c @@ -42,7 +42,7 @@ #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux/sis_drv.c b/linux/sis_drv.c index e916e4e9f..5aece8f96 100644 --- a/linux/sis_drv.c +++ b/linux/sis_drv.c @@ -35,7 +35,7 @@ #include "drm_agp_tmp.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" diff --git a/linux/tdfx_drv.c b/linux/tdfx_drv.c index 2e9721b53..36fdb35e1 100644 --- a/linux/tdfx_drv.c +++ b/linux/tdfx_drv.c @@ -78,7 +78,7 @@ static drm_pci_list_t DRM(idlist)[] = { #include "drm_auth.h" #include "drm_bufs.h" #include "drm_context.h" -#include "drm_dma.h" +#include "drm_dma_tmp.h" #include "drm_drawable.h" #include "drm_drv.h" |