summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2015-09-26 19:52:16 +0000
committerkettenis <kettenis@openbsd.org>2015-09-26 19:52:16 +0000
commit1fdfe5bacc2287be0bfda625ba86dfdc0ae51e8e (patch)
tree42fc47e98a5992ec91435b04949b06f843c6baae
parentProtect the list of free map entries with a mutex. This should fix the (diff)
downloadwireguard-openbsd-1fdfe5bacc2287be0bfda625ba86dfdc0ae51e8e.tar.xz
wireguard-openbsd-1fdfe5bacc2287be0bfda625ba86dfdc0ae51e8e.zip
Update drm_irq.c to the version from Linux 3.14.52.
Disable the DRM_IOCTL_IRQ_BUSID and DRM_IOCTL_CONTROL ioctls. These are legacy ioctls for DRI1 support, which we no longer support on OpenBSD.
-rw-r--r--sys/dev/pci/drm/drmP.h125
-rw-r--r--sys/dev/pci/drm/drm_drv.c66
-rw-r--r--sys/dev/pci/drm/drm_irq.c490
-rw-r--r--sys/dev/pci/drm/drm_linux.h39
-rw-r--r--sys/dev/pci/drm/drm_trace.h63
-rw-r--r--sys/dev/pci/drm/i915/i915_drv.c4
-rw-r--r--sys/dev/pci/drm/i915/intel_pm.c4
-rw-r--r--sys/dev/pci/drm/radeon/radeon_display.c18
-rw-r--r--sys/dev/pci/drm/radeon/radeon_kms.c6
9 files changed, 452 insertions, 363 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index 590f627eb95..4e9cfbe1c52 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drmP.h,v 1.197 2015/09/23 23:12:11 kettenis Exp $ */
+/* $OpenBSD: drmP.h,v 1.198 2015/09/26 19:52:16 kettenis Exp $ */
/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
*/
@@ -173,16 +173,13 @@ drm_can_sleep(void)
return true;
}
-#define DRM_WAIT_ON(ret, queue, lock, timeout, msg, condition ) do { \
- mtx_enter(lock); \
- while ((ret) == 0) { \
- if (condition) \
- break; \
- ret = msleep((queue), (lock), PZERO | PCATCH, \
- (msg), (timeout)); \
- } \
- mtx_leave(lock); \
-} while (/* CONSTCOND */ 0)
+#define DRM_WAIT_ON(ret, wq, timo, condition) do { \
+ ret = wait_event_interruptible_timeout(wq, condition, timo); \
+ if (ret == 0) \
+ ret = -EBUSY; \
+ if (ret > 0) \
+ ret = 0; \
+} while (0)
#define DRM_ERROR(fmt, arg...) \
printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt, \
@@ -320,24 +317,21 @@ struct drm_buf_entry {
};
struct drm_pending_event {
- TAILQ_ENTRY(drm_pending_event) link;
- struct drm_event *event;
- struct drm_file *file_priv;
- pid_t pid;
- void (*destroy)(struct drm_pending_event *);
+ struct drm_event *event;
+ struct list_head link;
+ struct drm_file *file_priv;
+ pid_t pid; /* pid of requester, no guarantee it's valid by the time
+ we deliver the event, for tracing only */
+ void (*destroy)(struct drm_pending_event *event);
};
-struct drm_pending_vblank_event {
- struct drm_pending_event base;
- int pipe;
- struct drm_event_vblank event;
-};
-
-TAILQ_HEAD(drmevlist, drm_pending_event);
-
struct drm_file {
SPLAY_HEAD(drm_obj_tree, drm_handle) obj_tree;
- struct drmevlist evlist;
+
+ wait_queue_head_t event_wait;
+ struct list_head event_list;
+ int event_space;
+
struct mutex table_lock;
struct selinfo rsel;
SPLAY_ENTRY(drm_file) link;
@@ -347,7 +341,6 @@ struct drm_file {
unsigned long ioctl_count;
dev_t kdev;
drm_magic_t magic;
- int event_space;
int flags;
int master;
int minor;
@@ -559,13 +552,13 @@ struct drm_driver_info {
#define DRIVER_AGP 0x1
#define DRIVER_AGP_REQUIRE 0x2
-#define DRIVER_MTRR 0x4
-#define DRIVER_DMA 0x8
-#define DRIVER_PCI_DMA 0x10
-#define DRIVER_SG 0x20
-#define DRIVER_IRQ 0x40
-#define DRIVER_GEM 0x80
-#define DRIVER_MODESET 0x100
+#define DRIVER_PCI_DMA 0x8
+#define DRIVER_SG 0x10
+#define DRIVER_HAVE_DMA 0x20
+#define DRIVER_HAVE_IRQ 0x40
+#define DRIVER_IRQ_SHARED 0x80
+#define DRIVER_GEM 0x1000
+#define DRIVER_MODESET 0x2000
u_int flags;
};
@@ -587,6 +580,25 @@ struct drm_cmdline_mode {
enum drm_connector_force force;
};
+struct drm_pending_vblank_event {
+ struct drm_pending_event base;
+ int pipe;
+ struct drm_event_vblank event;
+};
+
+struct drm_vblank_crtc {
+ wait_queue_head_t queue; /**< VBLANK wait queue */
+ struct timeval time[DRM_VBLANKTIME_RBSIZE]; /**< timestamp of current count */
+ atomic_t count; /**< number of VBLANK interrupts */
+ atomic_t refcount; /* number of users of vblank interruptsper crtc */
+ u32 last; /* protected by dev->vbl_lock, used */
+ /* for wraparound handling */
+ u32 last_wait; /* Last vblank seqno waited per CRTC */
+ unsigned int inmodeset; /* Display driver is setting mode */
+ bool enabled; /* so we don't call enable more than
+ once per disable */
+};
+
/**
* DRM device functions structure
*/
@@ -635,25 +647,37 @@ struct drm_device {
int irq; /* Interrupt used by board */
int irq_enabled; /* True if the irq handler is enabled */
- /* VBLANK support */
- struct drmevlist vbl_events; /* vblank events */
- int vblank_disable_allowed;
- /**< size of vblank counter register */
- uint32_t max_vblank_count;
- struct mutex event_lock;
-
- wait_queue_head_t *vbl_queue;
- atomic_t *_vblank_count;
- struct timeval *_vblank_time;
- struct mutex vblank_time_lock;
- struct mutex vbl_lock;
- atomic_t *vblank_refcount;
- uint32_t *last_vblank;
+ /** \name VBLANK IRQ support */
+ /*@{ */
+
+ /*
+ * At load time, disabling the vblank interrupt won't be allowed since
+ * old clients may not call the modeset ioctl and therefore misbehave.
+ * Once the modeset ioctl *has* been called though, we can safely
+ * disable them when unused.
+ */
+ bool vblank_disable_allowed;
+
+ /* array of size num_crtcs */
+ struct drm_vblank_crtc *vblank;
+
+ struct mutex vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */
+ struct mutex vbl_lock;
+ struct timeout vblank_disable_timer;
+
+ u32 max_vblank_count; /**< size of vblank counter register */
+
+ /**
+ * List of events
+ */
+ struct list_head vblank_event_list;
+ spinlock_t event_lock;
+
+ /*@} */
int *vblank_enabled;
int *vblank_inmodeset;
u32 *last_vblank_wait;
- struct timeout vblank_disable_timer;
int num_crtcs;
@@ -878,6 +902,11 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
return ((dev->driver->flags & feature) ? 1 : 0);
}
+static inline int drm_dev_to_irq(struct drm_device *dev)
+{
+ return dev->irq;
+}
+
#define DRM_PCIE_SPEED_25 1
#define DRM_PCIE_SPEED_50 2
#define DRM_PCIE_SPEED_80 4
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index d1aff158840..a5c0b71ae56 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_drv.c,v 1.137 2015/09/23 23:12:11 kettenis Exp $ */
+/* $OpenBSD: drm_drv.c,v 1.138 2015/09/26 19:52:16 kettenis Exp $ */
/*-
* Copyright 2007-2009 Owain G. Ainsworth <oga@openbsd.org>
* Copyright © 2008 Intel Corporation
@@ -111,8 +111,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
- DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
#ifdef __linux__
+ DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED),
@@ -179,11 +179,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma_ioctl, DRM_AUTH),
-#endif
DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-#if defined(__linux__) && defined(__OS_HAS_AGP)
+#if __OS_HAS_AGP
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -194,7 +193,6 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#endif
-#ifdef __linux__
DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#endif
@@ -394,7 +392,7 @@ drm_attach(struct device *parent, struct device *self, void *aux)
TAILQ_INIT(&dev->maplist);
SPLAY_INIT(&dev->files);
- TAILQ_INIT(&dev->vbl_events);
+ INIT_LIST_HEAD(&dev->vblank_event_list);
/*
* the dma buffers api is just weird. offset 1Gb to ensure we don't
@@ -635,7 +633,7 @@ drmopen(dev_t kdev, int flags, int fmt, struct proc *p)
file_priv->flags = flags;
file_priv->minor = minor(kdev);
INIT_LIST_HEAD(&file_priv->fbs);
- TAILQ_INIT(&file_priv->evlist);
+ INIT_LIST_HEAD(&file_priv->event_list);
file_priv->event_space = 4096; /* 4k for event buffer */
DRM_DEBUG("minor = %d\n", file_priv->minor);
@@ -683,8 +681,8 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
{
struct drm_device *dev = drm_get_device_from_kdev(kdev);
struct drm_file *file_priv;
- struct drm_pending_event *ev, *evtmp;
- struct drm_pending_vblank_event *vev;
+ struct drm_pending_event *e, *et;
+ struct drm_pending_vblank_event *v, *vt;
int retcode = 0;
if (dev == NULL)
@@ -710,20 +708,21 @@ drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
DRM_CURRENTPID, (long)&dev->device, dev->open_count);
mtx_enter(&dev->event_lock);
- struct drmevlist *list = &dev->vbl_events;
- for (ev = TAILQ_FIRST(list); ev != NULL; ev = evtmp) {
- evtmp = TAILQ_NEXT(ev, link);
- vev = (struct drm_pending_vblank_event *)ev;
- if (ev->file_priv == file_priv) {
- TAILQ_REMOVE(list, ev, link);
- drm_vblank_put(dev, vev->pipe);
- ev->destroy(ev);
+
+ /* Remove pending flips */
+ list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
+ if (v->base.file_priv == file_priv) {
+ list_del(&v->base.link);
+ drm_vblank_put(dev, v->pipe);
+ v->base.destroy(&v->base);
}
+
+ /* Remove unconsumed events */
+ list_for_each_entry_safe(e, et, &file_priv->event_list, link) {
+ list_del(&e->link);
+ e->destroy(e);
}
- while ((ev = TAILQ_FIRST(&file_priv->evlist)) != NULL) {
- TAILQ_REMOVE(&file_priv->evlist, ev, link);
- ev->destroy(ev);
- }
+
mtx_leave(&dev->event_lock);
if (dev->driver->flags & DRIVER_MODESET)
@@ -899,12 +898,12 @@ drmread(dev_t kdev, struct uio *uio, int ioflag)
* a whole event, we won't read any of it out.
*/
mtx_enter(&dev->event_lock);
- while (error == 0 && TAILQ_EMPTY(&file_priv->evlist)) {
+ while (error == 0 && list_empty(&file_priv->event_list)) {
if (ioflag & IO_NDELAY) {
mtx_leave(&dev->event_lock);
return (EAGAIN);
}
- error = msleep(&file_priv->evlist, &dev->event_lock,
+ error = msleep(&file_priv->event_list, &dev->event_lock,
PWAIT | PCATCH, "drmread", 0);
}
if (error) {
@@ -938,17 +937,22 @@ int
drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
size_t resid, struct drm_pending_event **out)
{
- struct drm_pending_event *ev = NULL;
- int gotone = 0;
+ struct drm_pending_event *e = NULL;
+ int gotone = 0;
MUTEX_ASSERT_LOCKED(&dev->event_lock);
- if ((ev = TAILQ_FIRST(&file_priv->evlist)) == NULL ||
- ev->event->length > resid)
+
+ *out = NULL;
+ if (list_empty(&file_priv->event_list))
+ goto out;
+ e = list_first_entry(&file_priv->event_list,
+ struct drm_pending_event, link);
+ if (e->event->length > resid)
goto out;
- TAILQ_REMOVE(&file_priv->evlist, ev, link);
- file_priv->event_space += ev->event->length;
- *out = ev;
+ file_priv->event_space += e->event->length;
+ list_del(&e->link);
+ *out = e;
gotone = 1;
out:
@@ -976,7 +980,7 @@ drmpoll(dev_t kdev, int events, struct proc *p)
mtx_enter(&dev->event_lock);
if (events & (POLLIN | POLLRDNORM)) {
- if (!TAILQ_EMPTY(&file_priv->evlist))
+ if (!list_empty(&file_priv->event_list))
revents |= events & (POLLIN | POLLRDNORM);
else
selrecord(p, &file_priv->rsel);
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c
index a8b25660904..e8b4fbcc025 100644
--- a/sys/dev/pci/drm/drm_irq.c
+++ b/sys/dev/pci/drm/drm_irq.c
@@ -1,4 +1,3 @@
-/* $OpenBSD: drm_irq.c,v 1.65 2015/09/23 23:12:11 kettenis Exp $ */
/**
* \file drm_irq.c
* IRQ support
@@ -34,15 +33,18 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/task.h>
-
#include "drmP.h"
-#include "drm.h"
+#include "drm_trace.h"
+
+#ifdef DRM_VBLANK_DEBUG
+#define VBL_DEBUG(x...) do { printf(x); } while(/* CONSTCOND */ 0)
+#else
+#define VBL_DEBUG(x...) do { } while(/* CONSTCOND */ 0)
+#endif
/* Access macro for slots in vblank timestamp ringbuffer. */
-#define vblanktimestamp(dev, crtc, count) ( \
- (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
- ((count) % DRM_VBLANKTIME_RBSIZE)])
+#define vblanktimestamp(dev, crtc, count) \
+ ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
/* Retry timestamp calculation up to 3 times to satisfy
* drm_timestamp_precision before giving up.
@@ -54,12 +56,6 @@
*/
#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
-#ifdef DRM_VBLANK_DEBUG
-#define DPRINTF(x...) do { printf(x); } while(/* CONSTCOND */ 0)
-#else
-#define DPRINTF(x...) do { } while(/* CONSTCOND */ 0)
-#endif
-
unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
/*
@@ -68,6 +64,7 @@ unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
*/
unsigned int drm_timestamp_monotonic = 1;
+#ifdef __linux__
/**
* Get interrupt from bus id.
*
@@ -84,28 +81,24 @@ unsigned int drm_timestamp_monotonic = 1;
int drm_irq_by_busid(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct drm_irq_busid *irq = data;
+ struct drm_irq_busid *p = data;
- /*
- * This is only ever called by root as part of a stupid interface.
- * just hand over the irq without checking the busid. If all clients
- * can be forced to use interface 1.2 then this can die.
- */
- irq->irq = dev->irq;
+ if (!dev->driver->bus->irq_by_busid)
+ return -EINVAL;
- DRM_DEBUG("%d:%d:%d => IRQ %d\n", irq->busnum, irq->devnum,
- irq->funcnum, irq->irq);
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+ return -EINVAL;
- return 0;
+ return dev->driver->bus->irq_by_busid(dev, p);
}
+#endif
/*
* Clear vblank timestamp buffer for a crtc.
*/
static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
{
- memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
- DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
+ memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time));
}
/*
@@ -130,7 +123,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
dev->driver->disable_vblank(dev, crtc);
- dev->vblank_enabled[crtc] = 0;
+ dev->vblank[crtc].enabled = false;
/* No further vblank irq's will be processed after
* this point. Get current hardware vblank count and
@@ -145,9 +138,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
* delayed gpu counter increment.
*/
do {
- dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+ dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc);
vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
- } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
+ } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
if (!count)
vblrc = 0;
@@ -155,7 +148,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
/* Compute time difference to stored timestamp of last vblank
* as updated by last invocation of drm_handle_vblank() in vblank irq.
*/
- vblcount = atomic_read(&dev->_vblank_count[crtc]);
+ vblcount = atomic_read(&dev->vblank[crtc].count);
diff_ns = timeval_to_ns(&tvblank) -
timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
@@ -172,7 +165,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
* hope for the best.
*/
if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
- atomic_inc(&dev->_vblank_count[crtc]);
+ atomic_inc(&dev->vblank[crtc].count);
smp_mb__after_atomic_inc();
}
@@ -182,7 +175,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
}
-static void vblank_disable_fn(void *arg)
+static void vblank_disable_fn(unsigned long arg)
{
struct drm_device *dev = (struct drm_device *)arg;
unsigned long irqflags;
@@ -193,8 +186,8 @@ static void vblank_disable_fn(void *arg)
for (i = 0; i < dev->num_crtcs; i++) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
- dev->vblank_enabled[i]) {
+ if (atomic_read(&dev->vblank[i].refcount) == 0 &&
+ dev->vblank[i].enabled) {
DRM_DEBUG("disabling vblank on crtc %d\n", i);
vblank_disable_and_save(dev, i);
}
@@ -208,18 +201,11 @@ void drm_vblank_cleanup(struct drm_device *dev)
if (dev->num_crtcs == 0)
return;
- timeout_del(&dev->vblank_disable_timer);
+ del_timer_sync(&dev->vblank_disable_timer);
- vblank_disable_fn(dev);
+ vblank_disable_fn((unsigned long)dev);
- kfree(dev->vbl_queue);
- kfree(dev->_vblank_count);
- kfree(dev->vblank_refcount);
- kfree(dev->vblank_enabled);
- kfree(dev->last_vblank);
- kfree(dev->last_vblank_wait);
- kfree(dev->vblank_inmodeset);
- kfree(dev->_vblank_time);
+ kfree(dev->vblank);
dev->num_crtcs = 0;
}
@@ -229,49 +215,21 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
{
int i, ret = -ENOMEM;
- timeout_set(&dev->vblank_disable_timer, vblank_disable_fn,
- dev);
+ setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
+ (unsigned long)dev);
mtx_init(&dev->vbl_lock, IPL_TTY);
mtx_init(&dev->vblank_time_lock, IPL_TTY);
dev->num_crtcs = num_crtcs;
- dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
- GFP_KERNEL);
- if (!dev->vbl_queue)
- goto err;
-
- dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL);
- if (!dev->_vblank_count)
- goto err;
-
- dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,
- GFP_KERNEL);
- if (!dev->vblank_refcount)
- goto err;
-
- dev->vblank_enabled = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
- if (!dev->vblank_enabled)
- goto err;
-
- dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
- if (!dev->last_vblank)
- goto err;
-
- dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
- if (!dev->last_vblank_wait)
- goto err;
-
- dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
- if (!dev->vblank_inmodeset)
+ dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);
+ if (!dev->vblank)
goto err;
- dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
- sizeof(struct timeval), GFP_KERNEL);
- if (!dev->_vblank_time)
- goto err;
+ for (i = 0; i < num_crtcs; i++)
+ init_waitqueue_head(&dev->vblank[i].queue);
- DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
+ DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
/* Driver specific high-precision vblank timestamping supported? */
if (dev->driver->get_vblank_timestamp)
@@ -279,14 +237,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
else
DRM_INFO("No driver support for vblank timestamp query.\n");
- /* Zero per-crtc vblank stuff */
- for (i = 0; i < num_crtcs; i++) {
- init_waitqueue_head(&dev->vbl_queue[i]);
- atomic_set(&dev->_vblank_count[i], 0);
- atomic_set(&dev->vblank_refcount[i], 0);
- }
+ dev->vblank_disable_allowed = false;
- dev->vblank_disable_allowed = 0;
return 0;
err:
@@ -295,17 +247,15 @@ err:
}
EXPORT_SYMBOL(drm_vblank_init);
-#ifdef notyet
+#ifdef __linux__
static void drm_irq_vgaarb_nokms(void *cookie, bool state)
{
struct drm_device *dev = cookie;
-#ifdef notyet
if (dev->driver->vgaarb_irq) {
dev->driver->vgaarb_irq(dev, state);
return;
}
-#endif
if (!dev->irq_enabled)
return;
@@ -333,36 +283,78 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
*/
int drm_irq_install(struct drm_device *dev)
{
- int ret;
+ int ret;
+#ifdef __linux__
+ unsigned long sh_flags = 0;
+ char *irqname;
+#endif
- if (dev->irq == 0 || dev->dev_private == NULL)
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- DRM_DEBUG("irq=%d\n", dev->irq);
+ if (drm_dev_to_irq(dev) == 0)
+ return -EINVAL;
mutex_lock(&dev->struct_mutex);
+
+ /* Driver must have been initialized */
+ if (!dev->dev_private) {
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
+ }
+
if (dev->irq_enabled) {
mutex_unlock(&dev->struct_mutex);
return -EBUSY;
}
- dev->irq_enabled = 1;
+ dev->irq_enabled = true;
mutex_unlock(&dev->struct_mutex);
- if (dev->driver->irq_install) {
- if ((ret = dev->driver->irq_install(dev)) != 0)
- goto err;
- } else {
- if (dev->driver->irq_preinstall)
- dev->driver->irq_preinstall(dev);
- if (dev->driver->irq_postinstall)
- dev->driver->irq_postinstall(dev);
+ DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
+
+ /* Before installing handler */
+ if (dev->driver->irq_preinstall)
+ dev->driver->irq_preinstall(dev);
+
+#ifdef __linux__
+ /* Install handler */
+ if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
+ sh_flags = IRQF_SHARED;
+
+ if (dev->devname)
+ irqname = dev->devname;
+ else
+ irqname = dev->driver->name;
+
+ ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,
+ sh_flags, irqname, dev);
+
+ if (ret < 0) {
+ mutex_lock(&dev->struct_mutex);
+ dev->irq_enabled = false;
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
+#endif
+
+ /* After installing handler */
+ if (dev->driver->irq_postinstall)
+ ret = dev->driver->irq_postinstall(dev);
+
+ if (ret < 0) {
+ mutex_lock(&dev->struct_mutex);
+ dev->irq_enabled = false;
+ mutex_unlock(&dev->struct_mutex);
+#ifdef __linux__
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ vga_client_register(dev->pdev, NULL, NULL, NULL);
+ free_irq(drm_dev_to_irq(dev), dev);
+#endif
}
- return 0;
-err:
- mutex_lock(&dev->struct_mutex);
- dev->irq_enabled = 0;
- mutex_unlock(&dev->struct_mutex);
return ret;
}
EXPORT_SYMBOL(drm_irq_install);
@@ -377,41 +369,53 @@ EXPORT_SYMBOL(drm_irq_install);
int drm_irq_uninstall(struct drm_device *dev)
{
unsigned long irqflags;
+ bool irq_enabled;
int i;
- mutex_lock(&dev->struct_mutex);
- if (!dev->irq_enabled) {
- mutex_unlock(&dev->struct_mutex);
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- }
- dev->irq_enabled = 0;
+ mutex_lock(&dev->struct_mutex);
+ irq_enabled = dev->irq_enabled;
+ dev->irq_enabled = false;
mutex_unlock(&dev->struct_mutex);
/*
- * Ick. we're about to turn of vblanks, so make sure anyone waiting
- * on them gets woken up. Also make sure we update state correctly
- * so that we can continue refcounting correctly.
+ * Wake up any waiters so they don't hang.
*/
if (dev->num_crtcs) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
for (i = 0; i < dev->num_crtcs; i++) {
- DRM_WAKEUP(&dev->vbl_queue[i]);
- dev->vblank_enabled[i] = 0;
- dev->last_vblank[i] =
+ wake_up(&dev->vblank[i].queue);
+ dev->vblank[i].enabled = false;
+ dev->vblank[i].last =
dev->driver->get_vblank_counter(dev, i);
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
- DRM_DEBUG("irq=%d\n", dev->irq);
+ if (!irq_enabled)
+ return -EINVAL;
- dev->driver->irq_uninstall(dev);
+ DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
+
+#ifdef __linux__
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ vga_client_register(dev->pdev, NULL, NULL, NULL);
+#endif
+
+ if (dev->driver->irq_uninstall)
+ dev->driver->irq_uninstall(dev);
+
+#ifdef __linux__
+ free_irq(drm_dev_to_irq(dev), dev);
+#endif
return 0;
}
EXPORT_SYMBOL(drm_irq_uninstall);
+#ifdef __linux__
/**
* IRQ control ioctl.
*
@@ -428,19 +432,24 @@ int drm_control(struct drm_device *dev, void *data,
{
struct drm_control *ctl = data;
- /* Handle drivers who used to require IRQ setup no longer does. */
- if (!(dev->driver->flags & DRIVER_IRQ))
- return 0;
+ /* if we haven't irq we fallback for compatibility reasons -
+ * this used to be a separate function in drm_dma.h
+ */
+
switch (ctl->func) {
case DRM_INST_HANDLER:
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+ return 0;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl->irq != dev->irq)
+ ctl->irq != drm_dev_to_irq(dev))
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
+ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+ return 0;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
return drm_irq_uninstall(dev);
@@ -448,6 +457,7 @@ int drm_control(struct drm_device *dev, void *data,
return -EINVAL;
}
}
+#endif
/**
* drm_calc_timestamping_constants - Calculate vblank timestamp constants
@@ -531,6 +541,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
* 0 = Default.
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
* @refcrtc: drm_crtc* of crtc which defines scanout timing.
+ * @mode: mode which defines the scanout timings
*
* Returns negative value on error, failure or if not supported in current
* video mode:
@@ -553,13 +564,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
const struct drm_crtc *refcrtc,
const struct drm_display_mode *mode)
{
- struct timeval stime, etime;
-#ifdef notyet
- struct timeval mono_time_offset;
-#endif
- int vbl_status, vtotal, vdisplay;
+ ktime_t stime, etime, mono_time_offset;
+ struct timeval tv_etime;
+ int vbl_status;
int vpos, hpos, i;
- s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
+ int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
bool invbl;
if (crtc < 0 || crtc >= dev->num_crtcs) {
@@ -573,10 +582,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
return -EIO;
}
- mode = &refcrtc->hwmode;
- vtotal = mode->crtc_vtotal;
- vdisplay = mode->crtc_vdisplay;
-
/* Durations of frames, lines, pixels in nanoseconds. */
framedur_ns = refcrtc->framedur_ns;
linedur_ns = refcrtc->linedur_ns;
@@ -585,7 +590,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
/* If mode timing undefined, just return as no-op:
* Happens during initial modesetting of a crtc.
*/
- if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
+ if (framedur_ns == 0) {
DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
return -EAGAIN;
}
@@ -598,29 +603,20 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
* code gets preempted or delayed for some reason.
*/
for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {
- /* Disable preemption to make it very likely to
- * succeed in the first iteration even on PREEMPT_RT kernel.
+ /*
+ * Get vertical and horizontal scanout position vpos, hpos,
+ * and bounding timestamps stime, etime, pre/post query.
*/
-#ifdef notyet
- preempt_disable();
-#endif
-
- /* Get system timestamp before query. */
- getmicrouptime(&stime);
-
- /* Get vertical and horizontal scanout pos. vpos, hpos. */
vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos,
&hpos, &stime, &etime);
- /* Get system timestamp after query. */
- getmicrouptime(&etime);
-#ifdef notyet
+ /*
+ * Get correction for CLOCK_MONOTONIC -> CLOCK_REALTIME if
+ * CLOCK_REALTIME is requested.
+ */
if (!drm_timestamp_monotonic)
mono_time_offset = ktime_get_monotonic_offset();
- preempt_enable();
-#endif
-
/* Return as no-op if scanout query unsupported or failed. */
if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
@@ -628,21 +624,22 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
return -EIO;
}
- duration_ns = timeval_to_ns(&etime) - timeval_to_ns(&stime);
+ /* Compute uncertainty in timestamp of scanout position query. */
+ duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime);
/* Accept result with < max_error nsecs timing uncertainty. */
- if (duration_ns <= (s64) *max_error)
+ if (duration_ns <= *max_error)
break;
}
/* Noisy system timing? */
if (i == DRM_TIMESTAMP_MAXRETRIES) {
DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
- crtc, (int) duration_ns/1000, *max_error/1000, i);
+ crtc, duration_ns/1000, *max_error/1000, i);
}
/* Return upper bound of timestamp precision error. */
- *max_error = (int) duration_ns;
+ *max_error = duration_ns;
/* Check if in vblank area:
* vpos is >=0 in video scanout area, but negative
@@ -655,41 +652,27 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
* since start of scanout at first display scanline. delta_ns
* can be negative if start of scanout hasn't happened yet.
*/
- delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
-
- /* Is vpos outside nominal vblank area, but less than
- * 1/100 of a frame height away from start of vblank?
- * If so, assume this isn't a massively delayed vblank
- * interrupt, but a vblank interrupt that fired a few
- * microseconds before true start of vblank. Compensate
- * by adding a full frame duration to the final timestamp.
- * Happens, e.g., on ATI R500, R600.
- *
- * We only do this if DRM_CALLED_FROM_VBLIRQ.
- */
- if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
- ((vdisplay - vpos) < vtotal / 100)) {
- delta_ns = delta_ns - framedur_ns;
-
- /* Signal this correction as "applied". */
- vbl_status |= 0x8;
- }
+ delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
-#ifdef notyet
if (!drm_timestamp_monotonic)
etime = ktime_sub(etime, mono_time_offset);
-#endif
+ /* save this only for debugging purposes */
+ tv_etime = ktime_to_timeval(etime);
/* Subtract time delta from raw timestamp to get final
* vblank_time timestamp for end of vblank.
*/
- *vblank_time = ns_to_timeval(timeval_to_ns(&etime) - delta_ns);
+ if (delta_ns < 0)
+ etime = ktime_add_ns(etime, -delta_ns);
+ else
+ etime = ktime_sub_ns(etime, delta_ns);
+ *vblank_time = ktime_to_timeval(etime);
- DPRINTF("crtc %d : v %d p(%d,%d)@ %lld.%ld -> %lld.%ld [e %d us, %d rep]\n",
+ VBL_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
crtc, (int)vbl_status, hpos, vpos,
- (long long)etime.tv_sec, (long)etime.tv_usec,
- (long long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
- (int)duration_ns/1000, i);
+ (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
+ (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+ duration_ns/1000, i);
vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
if (invbl)
@@ -701,15 +684,13 @@ EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
static struct timeval get_drm_timestamp(void)
{
- struct timeval now;
+ ktime_t now;
- getmicrouptime(&now);
-#ifdef notyet
+ now = ktime_get();
if (!drm_timestamp_monotonic)
now = ktime_sub(now, ktime_get_monotonic_offset());
-#endif
- return (now);
+ return ktime_to_timeval(now);
}
/**
@@ -768,7 +749,7 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
*/
u32 drm_vblank_count(struct drm_device *dev, int crtc)
{
- return atomic_read(&dev->_vblank_count[crtc]);
+ return atomic_read(&dev->vblank[crtc].count);
}
EXPORT_SYMBOL(drm_vblank_count);
@@ -797,10 +778,10 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
* a seqlock.
*/
do {
- cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
+ cur_vblank = atomic_read(&dev->vblank[crtc].count);
*vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
smp_rmb();
- } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
+ } while (cur_vblank != atomic_read(&dev->vblank[crtc].count));
return cur_vblank;
}
@@ -810,19 +791,17 @@ static void send_vblank_event(struct drm_device *dev,
struct drm_pending_vblank_event *e,
unsigned long seq, struct timeval *now)
{
- struct drm_file *file_priv = e->base.file_priv;
MUTEX_ASSERT_LOCKED(&dev->event_lock);
e->event.sequence = seq;
e->event.tv_sec = now->tv_sec;
e->event.tv_usec = now->tv_usec;
- TAILQ_INSERT_TAIL(&file_priv->evlist, &e->base, link);
- wakeup(&file_priv->evlist);
- selwakeup(&file_priv->rsel);
-#if 0
+ list_add_tail(&e->base.link,
+ &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ selwakeup(&e->base.file_priv->rsel);
trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
e->event.sequence);
-#endif
}
/**
@@ -846,6 +825,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
now = get_drm_timestamp();
}
+ e->pipe = crtc;
send_vblank_event(dev, e, seq, &now);
}
EXPORT_SYMBOL(drm_send_vblank_event);
@@ -889,15 +869,15 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
} while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
/* Deal with counter wrap */
- diff = cur_vblank - dev->last_vblank[crtc];
- if (cur_vblank < dev->last_vblank[crtc]) {
+ diff = cur_vblank - dev->vblank[crtc].last;
+ if (cur_vblank < dev->vblank[crtc].last) {
diff += dev->max_vblank_count;
DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
- crtc, dev->last_vblank[crtc], cur_vblank, diff);
+ crtc, dev->vblank[crtc].last, cur_vblank, diff);
}
- DPRINTF("enabling vblank interrupts on crtc %d, missed %d\n",
+ VBL_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
crtc, diff);
/* Reinitialize corresponding vblank timestamp if high-precision query
@@ -905,12 +885,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
* reinitialize delayed at next vblank interrupt in that case.
*/
if (rc) {
- tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
+ tslot = atomic_read(&dev->vblank[crtc].count) + diff;
vblanktimestamp(dev, crtc, tslot) = t_vblank;
}
smp_mb__before_atomic_inc();
- atomic_add(diff, &dev->_vblank_count[crtc]);
+ atomic_add(diff, &dev->vblank[crtc].count);
smp_mb__after_atomic_inc();
}
@@ -932,9 +912,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
- if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+ if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
- if (!dev->vblank_enabled[crtc]) {
+ if (!dev->vblank[crtc].enabled) {
/* Enable vblank irqs under vblank_time_lock protection.
* All vblank count & timestamp updates are held off
* until we are done reinitializing master counter and
@@ -942,19 +922,19 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
* prevent double-accounting of same vblank interval.
*/
ret = dev->driver->enable_vblank(dev, crtc);
- DPRINTF("enabling vblank on crtc %d, ret: %d\n",
+ VBL_DEBUG("enabling vblank on crtc %d, ret: %d\n",
crtc, ret);
if (ret)
- atomic_dec(&dev->vblank_refcount[crtc]);
+ atomic_dec(&dev->vblank[crtc].refcount);
else {
- dev->vblank_enabled[crtc] = 1;
+ dev->vblank[crtc].enabled = true;
drm_update_vblank_count(dev, crtc);
}
}
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
} else {
- if (!dev->vblank_enabled[crtc]) {
- atomic_dec(&dev->vblank_refcount[crtc]);
+ if (!dev->vblank[crtc].enabled) {
+ atomic_dec(&dev->vblank[crtc].refcount);
ret = -EINVAL;
}
}
@@ -974,12 +954,13 @@ EXPORT_SYMBOL(drm_vblank_get);
*/
void drm_vblank_put(struct drm_device *dev, int crtc)
{
- BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
+ BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
/* Last user schedules interrupt disable */
- if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
+ if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
(drm_vblank_offdelay > 0))
- timeout_add_msec(&dev->vblank_disable_timer, drm_vblank_offdelay);
+ mod_timer(&dev->vblank_disable_timer,
+ jiffies + ((drm_vblank_offdelay * HZ)/1000));
}
EXPORT_SYMBOL(drm_vblank_put);
@@ -992,35 +973,28 @@ EXPORT_SYMBOL(drm_vblank_put);
*/
void drm_vblank_off(struct drm_device *dev, int crtc)
{
- struct drmevlist *list;
- struct drm_pending_event *ev, *tmp;
- struct drm_pending_vblank_event *vev;
+ struct drm_pending_vblank_event *e, *t;
struct timeval now;
unsigned long irqflags;
unsigned int seq;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
vblank_disable_and_save(dev, crtc);
- DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ wake_up(&dev->vblank[crtc].queue);
- list = &dev->vbl_events;
/* Send any queued vblank events, lest the natives grow disquiet */
seq = drm_vblank_count_and_time(dev, crtc, &now);
spin_lock(&dev->event_lock);
- for (ev = TAILQ_FIRST(list); ev != NULL; ev = tmp) {
- tmp = TAILQ_NEXT(ev, link);
-
- vev = (struct drm_pending_vblank_event *)ev;
-
- if (vev->pipe != crtc)
+ list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+ if (e->pipe != crtc)
continue;
DRM_DEBUG("Sending premature vblank event on disable: \
wanted %d, current %d\n",
- vev->event.sequence, seq);
- TAILQ_REMOVE(list, ev, link);
- drm_vblank_put(dev, vev->pipe);
- send_vblank_event(dev, vev, seq, &now);
+ e->event.sequence, seq);
+ list_del(&e->base.link);
+ drm_vblank_put(dev, e->pipe);
+ send_vblank_event(dev, e, seq, &now);
}
spin_unlock(&dev->event_lock);
@@ -1048,10 +1022,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
* to avoid corrupting the count if multiple, mismatch calls occur),
* so that interrupts remain enabled in the interim.
*/
- if (!dev->vblank_inmodeset[crtc]) {
- dev->vblank_inmodeset[crtc] = 0x1;
+ if (!dev->vblank[crtc].inmodeset) {
+ dev->vblank[crtc].inmodeset = 0x1;
if (drm_vblank_get(dev, crtc) == 0)
- dev->vblank_inmodeset[crtc] |= 0x2;
+ dev->vblank[crtc].inmodeset |= 0x2;
}
}
EXPORT_SYMBOL(drm_vblank_pre_modeset);
@@ -1064,15 +1038,15 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
if (!dev->num_crtcs)
return;
- if (dev->vblank_inmodeset[crtc]) {
+ if (dev->vblank[crtc].inmodeset) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- dev->vblank_disable_allowed = 1;
+ dev->vblank_disable_allowed = true;
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- if (dev->vblank_inmodeset[crtc] & 0x2)
+ if (dev->vblank[crtc].inmodeset & 0x2)
drm_vblank_put(dev, crtc);
- dev->vblank_inmodeset[crtc] = 0;
+ dev->vblank[crtc].inmodeset = 0;
}
}
EXPORT_SYMBOL(drm_vblank_post_modeset);
@@ -1137,7 +1111,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
}
e->pipe = pipe;
- e->base.pid = DRM_CURRENTPID;
+ e->base.pid = curproc->p_pid;
e->event.base.type = DRM_EVENT_VBLANK;
e->event.base.length = sizeof e->event;
e->event.user_data = vblwait->request.signal;
@@ -1164,10 +1138,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
vblwait->request.sequence, seq, pipe);
-#if 0
- trace_drm_vblank_event_queued(current->pid, pipe,
+ trace_drm_vblank_event_queued(curproc->p_pid, pipe,
vblwait->request.sequence);
-#endif
e->event.sequence = vblwait->request.sequence;
if ((seq - vblwait->request.sequence) <= (1 << 23)) {
@@ -1176,7 +1148,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
vblwait->reply.sequence = seq;
} else {
/* drm_handle_vblank_events will call drm_vblank_put */
- TAILQ_INSERT_TAIL(&dev->vbl_events, &e->base, link);
+ list_add_tail(&e->base.link, &dev->vblank_event_list);
vblwait->reply.sequence = vblwait->request.sequence;
}
@@ -1213,8 +1185,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
int ret;
unsigned int flags, seq, crtc, high_crtc;
- if (!dev->irq_enabled)
- return -EINVAL;
+ if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+ if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
+ return -EINVAL;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
return -EINVAL;
@@ -1270,9 +1243,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
vblwait->request.sequence, crtc);
- dev->last_vblank_wait[crtc] = vblwait->request.sequence;
- DRM_WAIT_ON(ret, &dev->vbl_queue[crtc], &dev->vbl_lock, 3 * hz,
- "drmvblq", (((drm_vblank_count(dev, crtc) -
+ dev->vblank[crtc].last_wait = vblwait->request.sequence;
+ DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ,
+ (((drm_vblank_count(dev, crtc) -
vblwait->request.sequence) <= (1 << 23)) ||
!dev->irq_enabled));
@@ -1296,39 +1269,32 @@ done:
static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
{
- struct drmevlist *list;
- struct drm_pending_event *ev, *tmp;
- struct drm_pending_vblank_event *vev;
+ struct drm_pending_vblank_event *e, *t;
struct timeval now;
unsigned long flags;
unsigned int seq;
- list = &dev->vbl_events;
seq = drm_vblank_count_and_time(dev, crtc, &now);
spin_lock_irqsave(&dev->event_lock, flags);
- for (ev = TAILQ_FIRST(list); ev != NULL; ev = tmp) {
- tmp = TAILQ_NEXT(ev, link);
-
- vev = (struct drm_pending_vblank_event *)ev;
-
- if (vev->pipe != crtc)
+ list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+ if (e->pipe != crtc)
continue;
- if ((seq - vev->event.sequence) > (1<<23))
+ if ((seq - e->event.sequence) > (1<<23))
continue;
- DPRINTF("vblank event on %d, current %d\n",
- vev->event.sequence, seq);
+ VBL_DEBUG("vblank event on %d, current %d\n",
+ e->event.sequence, seq);
- TAILQ_REMOVE(list, ev, link);
- drm_vblank_put(dev, vev->pipe);
- send_vblank_event(dev, vev, seq, &now);
+ list_del(&e->base.link);
+ drm_vblank_put(dev, e->pipe);
+ send_vblank_event(dev, e, seq, &now);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
-// trace_drm_vblank_event(crtc, seq);
+ trace_drm_vblank_event(crtc, seq);
}
/**
@@ -1356,7 +1322,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
/* Vblank irq handling disabled. Nothing to do. */
- if (!dev->vblank_enabled[crtc]) {
+ if (!dev->vblank[crtc].enabled) {
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
return false;
}
@@ -1366,7 +1332,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
*/
/* Get current timestamp and count. */
- vblcount = atomic_read(&dev->_vblank_count[crtc]);
+ vblcount = atomic_read(&dev->vblank[crtc].count);
drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
/* Compute time difference to timestamp of last vblank */
@@ -1390,14 +1356,14 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
* the timestamp computed above.
*/
smp_mb__before_atomic_inc();
- atomic_inc(&dev->_vblank_count[crtc]);
+ atomic_inc(&dev->vblank[crtc].count);
smp_mb__after_atomic_inc();
} else {
DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
crtc, (int) diff_ns);
}
- DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ wake_up(&dev->vblank[crtc].queue);
drm_handle_vblank_events(dev, crtc);
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
diff --git a/sys/dev/pci/drm/drm_linux.h b/sys/dev/pci/drm/drm_linux.h
index 0819de601c2..eb9eb5c6225 100644
--- a/sys/dev/pci/drm/drm_linux.h
+++ b/sys/dev/pci/drm/drm_linux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_linux.h,v 1.37 2015/09/26 11:17:15 kettenis Exp $ */
+/* $OpenBSD: drm_linux.h,v 1.38 2015/09/26 19:52:16 kettenis Exp $ */
/*
* Copyright (c) 2013, 2014, 2015 Mark Kettenis
*
@@ -380,6 +380,7 @@ do { \
#define wake_up(x) wakeup(x)
#define wake_up_all(x) wakeup(x)
#define wake_up_all_locked(x) wakeup(x)
+#define wake_up_interruptible(x) wakeup(x)
#define waitqueue_active(wq) ((wq)->count > 0)
@@ -617,6 +618,7 @@ timespec_valid(const struct timespec *ts)
}
typedef struct timeval ktime_t;
+
static inline struct timeval
ktime_get(void)
{
@@ -626,6 +628,41 @@ ktime_get(void)
return tv;
}
+static inline struct timeval
+ktime_get_monotonic_offset(void)
+{
+ struct timeval tv = {0, 0};
+ return tv;
+}
+
+static inline int64_t
+ktime_to_ns(struct timeval tv)
+{
+ return timeval_to_ns(&tv);
+}
+
+#define ktime_to_timeval(tv) (tv)
+
+static inline struct timeval
+ktime_sub(struct timeval a, struct timeval b)
+{
+ struct timeval res;
+ timersub(&a, &b, &res);
+ return res;
+}
+
+static inline struct timeval
+ktime_add_ns(struct timeval tv, int64_t ns)
+{
+ return ns_to_timeval(timeval_to_ns(&tv) + ns);
+}
+
+static inline struct timeval
+ktime_sub_ns(struct timeval tv, int64_t ns)
+{
+ return ns_to_timeval(timeval_to_ns(&tv) - ns);
+}
+
#define GFP_ATOMIC M_NOWAIT
#define GFP_KERNEL (M_WAITOK | M_CANFAIL)
#define GFP_TEMPORARY (M_WAITOK | M_CANFAIL)
diff --git a/sys/dev/pci/drm/drm_trace.h b/sys/dev/pci/drm/drm_trace.h
new file mode 100644
index 00000000000..18ed1bb9469
--- /dev/null
+++ b/sys/dev/pci/drm/drm_trace.h
@@ -0,0 +1,63 @@
+#if !defined(_DRM_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _DRM_TRACE_H_
+
+#include <dev/pci/drm/drmP.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM drm
+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
+#define TRACE_INCLUDE_FILE drm_trace
+
+TRACE_EVENT(drm_vblank_event,
+ TP_PROTO(int crtc, unsigned int seq),
+ TP_ARGS(crtc, seq),
+ TP_STRUCT__entry(
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("crtc=%d, seq=%u", __entry->crtc, __entry->seq)
+);
+
+TRACE_EVENT(drm_vblank_event_queued,
+ TP_PROTO(pid_t pid, int crtc, unsigned int seq),
+ TP_ARGS(pid, crtc, seq),
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
+ __entry->seq)
+);
+
+TRACE_EVENT(drm_vblank_event_delivered,
+ TP_PROTO(pid_t pid, int crtc, unsigned int seq),
+ TP_ARGS(pid, crtc, seq),
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
+ __entry->seq)
+);
+
+#endif /* _DRM_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
diff --git a/sys/dev/pci/drm/i915/i915_drv.c b/sys/dev/pci/drm/i915/i915_drv.c
index a229f758d0b..b3e7b00d677 100644
--- a/sys/dev/pci/drm/i915/i915_drv.c
+++ b/sys/dev/pci/drm/i915/i915_drv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.c,v 1.89 2015/09/25 16:15:19 jsg Exp $ */
+/* $OpenBSD: i915_drv.c,v 1.90 2015/09/26 19:52:16 kettenis Exp $ */
/*
* Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
*
@@ -486,7 +486,7 @@ static struct drm_driver_info inteldrm_driver = {
.patchlevel = DRIVER_PATCHLEVEL,
.flags = DRIVER_AGP | DRIVER_AGP_REQUIRE |
- DRIVER_MTRR | DRIVER_IRQ | DRIVER_GEM |
+ DRIVER_HAVE_IRQ | DRIVER_GEM |
DRIVER_MODESET,
};
diff --git a/sys/dev/pci/drm/i915/intel_pm.c b/sys/dev/pci/drm/i915/intel_pm.c
index c112f08d7dc..e6a3feb0d2d 100644
--- a/sys/dev/pci/drm/i915/intel_pm.c
+++ b/sys/dev/pci/drm/i915/intel_pm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intel_pm.c,v 1.38 2015/09/25 16:15:19 jsg Exp $ */
+/* $OpenBSD: intel_pm.c,v 1.39 2015/09/26 19:52:16 kettenis Exp $ */
/*
* Copyright © 2012 Intel Corporation
*
@@ -5257,7 +5257,7 @@ static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
for_each_pipe(p)
if (p != PIPE_A)
- dev->last_vblank[p] = 0;
+ dev->vblank[p].last = 0;
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
diff --git a/sys/dev/pci/drm/radeon/radeon_display.c b/sys/dev/pci/drm/radeon/radeon_display.c
index 0cefd662b8c..62e15f918fa 100644
--- a/sys/dev/pci/drm/radeon/radeon_display.c
+++ b/sys/dev/pci/drm/radeon/radeon_display.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radeon_display.c,v 1.11 2015/09/23 23:12:12 kettenis Exp $ */
+/* $OpenBSD: radeon_display.c,v 1.12 2015/09/26 19:52:16 kettenis Exp $ */
/*
* Copyright 2007-8 Advanced Micro Devices, Inc.
* Copyright 2008 Red Hat Inc.
@@ -270,10 +270,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
{
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
struct radeon_unpin_work *work;
- struct drm_pending_vblank_event *e;
- struct timeval now;
unsigned long flags;
- struct drm_file *file_priv;
u32 update_pending;
int vpos, hpos;
@@ -328,16 +325,9 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
radeon_crtc->unpin_work = NULL;
/* wakeup userspace */
- if (work->event) {
- e = work->event;
- e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now);
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
- file_priv = e->base.file_priv;
- TAILQ_INSERT_TAIL(&file_priv->evlist, &e->base, link);
- wakeup(&file_priv->evlist);
- selwakeup(&file_priv->rsel);
- }
+ if (work->event)
+ drm_send_vblank_event(rdev->ddev, crtc_id, work->event);
+
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id);
diff --git a/sys/dev/pci/drm/radeon/radeon_kms.c b/sys/dev/pci/drm/radeon/radeon_kms.c
index 5bbc402c831..b461c51e1d9 100644
--- a/sys/dev/pci/drm/radeon/radeon_kms.c
+++ b/sys/dev/pci/drm/radeon/radeon_kms.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radeon_kms.c,v 1.40 2015/09/23 23:12:12 kettenis Exp $ */
+/* $OpenBSD: radeon_kms.c,v 1.41 2015/09/26 19:52:16 kettenis Exp $ */
/*
* Copyright 2008 Advanced Micro Devices, Inc.
* Copyright 2008 Red Hat Inc.
@@ -203,8 +203,8 @@ const struct drm_pcidev radeondrm_pciidlist[] = {
static struct drm_driver_info kms_driver = {
.flags =
- DRIVER_AGP | DRIVER_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_IRQ | DRIVER_DMA | DRIVER_GEM | DRIVER_MODESET,
+ DRIVER_AGP | DRIVER_PCI_DMA | DRIVER_SG |
+ DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_GEM | DRIVER_MODESET,
.buf_priv_size = 0,
.firstopen = radeon_driver_firstopen_kms,
.open = radeon_driver_open_kms,