drm_irq.c revision 189052
176116Sdcs/*-
276116Sdcs * Copyright 2003 Eric Anholt
376116Sdcs * All Rights Reserved.
476116Sdcs *
576116Sdcs * Permission is hereby granted, free of charge, to any person obtaining a
694290Sdcs * copy of this software and associated documentation files (the "Software"),
776116Sdcs * to deal in the Software without restriction, including without limitation
876116Sdcs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
976116Sdcs * and/or sell copies of the Software, and to permit persons to whom the
1076116Sdcs * Software is furnished to do so, subject to the following conditions:
1176116Sdcs *
1276116Sdcs * The above copyright notice and this permission notice (including the next
1376116Sdcs * paragraph) shall be included in all copies or substantial portions of the
1494290Sdcs * Software.
1594290Sdcs *
1694290Sdcs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1794290Sdcs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1894290Sdcs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1976116Sdcs * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
2076116Sdcs * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2176116Sdcs * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2276116Sdcs *
2376116Sdcs * Authors:
2476116Sdcs *    Eric Anholt <anholt@FreeBSD.org>
2576116Sdcs *
2676116Sdcs */
2776116Sdcs
2876116Sdcs#include <sys/cdefs.h>
2976116Sdcs__FBSDID("$FreeBSD: head/sys/dev/drm/drm_irq.c 189052 2009-02-25 18:54:35Z rnoland $");
3076116Sdcs
3176116Sdcs/** @file drm_irq.c
3276116Sdcs * Support code for handling setup/teardown of interrupt handlers and
3376116Sdcs * handing interrupt handlers off to the drivers.
3476116Sdcs */
3576116Sdcs
3676116Sdcs#include "dev/drm/drmP.h"
3776116Sdcs#include "dev/drm/drm.h"
3876116Sdcs
3976116Sdcsint drm_irq_by_busid(struct drm_device *dev, void *data,
4076116Sdcs		     struct drm_file *file_priv)
4194290Sdcs{
4294290Sdcs	struct drm_irq_busid *irq = data;
4394290Sdcs
4494290Sdcs	if ((irq->busnum >> 8) != dev->pci_domain ||
4594290Sdcs	    (irq->busnum & 0xff) != dev->pci_bus ||
4694290Sdcs	    irq->devnum != dev->pci_slot ||
4794290Sdcs	    irq->funcnum != dev->pci_func)
4894290Sdcs		return EINVAL;
4994290Sdcs
5076116Sdcs	irq->irq = dev->irq;
5194290Sdcs
5294290Sdcs	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
5394290Sdcs	    irq->busnum, irq->devnum, irq->funcnum, irq->irq);
5494290Sdcs
5576116Sdcs	return 0;
5676116Sdcs}
5776116Sdcs
5876116Sdcsstatic irqreturn_t
5976116Sdcsdrm_irq_handler_wrap(DRM_IRQ_ARGS)
6076116Sdcs{
6176116Sdcs	struct drm_device *dev = arg;
6276116Sdcs
6376116Sdcs	DRM_SPINLOCK(&dev->irq_lock);
6476116Sdcs	dev->driver->irq_handler(arg);
6576116Sdcs	DRM_SPINUNLOCK(&dev->irq_lock);
6676116Sdcs}
6776116Sdcs
6876116Sdcsstatic void vblank_disable_fn(void *arg)
6976116Sdcs{
7076116Sdcs	struct drm_device *dev = (struct drm_device *)arg;
7176116Sdcs	int i;
7276116Sdcs
7376116Sdcs	if (callout_pending(&dev->vblank_disable_timer)) {
7476116Sdcs		/* callout was reset */
7576116Sdcs		return;
7694290Sdcs	}
7776116Sdcs	if (!callout_active(&dev->vblank_disable_timer)) {
7876116Sdcs		/* callout was stopped */
7976116Sdcs		return;
8094290Sdcs	}
8194290Sdcs	callout_deactivate(&dev->vblank_disable_timer);
8294290Sdcs
8376116Sdcs	DRM_DEBUG("vblank_disable_allowed=%d\n", dev->vblank_disable_allowed);
8494290Sdcs	if (!dev->vblank_disable_allowed)
8594290Sdcs		return;
8676116Sdcs
8794290Sdcs	for (i = 0; i < dev->num_crtcs; i++) {
8876116Sdcs		if (atomic_read(&dev->vblank[i].refcount) == 0 &&
8994290Sdcs		    dev->vblank[i].enabled) {
9076116Sdcs			DRM_DEBUG("disabling vblank on crtc %d\n", i);
9176116Sdcs			dev->vblank[i].last =
9276116Sdcs			    dev->driver->get_vblank_counter(dev, i);
9376116Sdcs			dev->driver->disable_vblank(dev, i);
9476116Sdcs			dev->vblank[i].enabled = 0;
9576116Sdcs		}
9694290Sdcs	}
9794290Sdcs}
9894290Sdcs
9994290Sdcsstatic void drm_vblank_cleanup(struct drm_device *dev)
10094290Sdcs{
10194290Sdcs	unsigned long irqflags;
10294290Sdcs
10394290Sdcs	/* Bail if the driver didn't call drm_vblank_init() */
10494290Sdcs	if (dev->num_crtcs == 0)
10594290Sdcs		return;
10694290Sdcs
10776116Sdcs	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
10876116Sdcs	callout_stop(&dev->vblank_disable_timer);
10976116Sdcs	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
11076116Sdcs
11176116Sdcs	callout_drain(&dev->vblank_disable_timer);
11294290Sdcs
11394290Sdcs	vblank_disable_fn((void *)dev);
11476116Sdcs
11576116Sdcs	free(dev->vblank, DRM_MEM_DRIVER);
11676116Sdcs
11776116Sdcs	dev->num_crtcs = 0;
11876116Sdcs}
11976116Sdcs
12076116Sdcsint drm_vblank_init(struct drm_device *dev, int num_crtcs)
12176116Sdcs{
12294290Sdcs	int i, ret = ENOMEM;
12394290Sdcs
12494290Sdcs	callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0);
12594290Sdcs	atomic_set(&dev->vbl_signal_pending, 0);
12694290Sdcs	dev->num_crtcs = num_crtcs;
12794290Sdcs
12894290Sdcs	dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs,
12994290Sdcs	    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
13094290Sdcs	if (!dev->vblank)
13194290Sdcs	    goto err;
13276116Sdcs
13376116Sdcs	DRM_DEBUG("\n");
13476116Sdcs
13594290Sdcs	/* Zero per-crtc vblank stuff */
13676116Sdcs	for (i = 0; i < num_crtcs; i++) {
13776116Sdcs		DRM_INIT_WAITQUEUE(&dev->vblank[i].queue);
13876116Sdcs		TAILQ_INIT(&dev->vblank[i].sigs);
13976116Sdcs		atomic_set(&dev->vblank[i].count, 0);
14076116Sdcs		atomic_set(&dev->vblank[i].refcount, 0);
14194290Sdcs	}
14276116Sdcs
14376116Sdcs	dev->vblank_disable_allowed = 0;
14476116Sdcs
14594290Sdcs	return 0;
14694290Sdcs
14794290Sdcserr:
14894290Sdcs	drm_vblank_cleanup(dev);
14994290Sdcs	return ret;
15094290Sdcs}
15194290Sdcs
15294290Sdcsint drm_irq_install(struct drm_device *dev)
15394290Sdcs{
15494290Sdcs	int retcode;
15594290Sdcs
15694290Sdcs	if (dev->irq == 0 || dev->dev_private == NULL)
15794290Sdcs		return EINVAL;
15894290Sdcs
15994290Sdcs	DRM_DEBUG("irq=%d\n", dev->irq);
16094290Sdcs
16194290Sdcs	DRM_LOCK();
16294290Sdcs	if (dev->irq_enabled) {
16394290Sdcs		DRM_UNLOCK();
16494290Sdcs		return EBUSY;
16594290Sdcs	}
16694290Sdcs	dev->irq_enabled = 1;
16794290Sdcs
16894290Sdcs	dev->context_flag = 0;
16994290Sdcs
17094290Sdcs	/* Before installing handler */
17194290Sdcs	dev->driver->irq_preinstall(dev);
17294290Sdcs	DRM_UNLOCK();
17394290Sdcs
17494290Sdcs	/* Install handler */
17576116Sdcs#if __FreeBSD_version >= 700031
17676116Sdcs	retcode = bus_setup_intr(dev->device, dev->irqr,
17776116Sdcs				 INTR_TYPE_TTY | INTR_MPSAFE,
17876116Sdcs				 NULL, drm_irq_handler_wrap, dev, &dev->irqh);
17976116Sdcs#else
18076116Sdcs	retcode = bus_setup_intr(dev->device, dev->irqr,
18176116Sdcs				 INTR_TYPE_TTY | INTR_MPSAFE,
18276116Sdcs				 drm_irq_handler_wrap, dev, &dev->irqh);
18376116Sdcs#endif
18476116Sdcs	if (retcode != 0)
18576116Sdcs		goto err;
18676116Sdcs
18776116Sdcs	/* After installing handler */
18876116Sdcs	DRM_LOCK();
18994290Sdcs	dev->driver->irq_postinstall(dev);
19094290Sdcs	DRM_UNLOCK();
19194290Sdcs
19294290Sdcs	return 0;
19376116Sdcserr:
19476116Sdcs	DRM_LOCK();
19576116Sdcs	dev->irq_enabled = 0;
19676116Sdcs	DRM_UNLOCK();
19776116Sdcs
19876116Sdcs	return retcode;
19994290Sdcs}
20094290Sdcs
20194290Sdcsint drm_irq_uninstall(struct drm_device *dev)
20294290Sdcs{
20394290Sdcs	if (!dev->irq_enabled)
204264262Semaste		return EINVAL;
20594290Sdcs
20694290Sdcs	dev->irq_enabled = 0;
20776116Sdcs
20876116Sdcs	DRM_DEBUG("irq=%d\n", dev->irq);
20976116Sdcs
21076116Sdcs	dev->driver->irq_uninstall(dev);
21176116Sdcs
21276116Sdcs	DRM_UNLOCK();
21376116Sdcs	bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
21476116Sdcs	DRM_LOCK();
21594290Sdcs
21676116Sdcs	drm_vblank_cleanup(dev);
21776116Sdcs
21894290Sdcs	return 0;
219249223Skientzle}
22076116Sdcs
22176116Sdcsint drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
222249223Skientzle{
223249223Skientzle	struct drm_control *ctl = data;
22476116Sdcs	int err;
22576116Sdcs
22676116Sdcs	switch (ctl->func) {
22776116Sdcs	case DRM_INST_HANDLER:
22876116Sdcs		/* Handle drivers whose DRM used to require IRQ setup but the
22994290Sdcs		 * no longer does.
23076116Sdcs		 */
23176116Sdcs		if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
23294290Sdcs			return 0;
23394290Sdcs		if (dev->if_version < DRM_IF_VERSION(1, 2) &&
23494290Sdcs		    ctl->irq != dev->irq)
23594290Sdcs			return EINVAL;
23694290Sdcs		return drm_irq_install(dev);
23794290Sdcs	case DRM_UNINST_HANDLER:
23894290Sdcs		if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
23976116Sdcs			return 0;
24076116Sdcs		DRM_LOCK();
24176116Sdcs		err = drm_irq_uninstall(dev);
242264262Semaste		DRM_UNLOCK();
24376116Sdcs		return err;
244264262Semaste	default:
24594290Sdcs		return EINVAL;
24676116Sdcs	}
24776116Sdcs}
248167850Sjkim
249264262Semasteu32 drm_vblank_count(struct drm_device *dev, int crtc)
250167850Sjkim{
251264262Semaste	return atomic_read(&dev->vblank[crtc].count);
25276116Sdcs}
253264262Semaste
25476116Sdcsstatic void drm_update_vblank_count(struct drm_device *dev, int crtc)
25576116Sdcs{
256167850Sjkim	u32 cur_vblank, diff;
257167850Sjkim
258264262Semaste	/*
259167850Sjkim	 * Interrupts were disabled prior to this call, so deal with counter
260167850Sjkim	 * wrap if needed.
26176116Sdcs	 * NOTE!  It's possible we lost a full dev->max_vblank_count events
26276116Sdcs	 * here if the register is small or we had vblank interrupts off for
263264262Semaste	 * a long time.
26476116Sdcs	 */
26576116Sdcs	cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
26676116Sdcs	diff = cur_vblank - dev->vblank[crtc].last;
267264262Semaste	if (cur_vblank < dev->vblank[crtc].last) {
26876116Sdcs		diff += dev->max_vblank_count;
26976116Sdcs
27076116Sdcs		DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n",
271264262Semaste		    crtc, dev->vblank[crtc].last, cur_vblank, diff);
27276116Sdcs	}
27376116Sdcs
27476116Sdcs	DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
275264262Semaste	    crtc, diff);
27676116Sdcs
27776116Sdcs	atomic_add(diff, &dev->vblank[crtc].count);
27894290Sdcs}
27976116Sdcs
28076116Sdcsint drm_vblank_get(struct drm_device *dev, int crtc)
28176116Sdcs{
28276116Sdcs	unsigned long irqflags;
28376116Sdcs	int ret = 0;
28476116Sdcs
285249223Skientzle	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
28676116Sdcs	/* Going from 0->1 means we have to enable interrupts again */
28794290Sdcs	atomic_add_acq_int(&dev->vblank[crtc].refcount, 1);
28894290Sdcs	DRM_DEBUG("vblank refcount = %d\n", dev->vblank[crtc].refcount);
28976116Sdcs	if (dev->vblank[crtc].refcount == 1 &&
29076116Sdcs	    !dev->vblank[crtc].enabled) {
29176116Sdcs		ret = dev->driver->enable_vblank(dev, crtc);
29276116Sdcs		if (ret)
29376116Sdcs			atomic_dec(&dev->vblank[crtc].refcount);
29476116Sdcs		else {
29576116Sdcs			dev->vblank[crtc].enabled = 1;
29676116Sdcs			drm_update_vblank_count(dev, crtc);
29776116Sdcs		}
29876116Sdcs	}
29976116Sdcs	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
30076116Sdcs
30176116Sdcs	return ret;
30276116Sdcs}
30376116Sdcs
30476116Sdcsvoid drm_vblank_put(struct drm_device *dev, int crtc)
30576116Sdcs{
30676116Sdcs	unsigned long irqflags;
30776116Sdcs
30876116Sdcs	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
30976116Sdcs	/* Last user schedules interrupt disable */
31076116Sdcs	atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1);
31176116Sdcs	DRM_DEBUG("vblank refcount = %d\n", dev->vblank[crtc].refcount);
31276116Sdcs	if (dev->vblank[crtc].refcount == 0)
31376116Sdcs	    callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
31476116Sdcs		(timeout_t *)vblank_disable_fn, (void *)dev);
31576116Sdcs	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
31676116Sdcs}
31776116Sdcs
31876116Sdcsint drm_modeset_ctl(struct drm_device *dev, void *data,
31976116Sdcs		    struct drm_file *file_priv)
32076116Sdcs{
32176116Sdcs	struct drm_modeset_ctl *modeset = data;
32276116Sdcs	unsigned long irqflags;
32376116Sdcs	int crtc, ret = 0;
32476116Sdcs
32576116Sdcs	DRM_DEBUG("num_crtcs=%d\n", dev->num_crtcs);
32676116Sdcs	/* If drm_vblank_init() hasn't been called yet, just no-op */
32776116Sdcs	if (!dev->num_crtcs)
328249223Skientzle		goto out;
329249223Skientzle
33076116Sdcs	crtc = modeset->crtc;
33176116Sdcs	DRM_DEBUG("crtc=%d\n", crtc);
33276116Sdcs	if (crtc >= dev->num_crtcs) {
33394290Sdcs		ret = EINVAL;
33476116Sdcs		goto out;
335249223Skientzle	}
336249223Skientzle
33776116Sdcs	/*
33876116Sdcs	 * To avoid all the problems that might happen if interrupts
33994290Sdcs	 * were enabled/disabled around or between these calls, we just
34076116Sdcs	 * have the kernel take a reference on the CRTC (just once though
34176116Sdcs	 * to avoid corrupting the count if multiple, mismatch calls occur),
342249223Skientzle	 * so that interrupts remain enabled in the interim.
343249223Skientzle	 */
34476116Sdcs	switch (modeset->cmd) {
34576116Sdcs	case _DRM_PRE_MODESET:
34676116Sdcs		DRM_DEBUG("pre-modeset\n");
34794290Sdcs		if (!dev->vblank[crtc].inmodeset) {
34894290Sdcs			dev->vblank[crtc].inmodeset = 1;
34976116Sdcs			drm_vblank_get(dev, crtc);
35076116Sdcs		}
35176116Sdcs		break;
35276116Sdcs	case _DRM_POST_MODESET:
35376116Sdcs		DRM_DEBUG("post-modeset\n");
35476116Sdcs		if (dev->vblank[crtc].inmodeset) {
35576116Sdcs			DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
35676116Sdcs			dev->vblank_disable_allowed = 1;
35776116Sdcs			dev->vblank[crtc].inmodeset = 0;
35876116Sdcs			DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
35976116Sdcs			drm_vblank_put(dev, crtc);
36076116Sdcs		}
36176116Sdcs		break;
36276116Sdcs	default:
36376116Sdcs		ret = EINVAL;
36476116Sdcs		break;
36576116Sdcs	}
36676116Sdcs
36776116Sdcsout:
36876116Sdcs	return ret;
36976116Sdcs}
37076116Sdcs
37176116Sdcsint drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
37276116Sdcs{
37376116Sdcs	union drm_wait_vblank *vblwait = data;
37476116Sdcs	unsigned int flags, seq, crtc;
37576116Sdcs	int ret = 0;
37676116Sdcs
37776116Sdcs	if (!dev->irq_enabled)
37876116Sdcs		return EINVAL;
37976116Sdcs
38076116Sdcs	if (vblwait->request.type &
38176116Sdcs	    ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
38276116Sdcs		DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
38376116Sdcs		    vblwait->request.type,
38476116Sdcs		    (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
38576116Sdcs		return EINVAL;
38676116Sdcs	}
38776116Sdcs
38876116Sdcs	flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
38976116Sdcs	crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
39076116Sdcs
39176116Sdcs	if (crtc >= dev->num_crtcs)
39276116Sdcs		return EINVAL;
39376116Sdcs
39476116Sdcs	ret = drm_vblank_get(dev, crtc);
39576116Sdcs	if (ret) {
39676116Sdcs		DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
39776116Sdcs		return ret;
39894290Sdcs	}
39976116Sdcs	seq = drm_vblank_count(dev, crtc);
40076116Sdcs
40176116Sdcs	switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
40276116Sdcs	case _DRM_VBLANK_RELATIVE:
40376116Sdcs		vblwait->request.sequence += seq;
40476116Sdcs		vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
40576116Sdcs	case _DRM_VBLANK_ABSOLUTE:
40676116Sdcs		break;
40776116Sdcs	default:
40876116Sdcs		ret = EINVAL;
40976116Sdcs		goto done;
41076116Sdcs	}
41176116Sdcs
41276116Sdcs	if ((flags & _DRM_VBLANK_NEXTONMISS) &&
41376116Sdcs	    (seq - vblwait->request.sequence) <= (1<<23)) {
41476116Sdcs		vblwait->request.sequence = seq + 1;
41576116Sdcs	}
41676116Sdcs
41776116Sdcs	if (flags & _DRM_VBLANK_SIGNAL) {
41876116Sdcs#if 0 /* disabled */
41976116Sdcs		drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t),
42076116Sdcs		    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
42176116Sdcs		if (vbl_sig == NULL)
42276116Sdcs			return ENOMEM;
42376116Sdcs
42476116Sdcs		vbl_sig->sequence = vblwait->request.sequence;
42576116Sdcs		vbl_sig->signo = vblwait->request.signal;
42676116Sdcs		vbl_sig->pid = DRM_CURRENTPID;
42776116Sdcs
42894290Sdcs		vblwait->reply.sequence = atomic_read(&dev->vbl_received);
42976116Sdcs
43076116Sdcs		DRM_SPINLOCK(&dev->vbl_lock);
43176116Sdcs		TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
43276116Sdcs		DRM_SPINUNLOCK(&dev->vbl_lock);
43376116Sdcs		ret = 0;
43476116Sdcs#endif
43576116Sdcs		ret = EINVAL;
43676116Sdcs	} else {
43776116Sdcs		DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
43876116Sdcs		    vblwait->request.sequence, crtc);
43976116Sdcs		for ( ret = 0 ; !ret && !((drm_vblank_count(dev, crtc) -
44076116Sdcs		    vblwait->request.sequence) <= (1 << 23)) ; ) {
44176116Sdcs			mtx_lock(&dev->irq_lock);
44276116Sdcs			if (!((drm_vblank_count(dev, crtc) -
44376116Sdcs			    vblwait->request.sequence) <= (1 << 23)))
44476116Sdcs				ret = mtx_sleep(&dev->vblank[crtc].queue,
44594290Sdcs				    &dev->irq_lock, PCATCH, "vblwtq",
44676116Sdcs				    3 * DRM_HZ);
44776116Sdcs			mtx_unlock(&dev->irq_lock);
44876116Sdcs		}
44976116Sdcs
45076116Sdcs		DRM_DEBUG("return = %d\n", ret);
45176116Sdcs		if (ret != EINTR) {
45276116Sdcs			struct timeval now;
45376116Sdcs
45476116Sdcs			microtime(&now);
45576116Sdcs			vblwait->reply.tval_sec = now.tv_sec;
45676116Sdcs			vblwait->reply.tval_usec = now.tv_usec;
45776116Sdcs			vblwait->reply.sequence = drm_vblank_count(dev, crtc);
45876116Sdcs			DRM_DEBUG("returning %d to client\n",
45994290Sdcs			    vblwait->reply.sequence);
46094290Sdcs		} else {
46176116Sdcs			DRM_DEBUG("vblank wait interrupted by signal\n");
46276116Sdcs		}
46376116Sdcs	}
46476116Sdcs
46576116Sdcsdone:
46676116Sdcs	drm_vblank_put(dev, crtc);
46776116Sdcs	return ret;
46876116Sdcs}
46976116Sdcs
47076116Sdcsvoid drm_vbl_send_signals(struct drm_device *dev, int crtc)
47176116Sdcs{
47276116Sdcs}
47376116Sdcs
47476116Sdcs#if 0 /* disabled */
47576116Sdcsvoid drm_vbl_send_signals(struct drm_device *dev, int crtc )
47676116Sdcs{
47776116Sdcs	drm_vbl_sig_t *vbl_sig;
47876116Sdcs	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
47976116Sdcs	struct proc *p;
48076116Sdcs
48176116Sdcs	vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
48276116Sdcs	while (vbl_sig != NULL) {
48376116Sdcs		drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
48476116Sdcs
48576116Sdcs		if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
48676116Sdcs			p = pfind(vbl_sig->pid);
48776116Sdcs			if (p != NULL)
48876116Sdcs				psignal(p, vbl_sig->signo);
48976116Sdcs
49076116Sdcs			TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
49176116Sdcs			DRM_FREE(vbl_sig,sizeof(*vbl_sig));
49276116Sdcs		}
49376116Sdcs		vbl_sig = next;
49476116Sdcs	}
49576116Sdcs}
49676116Sdcs#endif
49794290Sdcs
49894290Sdcsvoid drm_handle_vblank(struct drm_device *dev, int crtc)
49976116Sdcs{
50076116Sdcs	atomic_inc(&dev->vblank[crtc].count);
50176116Sdcs	DRM_WAKEUP(&dev->vblank[crtc].queue);
50276116Sdcs	drm_vbl_send_signals(dev, crtc);
50376116Sdcs}
50494290Sdcs
50594290Sdcs