drm: add support for secondary vertical blank interrupt to DRM core
Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
Родитель
620034c84d
Коммит
776c9443e2
|
@ -465,10 +465,12 @@ typedef struct drm_irq_busid {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
|
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
|
||||||
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
|
_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_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
|
||||||
} drm_vblank_seq_type_t;
|
} 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 {
|
struct drm_wait_vblank_request {
|
||||||
drm_vblank_seq_type_t type;
|
drm_vblank_seq_type_t type;
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
#define DRIVER_IRQ_VBL 0x100
|
#define DRIVER_IRQ_VBL 0x100
|
||||||
#define DRIVER_DMA_QUEUE 0x200
|
#define DRIVER_DMA_QUEUE 0x200
|
||||||
#define DRIVER_FB_DMA 0x400
|
#define DRIVER_FB_DMA 0x400
|
||||||
|
#define DRIVER_IRQ_VBL2 0x800
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/** \name Begin the DRM... */
|
/** \name Begin the DRM... */
|
||||||
|
@ -562,6 +563,7 @@ struct drm_driver {
|
||||||
void (*kernel_context_switch_unlock) (struct drm_device * dev,
|
void (*kernel_context_switch_unlock) (struct drm_device * dev,
|
||||||
drm_lock_t *lock);
|
drm_lock_t *lock);
|
||||||
int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
|
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);
|
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 */
|
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
|
||||||
atomic_t vbl_received;
|
atomic_t vbl_received;
|
||||||
|
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
|
||||||
spinlock_t vbl_lock;
|
spinlock_t vbl_lock;
|
||||||
drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */
|
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;
|
unsigned int vbl_pending;
|
||||||
|
|
||||||
/*@} */
|
/*@} */
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
|
|
||||||
#define CORE_NAME "drm"
|
#define CORE_NAME "drm"
|
||||||
#define CORE_DESC "DRM shared core routines"
|
#define CORE_DESC "DRM shared core routines"
|
||||||
#define CORE_DATE "20051102"
|
#define CORE_DATE "20060810"
|
||||||
|
|
||||||
#define DRM_IF_MAJOR 1
|
#define DRM_IF_MAJOR 1
|
||||||
#define DRM_IF_MINOR 2
|
#define DRM_IF_MINOR 3
|
||||||
|
|
||||||
#define CORE_MAJOR 1
|
#define CORE_MAJOR 1
|
||||||
#define CORE_MINOR 0
|
#define CORE_MINOR 1
|
||||||
#define CORE_PATCHLEVEL 1
|
#define CORE_PATCHLEVEL 0
|
||||||
|
|
|
@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
|
||||||
spin_lock_init(&dev->vbl_lock);
|
spin_lock_init(&dev->vbl_lock);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dev->vbl_sigs.head);
|
INIT_LIST_HEAD(&dev->vbl_sigs.head);
|
||||||
|
INIT_LIST_HEAD(&dev->vbl_sigs2.head);
|
||||||
|
|
||||||
dev->vbl_pending = 0;
|
dev->vbl_pending = 0;
|
||||||
}
|
}
|
||||||
|
@ -248,9 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
atomic_t *seq;
|
||||||
if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!dev->irq)
|
if (!dev->irq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -258,9 +257,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||||
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
|
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
|
||||||
return -EFAULT;
|
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:
|
case _DRM_VBLANK_RELATIVE:
|
||||||
vblwait.request.sequence += atomic_read(&dev->vbl_received);
|
vblwait.request.sequence += atomic_read(seq);
|
||||||
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
|
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
|
||||||
case _DRM_VBLANK_ABSOLUTE:
|
case _DRM_VBLANK_ABSOLUTE:
|
||||||
break;
|
break;
|
||||||
|
@ -268,13 +284,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
|
|
||||||
|
|
||||||
if (flags & _DRM_VBLANK_SIGNAL) {
|
if (flags & _DRM_VBLANK_SIGNAL) {
|
||||||
unsigned long irqflags;
|
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;
|
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);
|
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
|
* for the same vblank sequence number; nothing to be done in
|
||||||
* that case
|
* 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
|
if (vbl_sig->sequence == vblwait.request.sequence
|
||||||
&& vbl_sig->info.si_signo == vblwait.request.signal
|
&& vbl_sig->info.si_signo == vblwait.request.signal
|
||||||
&& vbl_sig->task == current) {
|
&& vbl_sig->task == current) {
|
||||||
|
@ -315,11 +331,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
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);
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||||
} else {
|
} 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 =
|
ret =
|
||||||
dev->driver->vblank_wait(dev,
|
dev->driver->vblank_wait(dev,
|
||||||
&vblwait.request.sequence);
|
&vblwait.request.sequence);
|
||||||
|
@ -347,25 +366,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||||
*/
|
*/
|
||||||
void drm_vbl_send_signals(drm_device_t * dev)
|
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;
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->vbl_lock, flags);
|
spin_lock_irqsave(&dev->vbl_lock, flags);
|
||||||
|
|
||||||
list_for_each_safe(list, tmp, &dev->vbl_sigs.head) {
|
for (i = 0; i < 2; i++) {
|
||||||
vbl_sig = list_entry(list, drm_vbl_sig_t, head);
|
struct list_head *list, *tmp;
|
||||||
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
drm_vbl_sig_t *vbl_sig;
|
||||||
vbl_sig->info.si_code = vbl_seq;
|
drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||||
send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info,
|
unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
|
||||||
vbl_sig->task);
|
&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--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче