Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 776c9443 authored by Michel Dänzer's avatar Michel Dänzer Committed by airlied
Browse files

drm: add support for secondary vertical blank interrupt to DRM core



Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 620034c8
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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;

	/*@} */
+4 −4
Original line number Diff line number Diff line
@@ -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
+49 −23
Original line number Diff line number Diff line
@@ -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,27 +366,34 @@ 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) {
	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);
				send_sig_info(vbl_sig->info.si_signo,
					      &vbl_sig->info, vbl_sig->task);

				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--;
			}
		}
	}

	spin_unlock_irqrestore(&dev->vbl_lock, flags);
}