From 4f2c60bb65fec6333c4b16bbc33c0c8112244916 Mon Sep 17 00:00:00 2001 From: Jeff Hartmann Date: Thu, 7 Sep 2000 22:33:36 +0000 Subject: [PATCH] Code to help in debugging of the mga drm modules locking policy --- linux-core/Makefile.kernel | 1 + linux-core/drmP.h | 20 ++++- linux-core/mga_drv.c | 97 ++++++++++++----------- linux/Makefile.kernel | 1 + linux/Makefile.linux | 3 +- linux/drmP.h | 20 ++++- linux/drm_heavy_kern_lock.c | 150 ++++++++++++++++++++++++++++++++++++ linux/fops.c | 1 + linux/mga_dma.c | 17 ++-- linux/mga_drv.c | 97 ++++++++++++----------- linux/mga_state.c | 14 +++- 11 files changed, 323 insertions(+), 98 deletions(-) create mode 100644 linux/drm_heavy_kern_lock.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b1b8d976..2b9b357f 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -27,6 +27,7 @@ export-objs := $(patsubst %.o,%_drv.o,$(module-list)) # lib-objs := init.o memory.o proc.o auth.o context.o drawable.o bufs.o lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o +lib-objs += drm_heavy_kern_lock.o ifeq ($(CONFIG_AGP),y) lib-objs += agpsupport.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2bfd4bef..74ac66d3 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -300,6 +300,7 @@ typedef struct drm_ioctl_desc { drm_ioctl_t *func; int auth_needed; int root_only; + int needs_hvy_lock; } drm_ioctl_desc_t; typedef struct drm_devstate { @@ -430,9 +431,10 @@ typedef struct drm_file { struct drm_file *next; struct drm_file *prev; struct drm_device *dev; + volatile int lock_depth; + unsigned long irq_flags; } drm_file_t; - typedef struct drm_queue { atomic_t use_count; /* Outstanding uses (+1) */ atomic_t finalization; /* Finalization in progress */ @@ -615,6 +617,12 @@ typedef struct drm_device { void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ sigset_t sigmask; + + spinlock_t big_fscking_lock; + volatile int irq_lock_depth; + unsigned long irq_flags; + volatile int bh_lock_depth; + unsigned long bh_flags; } drm_device_t; @@ -817,6 +825,16 @@ extern void drm_ctxbitmap_cleanup(drm_device_t *dev); extern int drm_ctxbitmap_next(drm_device_t *dev); extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + /* BIG Fscking lock (drm_heavy_kern_lock.c) */ +extern void drm_schedule(drm_device_t *dev); +extern void drm_schedule_timeout(drm_device_t *dev, unsigned long timeout); +extern void drm_big_fscking_lock(drm_device_t *dev); +extern void drm_big_fscking_unlock(drm_device_t *dev); +extern void __inline drm_big_fscking_lock_filp(drm_device_t *dev, + drm_file_t *filp); +extern void __inline drm_big_fscking_unlock_filp(drm_device_t *dev, + drm_file_t *filp); + #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) /* AGP/GART support (agpsupport.c) */ extern drm_agp_head_t *drm_agp_init(void); diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index c49cef58..5e47f436 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -66,54 +66,55 @@ static struct miscdevice mga_misc = { }; static drm_ioctl_desc_t mga_ioctls[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_version, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_version, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { mga_control, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { mga_addbufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { mga_control, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { mga_addbufs, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_resctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_resctx, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma, 1, 0, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0, 1 }, }; #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -182,6 +183,9 @@ static int mga_setup(drm_device_t *dev) dev->last_context = 0; dev->last_switch = 0; dev->last_checked = 0; + dev->irq_lock_depth = -1; + dev->bh_lock_depth = -1; + init_timer(&dev->timer); init_waitqueue_head(&dev->context_wait); @@ -192,6 +196,7 @@ static int mga_setup(drm_device_t *dev) dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); init_waitqueue_head(&dev->buf_writers); @@ -539,7 +544,7 @@ int mga_release(struct inode *inode, struct file *filp) /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - schedule(); + drm_schedule(dev); if (signal_pending(current)) { retcode = -ERESTARTSYS; break; @@ -619,7 +624,11 @@ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, || (ioctl->auth_needed && !priv->authenticated)) { retcode = -EACCES; } else { + if(ioctl->needs_hvy_lock == 1) + drm_big_fscking_lock_filp(dev, priv); retcode = (func)(inode, filp, cmd, arg); + if(ioctl->needs_hvy_lock == 1) + drm_big_fscking_unlock_filp(dev, priv); } } diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index b1b8d976..2b9b357f 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -27,6 +27,7 @@ export-objs := $(patsubst %.o,%_drv.o,$(module-list)) # lib-objs := init.o memory.o proc.o auth.o context.o drawable.o bufs.o lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o +lib-objs += drm_heavy_kern_lock.o ifeq ($(CONFIG_AGP),y) lib-objs += agpsupport.o diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 7fe57f8e..84648d54 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -53,7 +53,8 @@ LIBS= libdrm.a PROGS= drmstat DRMOBJS= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ - lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o + lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \ + drm_heavy_kern_lock.o DRMHEADERS= drm.h drmP.h compat-pre24.h GAMMAOBJS= gamma_drv.o gamma_dma.o diff --git a/linux/drmP.h b/linux/drmP.h index 2bfd4bef..74ac66d3 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -300,6 +300,7 @@ typedef struct drm_ioctl_desc { drm_ioctl_t *func; int auth_needed; int root_only; + int needs_hvy_lock; } drm_ioctl_desc_t; typedef struct drm_devstate { @@ -430,9 +431,10 @@ typedef struct drm_file { struct drm_file *next; struct drm_file *prev; struct drm_device *dev; + volatile int lock_depth; + unsigned long irq_flags; } drm_file_t; - typedef struct drm_queue { atomic_t use_count; /* Outstanding uses (+1) */ atomic_t finalization; /* Finalization in progress */ @@ -615,6 +617,12 @@ typedef struct drm_device { void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ sigset_t sigmask; + + spinlock_t big_fscking_lock; + volatile int irq_lock_depth; + unsigned long irq_flags; + volatile int bh_lock_depth; + unsigned long bh_flags; } drm_device_t; @@ -817,6 +825,16 @@ extern void drm_ctxbitmap_cleanup(drm_device_t *dev); extern int drm_ctxbitmap_next(drm_device_t *dev); extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + /* BIG Fscking lock (drm_heavy_kern_lock.c) */ +extern void drm_schedule(drm_device_t *dev); +extern void drm_schedule_timeout(drm_device_t *dev, unsigned long timeout); +extern void drm_big_fscking_lock(drm_device_t *dev); +extern void drm_big_fscking_unlock(drm_device_t *dev); +extern void __inline drm_big_fscking_lock_filp(drm_device_t *dev, + drm_file_t *filp); +extern void __inline drm_big_fscking_unlock_filp(drm_device_t *dev, + drm_file_t *filp); + #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) /* AGP/GART support (agpsupport.c) */ extern drm_agp_head_t *drm_agp_init(void); diff --git a/linux/drm_heavy_kern_lock.c b/linux/drm_heavy_kern_lock.c new file mode 100644 index 00000000..8ff0dc18 --- /dev/null +++ b/linux/drm_heavy_kern_lock.c @@ -0,0 +1,150 @@ +/* This has to be used VERY carefully, since you never want to sleep with the + * lock. It would be very bad if you slept w/ irq's disabled. + */ + +/* Big fscking lock implementation */ +#define __NO_VERSION__ +#include "drmP.h" +#include + +/* This is not smp safe! */ +static __inline__ drm_file_t *drm_find_filp_by_current_pid(drm_device_t *dev) +{ + drm_file_t *first; + +/* down(&dev->struct_sem); */ + first = dev->file_first; + while(first != NULL) { + if(first->pid == current->pid) { + break; + } + first = first->next; + } + +/* up(&dev->struct_sem); */ + return first; +} + +static __inline__ void drm_release_big_fscking_lock(drm_device_t *dev, drm_file_t *filp) +{ + if(filp->lock_depth >= 0) + spin_unlock_irqrestore(&dev->big_fscking_lock, + filp->irq_flags); +} + +static __inline__ void drm_reacquire_big_fscking_lock(drm_device_t *dev, drm_file_t *filp) +{ + unsigned long flags; + + if(filp->lock_depth >= 0) { + barrier(); + spin_lock_irqsave(&dev->big_fscking_lock, flags); + filp->irq_flags = flags; + } +} + +/* This can NEVER be called from an interrupt */ +void drm_schedule(drm_device_t *dev) +{ + drm_file_t *filp; + + if(in_interrupt()) { + BUG(); + } + + filp = drm_find_filp_by_current_pid(dev); + if(filp == NULL) BUG(); + drm_release_big_fscking_lock(dev, filp); + schedule(); + drm_reacquire_big_fscking_lock(dev, filp); +} + +void drm_schedule_timeout(drm_device_t *dev, unsigned long timeout) +{ + drm_file_t *filp; + + if(in_interrupt()) { + BUG(); + } + + filp = drm_find_filp_by_current_pid(dev); + if(filp == NULL) BUG(); + drm_release_big_fscking_lock(dev, filp); + schedule_timeout(timeout); + drm_reacquire_big_fscking_lock(dev, filp); +} + +void drm_big_fscking_lock(drm_device_t *dev) +{ + drm_file_t *filp; + unsigned long flags; + + if(in_irq()) { + barrier(); + if(!++dev->irq_lock_depth) { + spin_lock_irqsave(&dev->big_fscking_lock, + flags); + dev->irq_flags = flags; + } + } else if (in_softirq()) { + barrier(); + if(!++dev->bh_lock_depth) { + spin_lock_irqsave(&dev->big_fscking_lock, + flags); + dev->bh_flags = flags; + } + } else { + filp = drm_find_filp_by_current_pid(dev); + if(filp == NULL) BUG(); + barrier(); + if(!++filp->lock_depth) { + spin_lock_irqsave(&dev->big_fscking_lock, + flags); + dev->irq_flags = flags; + } + } +} + +void drm_big_fscking_unlock(drm_device_t *dev) +{ + drm_file_t *filp; + + if(in_irq()) { + barrier(); + if(--dev->irq_lock_depth < 0) + spin_unlock_irqrestore(&dev->big_fscking_lock, + dev->irq_flags); + } else if (in_softirq()) { + barrier(); + if(--dev->bh_lock_depth < 0) + spin_unlock_irqrestore(&dev->big_fscking_lock, + dev->bh_flags); + } else { + filp = drm_find_filp_by_current_pid(dev); + if(filp == NULL) BUG(); + barrier(); + if(--filp->lock_depth < 0) + spin_unlock_irqrestore(&dev->big_fscking_lock, + filp->irq_flags); + } +} + +void __inline drm_big_fscking_lock_filp(drm_device_t *dev, drm_file_t *filp) +{ + unsigned long flags; + + barrier(); + if(!++filp->lock_depth) { + spin_lock_irqsave(&dev->big_fscking_lock, + flags); + dev->irq_flags = flags; + } +} + +void __inline drm_big_fscking_unlock_filp(drm_device_t *dev, drm_file_t *filp) +{ + barrier(); + if(--filp->lock_depth < 0) + spin_unlock_irqrestore(&dev->big_fscking_lock, + filp->irq_flags); +} diff --git a/linux/fops.c b/linux/fops.c index 8e373e5a..0c03d205 100644 --- a/linux/fops.c +++ b/linux/fops.c @@ -55,6 +55,7 @@ int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev) priv->dev = dev; priv->ioctl_count = 0; priv->authenticated = capable(CAP_SYS_ADMIN); + priv->lock_depth = -1; down(&dev->struct_sem); if (!dev->file_last) { diff --git a/linux/mga_dma.c b/linux/mga_dma.c index f80fb489..40cc3a55 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -230,7 +230,7 @@ drm_buf_t *mga_freelist_get(drm_device_t *dev) &dev_priv->dispatch_status)) break; atomic_inc(&dev->total_sleeps); - schedule(); + drm_schedule(dev); if (signal_pending(current)) { clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); @@ -417,6 +417,7 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) } mga_flush_write_combine(); + atomic_inc(&dev_priv->pending_bufs); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); @@ -472,7 +473,7 @@ int mga_advance_primary(drm_device_t *dev) break; atomic_inc(&dev->total_sleeps); atomic_inc(&dma->total_missed_sched); - schedule(); + drm_schedule(dev); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -563,6 +564,8 @@ int mga_dma_schedule(drm_device_t *dev, int locked) drm_device_dma_t *dma = dev->dma; int retval = 0; + drm_big_fscking_lock(dev); + if (test_and_set_bit(0, &dev->dma_flag)) { atomic_inc(&dma->total_missed_dma); retval = -EBUSY; @@ -633,6 +636,7 @@ sch_out_wakeup: } clear_bit(0, &dev->dma_flag); + drm_big_fscking_unlock(dev); return retval; } @@ -645,6 +649,7 @@ static void mga_dma_service(int irq, void *device, struct pt_regs *regs) DRM_DEBUG("%s\n", __FUNCTION__); atomic_inc(&dev->total_irq); if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; + drm_big_fscking_lock(dev); MGA_WRITE(MGAREG_ICLEAR, 0x00000001); last_prim_buffer = dev_priv->last_prim; last_prim_buffer->num_dwords = 0; @@ -658,6 +663,7 @@ static void mga_dma_service(int irq, void *device, struct pt_regs *regs) atomic_dec(&dev_priv->pending_bufs); queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); + drm_big_fscking_unlock(dev); } static void mga_dma_task_queue(void *device) @@ -813,8 +819,9 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { /* Poll for the first buffer to insure that * the status register will be correct */ - + mga_flush_write_combine(); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | @@ -960,7 +967,7 @@ static int mga_flush_queue(drm_device_t *dev) &dev_priv->dispatch_status)) break; atomic_inc(&dev->total_sleeps); - schedule(); + drm_schedule(dev); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ clear_bit(MGA_IN_FLUSH, @@ -1050,7 +1057,7 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - schedule(); + drm_schedule(dev); if (signal_pending(current)) { ret = -ERESTARTSYS; break; diff --git a/linux/mga_drv.c b/linux/mga_drv.c index c49cef58..5e47f436 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -66,54 +66,55 @@ static struct miscdevice mga_misc = { }; static drm_ioctl_desc_t mga_ioctls[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_version, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_version, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { mga_control, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { mga_addbufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { mga_control, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { mga_addbufs, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_resctx, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_resctx, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma, 1, 0, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0, 1 }, }; #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -182,6 +183,9 @@ static int mga_setup(drm_device_t *dev) dev->last_context = 0; dev->last_switch = 0; dev->last_checked = 0; + dev->irq_lock_depth = -1; + dev->bh_lock_depth = -1; + init_timer(&dev->timer); init_waitqueue_head(&dev->context_wait); @@ -192,6 +196,7 @@ static int mga_setup(drm_device_t *dev) dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); init_waitqueue_head(&dev->buf_writers); @@ -539,7 +544,7 @@ int mga_release(struct inode *inode, struct file *filp) /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - schedule(); + drm_schedule(dev); if (signal_pending(current)) { retcode = -ERESTARTSYS; break; @@ -619,7 +624,11 @@ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, || (ioctl->auth_needed && !priv->authenticated)) { retcode = -EACCES; } else { + if(ioctl->needs_hvy_lock == 1) + drm_big_fscking_lock_filp(dev, priv); retcode = (func)(inode, filp, cmd, arg); + if(ioctl->needs_hvy_lock == 1) + drm_big_fscking_unlock_filp(dev, priv); } } diff --git a/linux/mga_state.c b/linux/mga_state.c index 0c2f5729..33667d80 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -218,8 +218,8 @@ static void mgaG400EmitTex1(drm_mga_private_t * dev_priv, int source ) /* This takes 25 dwords */ - PRIMOUTREG(MGAREG_TEXCTL2, - regs[MGA_TEXREG_CTL2] | TMC_map1_enable | 0x00008000); + PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable | + 0x00008000); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]); PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]); PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]); @@ -873,7 +873,9 @@ int mga_clear_bufs(struct inode *inode, struct file *filp, clear.clear_color_mask, clear.clear_depth_mask); PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); return 0; } @@ -903,7 +905,9 @@ int mga_swap_bufs(struct inode *inode, struct file *filp, PRIMUPDATE(dev_priv); set_bit(MGA_BUF_SWAP_PENDING, &dev_priv->current_prim->buffer_status); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); return 0; } @@ -951,7 +955,9 @@ int mga_iload(struct inode *inode, struct file *filp, AGEBUF(dev_priv, buf_priv); buf_priv->discard = 1; mga_freelist_put(dev, buf); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); return 0; } @@ -999,7 +1005,9 @@ int mga_vertex(struct inode *inode, struct file *filp, mga_dma_dispatch_vertex(dev, buf); PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); return 0; } @@ -1046,7 +1054,9 @@ int mga_indices(struct inode *inode, struct file *filp, mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); return 0; }