mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
drm: add support for secondary vertical blank interrupt to DRM core
Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
parent
620034c84d
commit
776c9443e2
4 changed files with 60 additions and 28 deletions
|
@ -465,10 +465,12 @@ typedef struct drm_irq_busid {
|
|||
typedef enum {
|
||||
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
|
||||
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
|
||||
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
|
||||
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
|
||||
} drm_vblank_seq_type_t;
|
||||
|
||||
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
|
||||
#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
|
||||
#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY)
|
||||
|
||||
struct drm_wait_vblank_request {
|
||||
drm_vblank_seq_type_t type;
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#define DRIVER_IRQ_VBL 0x100
|
||||
#define DRIVER_DMA_QUEUE 0x200
|
||||
#define DRIVER_FB_DMA 0x400
|
||||
#define DRIVER_IRQ_VBL2 0x800
|
||||
|
||||
/***********************************************************************/
|
||||
/** \name Begin the DRM... */
|
||||
|
@ -562,6 +563,7 @@ struct drm_driver {
|
|||
void (*kernel_context_switch_unlock) (struct drm_device * dev,
|
||||
drm_lock_t *lock);
|
||||
int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
|
||||
int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence);
|
||||
int (*dri_library_name) (struct drm_device *dev, char *buf);
|
||||
|
||||
/**
|
||||
|
@ -708,8 +710,10 @@ typedef struct drm_device {
|
|||
|
||||
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
|
||||
atomic_t vbl_received;
|
||||
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
|
||||
spinlock_t vbl_lock;
|
||||
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;
|
||||
|
||||
/*@} */
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
|
||||
#define CORE_NAME "drm"
|
||||
#define CORE_DESC "DRM shared core routines"
|
||||
#define CORE_DATE "20051102"
|
||||
#define CORE_DATE "20060810"
|
||||
|
||||
#define DRM_IF_MAJOR 1
|
||||
#define DRM_IF_MINOR 2
|
||||
#define DRM_IF_MINOR 3
|
||||
|
||||
#define CORE_MAJOR 1
|
||||
#define CORE_MINOR 0
|
||||
#define CORE_PATCHLEVEL 1
|
||||
#define CORE_MINOR 1
|
||||
#define CORE_PATCHLEVEL 0
|
||||
|
|
|
@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
|
|||
spin_lock_init(&dev->vbl_lock);
|
||||
|
||||
INIT_LIST_HEAD(&dev->vbl_sigs.head);
|
||||
INIT_LIST_HEAD(&dev->vbl_sigs2.head);
|
||||
|
||||
dev->vbl_pending = 0;
|
||||
}
|
||||
|
@ -248,9 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
struct timeval now;
|
||||
int ret = 0;
|
||||
unsigned int flags;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
|
||||
return -EINVAL;
|
||||
atomic_t *seq;
|
||||
|
||||
if (!dev->irq)
|
||||
return -EINVAL;
|
||||
|
@ -258,9 +257,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
|
||||
if (vblwait.request.type &
|
||||
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
|
||||
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
|
||||
vblwait.request.type,
|
||||
(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
|
||||
|
||||
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
|
||||
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
|
||||
return -EINVAL;
|
||||
|
||||
seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 :
|
||||
&dev->vbl_received;
|
||||
|
||||
switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
|
||||
case _DRM_VBLANK_RELATIVE:
|
||||
vblwait.request.sequence += atomic_read(&dev->vbl_received);
|
||||
vblwait.request.sequence += atomic_read(seq);
|
||||
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
|
||||
case _DRM_VBLANK_ABSOLUTE:
|
||||
break;
|
||||
|
@ -268,13 +284,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
|
||||
|
||||
if (flags & _DRM_VBLANK_SIGNAL) {
|
||||
unsigned long irqflags;
|
||||
drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
|
||||
? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||
drm_vbl_sig_t *vbl_sig;
|
||||
|
||||
vblwait.reply.sequence = atomic_read(&dev->vbl_received);
|
||||
vblwait.reply.sequence = atomic_read(seq);
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
|
||||
|
@ -282,7 +298,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
* for the same vblank sequence number; nothing to be done in
|
||||
* that case
|
||||
*/
|
||||
list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) {
|
||||
list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
|
||||
if (vbl_sig->sequence == vblwait.request.sequence
|
||||
&& vbl_sig->info.si_signo == vblwait.request.signal
|
||||
&& vbl_sig->task == current) {
|
||||
|
@ -315,11 +331,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
|
||||
list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head);
|
||||
list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
|
||||
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
} else {
|
||||
if (dev->driver->vblank_wait)
|
||||
if (flags & _DRM_VBLANK_SECONDARY) {
|
||||
if (dev->driver->vblank_wait2)
|
||||
ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
|
||||
} else if (dev->driver->vblank_wait)
|
||||
ret =
|
||||
dev->driver->vblank_wait(dev,
|
||||
&vblwait.request.sequence);
|
||||
|
@ -347,25 +366,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
*/
|
||||
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;
|
||||
int i;
|
||||
|
||||
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);
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct list_head *list, *tmp;
|
||||
drm_vbl_sig_t *vbl_sig;
|
||||
drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||
unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
|
||||
&dev->vbl_received);
|
||||
|
||||
list_del(list);
|
||||
list_for_each_safe(list, tmp, &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);
|
||||
|
||||
drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
|
||||
list_del(list);
|
||||
|
||||
dev->vbl_pending--;
|
||||
drm_free(vbl_sig, sizeof(*vbl_sig),
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
dev->vbl_pending--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue