Index: drmP.h =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm/dist/bsd-core/drmP.h,v retrieving revision 1.5 diff -u -b -r1.5 drmP.h --- drmP.h 19 Jul 2008 17:28:14 -0000 1.5 +++ drmP.h 19 Jul 2008 20:02:26 -0000 @@ -402,7 +402,11 @@ "lock; addl $0,0(%%rsp)" : : : "memory"); #endif -#ifdef __FreeBSD__ +/* XXX If we end up using these macros on memory which is not accessible + * via volatile pointer dereferences, this code should be revisited. + */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) #define DRM_READ8(map, offset) \ *(volatile u_int8_t *) (((unsigned long)(map)->handle) + (offset)) #define DRM_READ16(map, offset) \ @@ -416,13 +420,10 @@ #define DRM_WRITE32(map, offset, val) \ *(volatile u_int32_t *)(((unsigned long)(map)->handle) + (offset)) = val -#define DRM_VERIFYAREA_READ( uaddr, size ) \ - (!useracc(__DECONST(caddr_t, uaddr), size, VM_PROT_READ)) - -#else /* __FreeBSD__ */ - typedef vaddr_t vm_offset_t; +#else /* __FreeBSD__ || __NetBSD__ */ + #define DRM_READ8(map, offset) \ bus_space_read_1( (map)->bst, (map)->bsh, (offset)) #define DRM_READ16(map, offset) \ @@ -436,11 +437,17 @@ #define DRM_WRITE32(map, offset, val) \ bus_space_write_4((map)->bst, (map)->bsh, (offset), (val)) +#endif /* !__FreeBSD__ */ + +#ifdef __FreeBSD__ +#define DRM_VERIFYAREA_READ( uaddr, size ) \ + (!useracc(__DECONST(caddr_t, uaddr), size, VM_PROT_READ)) +#else #define DRM_VERIFYAREA_READ( uaddr, size ) \ (!uvm_map_checkprot(&(curproc->p_vmspace->vm_map), \ (vaddr_t)uaddr, (vaddr_t)uaddr+size, UVM_PROT_READ)) +#endif -#endif /* !__FreeBSD__ */ #define DRM_COPY_TO_USER(user, kern, size) \ copyout(kern, user, size) @@ -881,6 +888,7 @@ DRM_SPINTYPE dev_lock; /* protects everything else */ #endif DRM_SPINTYPE drw_lock; + DRM_SPINTYPE tsk_lock; /* Usage Counters */ int open_count; /* Outstanding files open */ @@ -933,6 +941,7 @@ atomic_t context_flag; /* Context swapping flag */ int last_context; /* Last current context */ + int vblank_disable_allowed; wait_queue_head_t *vbl_queue; /* vblank wait queue */ atomic_t *_vblank_count; /* number of VBLANK interrupts */ /* (driver must alloc the right number of counters) */ @@ -1195,8 +1204,9 @@ struct drm_file *file_priv); int drm_update_draw(struct drm_device *dev, void *data, struct drm_file *file_priv); +void drm_drawable_free_all(struct drm_device *dev); struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, - int handle); + unsigned int handle); /* Authentication IOCTL support (drm_auth.c) */ int drm_getmagic(struct drm_device *dev, void *data, Index: drm_drawable.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm/dist/bsd-core/drm_drawable.c,v retrieving revision 1.3 diff -u -b -r1.3 drm_drawable.c --- drm_drawable.c 19 Jul 2008 14:15:11 -0000 1.3 +++ drm_drawable.c 19 Jul 2008 20:02:26 -0000 @@ -35,13 +35,27 @@ #include "drmP.h" +struct bsd_drm_drawable_info; + +int drm_drawable_compare(struct bsd_drm_drawable_info *, + struct bsd_drm_drawable_info *); +void drm_drawable_free(struct drm_device *dev, + struct bsd_drm_drawable_info *draw); +struct bsd_drm_drawable_info * + drm_get_drawable(struct drm_device *, unsigned int); + +#if defined(__NetBSD__) || defined(__NetBSD__) +RB_PROTOTYPE(drawable_tree, bsd_drm_drawable_info, tree, + drm_drawable_compare); +#endif /* __NetBSD__ || __OpenBSD__ */ + struct bsd_drm_drawable_info { struct drm_drawable_info info; - int handle; + unsigned int handle; RB_ENTRY(bsd_drm_drawable_info) tree; }; -static int +int drm_drawable_compare(struct bsd_drm_drawable_info *a, struct bsd_drm_drawable_info *b) { @@ -50,23 +64,38 @@ if (a->handle < b->handle) return -1; return 0; -} +}; +#ifdef __FreeBSD__ RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree, drm_drawable_compare); +#else +RB_GENERATE(drawable_tree, bsd_drm_drawable_info, tree, + drm_drawable_compare); +#endif -struct drm_drawable_info * -drm_get_drawable_info(struct drm_device *dev, int handle) +struct bsd_drm_drawable_info * +drm_get_drawable(struct drm_device *dev, unsigned int handle) { - struct bsd_drm_drawable_info find, *result; + struct bsd_drm_drawable_info find; find.handle = handle; - result = RB_FIND(drawable_tree, &dev->drw_head, &find); + return (RB_FIND(drawable_tree, &dev->drw_head, &find)); +} + +struct drm_drawable_info * +drm_get_drawable_info(struct drm_device *dev, unsigned int handle) +{ + struct bsd_drm_drawable_info *result = NULL; + if ((result = drm_get_drawable(dev, handle))) return &result->info; + + return (NULL); } -int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_draw_t *draw = data; struct bsd_drm_drawable_info *info; @@ -79,7 +108,6 @@ #ifdef __FreeBSD__ info->handle = alloc_unr(dev->drw_unrhdr); #else - /* XXXJDM */ info->handle = ++dev->drw_no; #endif DRM_SPINLOCK(&dev->drw_lock); @@ -92,22 +120,17 @@ return 0; } -int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_draw_t *draw = (drm_draw_t *)data; - struct drm_drawable_info *info; + struct bsd_drm_drawable_info *info; DRM_SPINLOCK(&dev->drw_lock); - info = drm_get_drawable_info(dev, draw->handle); + info = drm_get_drawable(dev, draw->handle); if (info != NULL) { - RB_REMOVE(drawable_tree, &dev->drw_head, - (struct bsd_drm_drawable_info *)info); + drm_drawable_free(dev, info); DRM_SPINUNLOCK(&dev->drw_lock); -#ifdef __FreeBSD__ - free_unr(dev->drw_unrhdr, draw->handle); -#endif - drm_free(info, sizeof(struct bsd_drm_drawable_info), - DRM_MEM_DRAWABLE); return 0; } else { DRM_SPINUNLOCK(&dev->drw_lock); @@ -115,8 +138,8 @@ } } -int drm_update_draw(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int +drm_update_draw(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_drawable_info *info; struct drm_update_draw *update = (struct drm_update_draw *)data; @@ -130,6 +153,7 @@ case DRM_DRAWABLE_CLIPRECTS: DRM_SPINLOCK(&dev->drw_lock); if (update->num != info->num_rects) { + if (info->rects) drm_free(info->rects, sizeof(*info->rects) * info->num_rects, DRM_MEM_DRAWABLE); @@ -158,3 +182,37 @@ return EINVAL; } } + +void +drm_drawable_free(struct drm_device *dev, struct bsd_drm_drawable_info *draw) +{ + if (draw) { + RB_REMOVE(drawable_tree, &dev->drw_head, draw); + if (draw->info.rects) + drm_free(draw->info.rects, + sizeof(*draw->info.rects) * draw->info.num_rects, + DRM_MEM_DRAWABLE); +#ifdef __FreeBSD__ + free_unr(dev->drw_unrhdr, draw->info->handle); +#endif + drm_free(draw, sizeof(*draw), + DRM_MEM_DRAWABLE); + } +} + +void +drm_drawable_free_all(struct drm_device *dev) +{ + struct bsd_drm_drawable_info *draw, *nxt; + + DRM_SPINLOCK(&dev->drw_lock); + + for (draw = RB_MIN(drawable_tree, &dev->drw_head); draw != NULL; + draw = nxt) { + nxt = RB_NEXT(drawable_tree, &dev->drw_head, draw); + drm_drawable_free(dev, draw); + + } + DRM_SPINUNLOCK(&dev->drw_lock); + +} Index: drm_drv.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm/dist/bsd-core/drm_drv.c,v retrieving revision 1.5 diff -u -b -r1.5 drm_drv.c --- drm_drv.c 19 Jul 2008 17:44:14 -0000 1.5 +++ drm_drv.c 19 Jul 2008 20:02:26 -0000 @@ -427,6 +427,7 @@ mutex_init(&dev->irq_lock, MUTEX_DEFAULT, IPL_VM); mutex_init(&dev->vbl_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&dev->drw_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&dev->tsk_lock, MUTEX_DEFAULT, IPL_NONE); drm_attach_common(dev, pa, idlist); } @@ -733,6 +734,7 @@ DRM_SPINUNINIT(&dev->irq_lock); DRM_SPINUNINIT(&dev->vbl_lock); DRM_SPINUNINIT(&dev->drw_lock); + DRM_SPINUNINIT(&dev->tsk_lock); #endif return retcode; } @@ -792,6 +794,8 @@ #ifdef __FreeBSD__ delete_unrhdr(dev->drw_unrhdr); +#elif defined(__NetBSD__) + drm_drawable_free_all(dev); #endif drm_mem_uninit(); Index: drm_irq.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm/dist/bsd-core/drm_irq.c,v retrieving revision 1.3 diff -u -b -r1.3 drm_irq.c --- drm_irq.c 19 Jul 2008 14:15:11 -0000 1.3 +++ drm_irq.c 19 Jul 2008 20:02:26 -0000 @@ -89,9 +89,6 @@ struct drm_device *dev = (struct drm_device *)arg; int i; -#ifndef __FreeBSD__ /* XXXMRG */ - mutex_enter(&dev->vbl_lock); -#endif if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ return; @@ -102,16 +99,19 @@ } callout_deactivate(&dev->vblank_disable_timer); + if (!dev->vblank_disable_allowed) + return; + for (i = 0; i < dev->num_crtcs; i++) { if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { + DRM_DEBUG("disabling vblank on crtc %d\n", i); + dev->last_vblank[i] = + dev->driver.get_vblank_counter(dev, i); dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } } -#ifndef __FreeBSD__ /* XXXMRG */ - mutex_exit(&dev->vbl_lock); -#endif } static void drm_vblank_cleanup(struct drm_device *dev) @@ -209,6 +209,8 @@ atomic_set(&dev->vblank_refcount[i], 0); } + dev->vblank_disable_allowed = 0; + return 0; err: @@ -384,7 +386,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) { - unsigned long irqflags; u32 cur_vblank, diff; if (dev->vblank_suspend[crtc]) @@ -398,7 +399,6 @@ * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { if (cur_vblank == dev->last_vblank[crtc] - 1) { diff = 0; @@ -414,7 +414,9 @@ diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + + DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + crtc, diff); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -432,8 +434,10 @@ ret = dev->driver.enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else + else { dev->vblank_enabled[crtc] = 1; + drm_update_vblank_count(dev, crtc); + } } DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); @@ -460,6 +464,8 @@ struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; + unsigned long irqflags; + u32 new, diff; int crtc, ret = 0; crtc = modeset->crtc; @@ -470,27 +476,28 @@ switch (modeset->cmd) { case _DRM_PRE_MODESET: + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + if (!dev->vblank_enabled[crtc]) { dev->vblank_premodeset[crtc] = dev->driver.get_vblank_counter(dev, crtc); dev->vblank_suspend[crtc] = 1; + } + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { - u32 new = dev->driver.get_vblank_counter(dev, crtc); - - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) { - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); - DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" - " => _vblank_count[%d]-=0x%x\n", crtc, - dev->vblank_premodeset[crtc], new, - crtc, dev->max_vblank_count + new - - dev->vblank_premodeset[crtc]); - } + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + new = dev->driver.get_vblank_counter(dev, crtc); + if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { + if (new > dev->vblank_premodeset[crtc]) + diff = dev->vblank_premodeset[crtc] - new; + else + diff = new; + atomic_add(diff, &dev->_vblank_count[crtc]); } dev->vblank_suspend[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -524,7 +531,6 @@ if (crtc >= dev->num_crtcs) return EINVAL; - drm_update_vblank_count(dev, crtc); seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -622,7 +628,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) { - drm_update_vblank_count(dev, crtc); + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } @@ -636,35 +642,29 @@ { struct drm_device *dev = context; - DRM_LOCK(); - for (;;) { - int ret; + DRM_SPINLOCK(&dev->tsk_lock); + + DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */ + if (dev->locked_task_call == NULL || + drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) { + DRM_UNLOCK(); + DRM_SPINUNLOCK(&dev->tsk_lock); + return; + } - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) - { dev->lock.file_priv = NULL; /* kernel owned */ dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } - /* Contention */ -#if defined(__FreeBSD__) && __FreeBSD_version > 500000 - ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock, - PZERO | PCATCH, "drmlk2", 0); -#else - ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH, - "drmlk2", 0); -#endif - if (ret != 0) - return; - } DRM_UNLOCK(); dev->locked_task_call(dev); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + + dev->locked_task_call = NULL; + + DRM_SPINUNLOCK(&dev->tsk_lock); } void @@ -674,8 +674,14 @@ #if defined(__NetBSD__) static struct work drm_tasklet_wk; #endif + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + DRM_SPINUNLOCK(&dev->tsk_lock); + return; + } dev->locked_task_call = tasklet; + DRM_SPINUNLOCK(&dev->tsk_lock); #if defined(__FreeBSD__) taskqueue_enqueue(taskqueue_swi, &dev->locked_task); #elif defined(__NetBSD__) Index: drm_lock.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm/dist/bsd-core/drm_lock.c,v retrieving revision 1.2 diff -u -b -r1.2 drm_lock.c --- drm_lock.c 19 Jul 2008 06:18:23 -0000 1.2 +++ drm_lock.c 19 Jul 2008 20:02:26 -0000 @@ -183,6 +183,13 @@ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context) return EINVAL; + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + dev->locked_task_call(dev); + dev->locked_task_call = NULL; + } + DRM_SPINUNLOCK(&dev->tsk_lock); + atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); DRM_LOCK();