Skip to content

Commit

Permalink
drm: add support for secondary vertical blank interrupt to DRM core
Browse files Browse the repository at this point in the history
Signed-off-by: Dave Airlie <airlied@linux.ie>
  • Loading branch information
=?utf-8?q?Michel_D=C3=A4nzer?= authored and airlied committed Dec 7, 2006
1 parent 620034c commit 776c944
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 28 deletions.
4 changes: 3 additions & 1 deletion drivers/char/drm/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/char/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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... */
Expand Down Expand Up @@ -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);

/**
Expand Down Expand Up @@ -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;

/*@} */
Expand Down
8 changes: 4 additions & 4 deletions drivers/char/drm/drm_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
72 changes: 49 additions & 23 deletions drivers/char/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -248,41 +249,56 @@ 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;

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;
default:
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);

/* Check if this task has already scheduled the same signal
* 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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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_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);

list_del(list);
list_del(list);

drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
drm_free(vbl_sig, sizeof(*vbl_sig),
DRM_MEM_DRIVER);

dev->vbl_pending--;
dev->vbl_pending--;
}
}
}

Expand Down

0 comments on commit 776c944

Please sign in to comment.