Loading drivers/char/drm/drmP.h +3 −0 Original line number Diff line number Diff line Loading @@ -715,6 +715,8 @@ typedef struct drm_device { drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ unsigned int vbl_pending; spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); /*@} */ cycles_t ctx_start; Loading Loading @@ -966,6 +968,7 @@ 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); extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*)); /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *drm_agp_init(drm_device_t * dev); Loading drivers/char/drm/drm_irq.c +76 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,7 @@ static int drm_irq_install(drm_device_t * dev) init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->tasklet_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs2.head); Loading Loading @@ -176,6 +177,8 @@ int drm_irq_uninstall(drm_device_t * dev) free_irq(dev->irq, dev); dev->locked_tasklet_func = NULL; return 0; } Loading Loading @@ -399,3 +402,76 @@ void drm_vbl_send_signals(drm_device_t * dev) } EXPORT_SYMBOL(drm_vbl_send_signals); /** * Tasklet wrapper function. * * \param data DRM device in disguise. * * Attempts to grab the HW lock and calls the driver callback on success. On * failure, leave the lock marked as contended so the callback can be called * from drm_unlock(). */ static void drm_locked_tasklet_func(unsigned long data) { drm_device_t *dev = (drm_device_t*)data; unsigned long irqflags; spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (!dev->locked_tasklet_func || !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; } dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); dev->locked_tasklet_func(dev); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); dev->locked_tasklet_func = NULL; spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); } /** * Schedule a tasklet to call back a driver hook with the HW lock held. * * \param dev DRM device. * \param func Driver callback. * * This is intended for triggering actions that require the HW lock from an * interrupt handler. The lock will be grabbed ASAP after the interrupt handler * completes. Note that the callback may be called from interrupt or process * context, it must not make any assumptions about this. Also, the HW lock will * be held with the kernel context or any client context. */ void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) { unsigned long irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) return; spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (dev->locked_tasklet_func) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; } dev->locked_tasklet_func = func; spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); drm_tasklet.data = (unsigned long)dev; tasklet_hi_schedule(&drm_tasklet); } EXPORT_SYMBOL(drm_locked_tasklet); drivers/char/drm/drm_lock.c +11 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; unsigned int irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; Loading @@ -165,6 +166,16 @@ int drm_unlock(struct inode *inode, struct file *filp, return -EINVAL; } spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (dev->locked_tasklet_func) { dev->locked_tasklet_func(dev); dev->locked_tasklet_func = NULL; } spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); /* kernel_context_switch isn't used by any of the x86 drm Loading Loading
drivers/char/drm/drmP.h +3 −0 Original line number Diff line number Diff line Loading @@ -715,6 +715,8 @@ typedef struct drm_device { drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ unsigned int vbl_pending; spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); /*@} */ cycles_t ctx_start; Loading Loading @@ -966,6 +968,7 @@ 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); extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*)); /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *drm_agp_init(drm_device_t * dev); Loading
drivers/char/drm/drm_irq.c +76 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,7 @@ static int drm_irq_install(drm_device_t * dev) init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->tasklet_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs2.head); Loading Loading @@ -176,6 +177,8 @@ int drm_irq_uninstall(drm_device_t * dev) free_irq(dev->irq, dev); dev->locked_tasklet_func = NULL; return 0; } Loading Loading @@ -399,3 +402,76 @@ void drm_vbl_send_signals(drm_device_t * dev) } EXPORT_SYMBOL(drm_vbl_send_signals); /** * Tasklet wrapper function. * * \param data DRM device in disguise. * * Attempts to grab the HW lock and calls the driver callback on success. On * failure, leave the lock marked as contended so the callback can be called * from drm_unlock(). */ static void drm_locked_tasklet_func(unsigned long data) { drm_device_t *dev = (drm_device_t*)data; unsigned long irqflags; spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (!dev->locked_tasklet_func || !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; } dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); dev->locked_tasklet_func(dev); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); dev->locked_tasklet_func = NULL; spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); } /** * Schedule a tasklet to call back a driver hook with the HW lock held. * * \param dev DRM device. * \param func Driver callback. * * This is intended for triggering actions that require the HW lock from an * interrupt handler. The lock will be grabbed ASAP after the interrupt handler * completes. Note that the callback may be called from interrupt or process * context, it must not make any assumptions about this. Also, the HW lock will * be held with the kernel context or any client context. */ void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) { unsigned long irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) return; spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (dev->locked_tasklet_func) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; } dev->locked_tasklet_func = func; spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); drm_tasklet.data = (unsigned long)dev; tasklet_hi_schedule(&drm_tasklet); } EXPORT_SYMBOL(drm_locked_tasklet);
drivers/char/drm/drm_lock.c +11 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; unsigned int irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; Loading @@ -165,6 +166,16 @@ int drm_unlock(struct inode *inode, struct file *filp, return -EINVAL; } spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (dev->locked_tasklet_func) { dev->locked_tasklet_func(dev); dev->locked_tasklet_func = NULL; } spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); /* kernel_context_switch isn't used by any of the x86 drm Loading