summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-04-05 04:15:38 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-04-05 04:15:38 +0000
commit816afca8624a62abcfc02b37211dfcff81c386c5 (patch)
tree480affd767cee7a3c923cb17715cf7578b3affde
parent82592d1958f04b9d94c944120248d114a03acb88 (diff)
Rework the vblank subsystem so that instead of having various bits in
the drm softc, we only have one pointer, with the rest in that struct. This is so that vblank-less drivers (yes, they exist) don't need to waste space on useless crud. While i'm reworking most of this code anyway, accept that on openbsd all of the #defined atomic functions are not atomic other than set and clear bit. Also, realise that the vb_lock is held whenever we manipulate these counts anyway. With those two facts in mind just remove the atomic_blah() and just use ++ and --.
-rw-r--r--sys/dev/pci/drm/drmP.h26
-rw-r--r--sys/dev/pci/drm/drm_irq.c179
-rw-r--r--sys/dev/pci/drm/i915_irq.c2
-rw-r--r--sys/dev/pci/drm/radeon_irq.c2
4 files changed, 102 insertions, 107 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index 734f0741188..1c5969dfa8c 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -295,12 +295,19 @@ struct drm_local_map {
enum drm_map_type type; /* Type of memory mapped */
};
-struct drm_vblank {
- u_int32_t last_vblank; /* Last vblank we recieved */
- atomic_t vbl_count; /* Number of interrupts */
- atomic_t vbl_refcount; /* Number of users */
- int vbl_enabled; /* Enabled? */
- int vbl_inmodeset; /* is the DDX currently modesetting */
+struct drm_vblank_info {
+ struct mutex vb_lock; /* VBLANK data lock */
+ struct timeout vb_disable_timer; /* timer for disable */
+ int vb_disable_allowed;
+ int vb_num; /* number of crtcs */
+ u_int32_t vb_max; /* counter reg size */
+ struct drm_vblank {
+ u_int32_t vbl_last; /* Last recieved */
+ u_int32_t vbl_count; /* interrupt no. */
+ int vbl_refs; /* Number of users */
+ int vbl_enabled; /* Enabled? */
+ int vbl_inmodeset; /* in a modeset? */
+ } vb_crtcs[1];
};
/* Heap implementation for radeon and i915 legacy */
@@ -417,12 +424,7 @@ struct drm_device {
int irq_enabled; /* True if the irq handler is enabled */
/* VBLANK support */
- int num_crtcs; /* number of crtcs */
- u_int32_t max_vblank_count; /* size of counter reg*/
- struct mutex vbl_lock; /* VBLANK data lock */
- int vblank_disable_allowed;
- struct timeout vblank_disable_timer; /* timer for disable */
- struct drm_vblank *vblank; /* One per ctrc */
+ struct drm_vblank_info *vblank; /* One per ctrc */
pid_t buf_pgid;
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c
index 50fa58d826b..42df7efae18 100644
--- a/sys/dev/pci/drm/drm_irq.c
+++ b/sys/dev/pci/drm/drm_irq.c
@@ -104,14 +104,16 @@ drm_irq_uninstall(struct drm_device *dev)
* on them gets woken up. Also make sure we update state correctly
* so that we can continue refcounting correctly.
*/
- mtx_enter(&dev->vbl_lock);
- for (i = 0; i < dev->num_crtcs; i++) {
- wakeup(&dev->vblank[i]);
- dev->vblank[i].vbl_enabled = 0;
- dev->vblank[i].last_vblank =
- dev->driver->get_vblank_counter(dev, i);
+ if (dev->vblank != NULL) {
+ mtx_enter(&dev->vblank->vb_lock);
+ for (i = 0; i < dev->vblank->vb_num; i++) {
+ wakeup(&dev->vblank->vb_crtcs[i]);
+ dev->vblank->vb_crtcs[i].vbl_enabled = 0;
+ dev->vblank->vb_crtcs[i].vbl_last =
+ dev->driver->get_vblank_counter(dev, i);
+ }
+ mtx_leave(&dev->vblank->vb_lock);
}
- mtx_leave(&dev->vbl_lock);
DRM_DEBUG("irq=%d\n", dev->irq);
@@ -145,107 +147,104 @@ drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
void
vblank_disable(void *arg)
{
- struct drm_device *dev = (struct drm_device*)arg;
- int i;
+ struct drm_device *dev = (struct drm_device*)arg;
+ struct drm_vblank_info *vbl = dev->vblank;
+ struct drm_vblank *crtc;
+ int i;
- mtx_enter(&dev->vbl_lock);
- if (!dev->vblank_disable_allowed)
+ mtx_enter(&vbl->vb_lock);
+ if (!vbl->vb_disable_allowed)
goto out;
- for (i=0; i < dev->num_crtcs; i++){
- if (atomic_read(&dev->vblank[i].vbl_refcount) == 0 &&
- dev->vblank[i].vbl_enabled) {
- dev->vblank[i].last_vblank =
+ for (i = 0; i < vbl->vb_num; i++) {
+ crtc = &vbl->vb_crtcs[i];
+
+ if (crtc->vbl_refs == 0 && crtc->vbl_enabled) {
+ crtc->vbl_last =
dev->driver->get_vblank_counter(dev, i);
dev->driver->disable_vblank(dev, i);
- dev->vblank[i].vbl_enabled = 0;
+ crtc->vbl_enabled = 0;
}
}
out:
- mtx_leave(&dev->vbl_lock);
+ mtx_leave(&vbl->vb_lock);
}
void
drm_vblank_cleanup(struct drm_device *dev)
{
- if (dev->num_crtcs == 0)
+ if (dev->vblank == NULL)
return; /* not initialised */
- timeout_del(&dev->vblank_disable_timer);
+ timeout_del(&dev->vblank->vb_disable_timer);
vblank_disable(dev);
drm_free(dev->vblank);
-
dev->vblank = NULL;
- dev->num_crtcs = 0;
}
int
drm_vblank_init(struct drm_device *dev, int num_crtcs)
{
- timeout_set(&dev->vblank_disable_timer, vblank_disable, dev);
- mtx_init(&dev->vbl_lock, IPL_BIO);
- dev->num_crtcs = num_crtcs;
-
- dev->vblank = drm_calloc(num_crtcs, sizeof(*dev->vblank));
+ dev->vblank = malloc(sizeof(*dev->vblank) + (num_crtcs *
+ sizeof(struct drm_vblank)), M_DRM, M_WAITOK | M_CANFAIL | M_ZERO);
if (dev->vblank == NULL)
- goto err;
+ return (ENOMEM);
- dev->vblank_disable_allowed = 0;
+ dev->vblank->vb_num = num_crtcs;
+ mtx_init(&dev->vblank->vb_lock, IPL_BIO);
+ timeout_set(&dev->vblank->vb_disable_timer, vblank_disable, dev);
return (0);
-
-err:
- drm_vblank_cleanup(dev);
- return ENOMEM;
}
u_int32_t
drm_vblank_count(struct drm_device *dev, int crtc)
{
- return atomic_read(&dev->vblank[crtc].vbl_count);
+ return (dev->vblank->vb_crtcs[crtc].vbl_count);
}
void
drm_update_vblank_count(struct drm_device *dev, int crtc)
{
- u_int32_t cur_vblank, diff;
+ u_int32_t cur_vblank, diff;
/*
* Interrupt was disabled prior to this call, so deal with counter wrap
- * note that we may have lost a full dev->max_vblank_count events if
+ * note that we may have lost a full vb_max events if
* the register is small or the interrupts were off for a long time.
*/
cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
- diff = cur_vblank - dev->vblank[crtc].last_vblank;
- if (cur_vblank < dev->vblank[crtc].last_vblank)
- diff += dev->max_vblank_count;
+ diff = cur_vblank - dev->vblank->vb_crtcs[crtc].vbl_last;
+ if (cur_vblank < dev->vblank->vb_crtcs[crtc].vbl_last)
+ diff += dev->vblank->vb_max;
- atomic_add(diff, &dev->vblank[crtc].vbl_count);
+ dev->vblank->vb_crtcs[crtc].vbl_count += diff;
}
int
drm_vblank_get(struct drm_device *dev, int crtc)
{
- int ret = 0;
+ struct drm_vblank_info *vbl = dev->vblank;
+ int ret = 0;
if (dev->irq_enabled == 0)
return (EINVAL);
- mtx_enter(&dev->vbl_lock);
- atomic_add(1, &dev->vblank[crtc].vbl_refcount);
- if (dev->vblank[crtc].vbl_refcount == 1 &&
- dev->vblank[crtc].vbl_enabled == 0) {
+ mtx_enter(&vbl->vb_lock);
+ vbl->vb_crtcs[crtc].vbl_refs++;
+ if (vbl->vb_crtcs[crtc].vbl_refs == 1 &&
+ vbl->vb_crtcs[crtc].vbl_enabled == 0) {
if ((ret = dev->driver->enable_vblank(dev, crtc)) == 0) {
- dev->vblank[crtc].vbl_enabled = 1;
+ vbl->vb_crtcs[crtc].vbl_enabled = 1;
drm_update_vblank_count(dev, crtc);
} else {
- atomic_dec(&dev->vblank[crtc].vbl_refcount);
+ vbl->vb_crtcs[crtc].vbl_refs--;
}
}
- mtx_leave(&dev->vbl_lock);
+ mtx_leave(&vbl->vb_lock);
return (ret);
}
@@ -253,30 +252,32 @@ drm_vblank_get(struct drm_device *dev, int crtc)
void
drm_vblank_put(struct drm_device *dev, int crtc)
{
- mtx_enter(&dev->vbl_lock);
- /* Last user schedules interrupt disable */
- atomic_dec(&dev->vblank[crtc].vbl_refcount);
- if (dev->vblank[crtc].vbl_refcount == 0)
- timeout_add_sec(&dev->vblank_disable_timer, 5);
- mtx_leave(&dev->vbl_lock);
+ mtx_enter(&dev->vblank->vb_lock);
+ /* Last user schedules disable */
+ if (--dev->vblank->vb_crtcs[crtc].vbl_refs == 0)
+ timeout_add_sec(&dev->vblank->vb_disable_timer, 5);
+ mtx_leave(&dev->vblank->vb_lock);
}
int
drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_modeset_ctl *modeset = data;
- int crtc, ret = 0;
+ struct drm_modeset_ctl *modeset = data;
+ int crtc, ret = 0;
+ struct drm_vblank *vbl;
/* not initialised yet, just noop */
- if (dev->num_crtcs == 0)
+ if (dev->vblank == NULL)
goto out;
crtc = modeset->crtc;
- if (crtc >= dev->num_crtcs) {
+ if (crtc >= dev->vblank->vb_num) {
ret = EINVAL;
goto out;
}
+ vbl = &dev->vblank->vb_crtcs[crtc];
+
/*
* If interrupts are enabled/disabled between calls to this ioctl then
* it can get nasty. So just grab a reference so that the interrupts
@@ -284,22 +285,22 @@ drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
*/
switch (modeset->cmd) {
case _DRM_PRE_MODESET:
- if (dev->vblank[crtc].vbl_inmodeset == 0) {
- mtx_enter(&dev->vbl_lock);
- dev->vblank[crtc].vbl_inmodeset = 0x1;
- mtx_leave(&dev->vbl_lock);
+ if (vbl->vbl_inmodeset == 0) {
+ mtx_enter(&dev->vblank->vb_lock);
+ vbl->vbl_inmodeset = 0x1;
+ mtx_leave(&dev->vblank->vb_lock);
if (drm_vblank_get(dev, crtc) == 0)
- dev->vblank[crtc].vbl_inmodeset |= 0x2;
+ vbl->vbl_inmodeset |= 0x2;
}
break;
case _DRM_POST_MODESET:
- if (dev->vblank[crtc].vbl_inmodeset) {
- mtx_enter(&dev->vbl_lock);
- dev->vblank_disable_allowed = 1;
- mtx_leave(&dev->vbl_lock);
- if (dev->vblank[crtc].vbl_inmodeset & 0x2)
+ if (vbl->vbl_inmodeset) {
+ mtx_enter(&dev->vblank->vb_lock);
+ dev->vblank->vb_disable_allowed = 1;
+ mtx_leave(&dev->vblank->vb_lock);
+ if (vbl->vbl_inmodeset & 0x2)
drm_vblank_put(dev, crtc);
- dev->vblank[crtc].vbl_inmodeset = 0;
+ vbl->vbl_inmodeset = 0;
}
break;
default:
@@ -314,20 +315,21 @@ out:
int
drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
+ struct timeval now;
union drm_wait_vblank *vblwait = data;
int ret, flags, crtc, seq;
- if (!dev->irq_enabled)
- return EINVAL;
+ if (!dev->irq_enabled || dev->vblank == NULL ||
+ vblwait->request.type & _DRM_VBLANK_SIGNAL)
+ return (EINVAL);
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
- if (crtc >= dev->num_crtcs)
- return EINVAL;
+ if (crtc >= dev->vblank->vb_num)
+ return (EINVAL);
- ret = drm_vblank_get(dev, crtc);
- if (ret)
+ if ((ret = drm_vblank_get(dev, crtc)) != 0)
return (ret);
seq = drm_vblank_count(dev,crtc);
@@ -342,23 +344,14 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
vblwait->request.sequence = seq + 1;
}
- if (flags & _DRM_VBLANK_SIGNAL) {
- ret = EINVAL;
- } else {
- DRM_WAIT_ON(ret, &dev->vblank[crtc], &dev->vbl_lock, 3 * hz,
- "drmvblq", ((drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23)) ||
- dev->irq_enabled == 0);
-
- if (ret != EINTR) {
- struct timeval now;
-
- microtime(&now);
- vblwait->reply.tval_sec = now.tv_sec;
- vblwait->reply.tval_usec = now.tv_usec;
- vblwait->reply.sequence = drm_vblank_count(dev, crtc);
- }
- }
+ DRM_WAIT_ON(ret, &dev->vblank->vb_crtcs[crtc], &dev->vblank->vb_lock,
+ 3 * hz, "drmvblq", ((drm_vblank_count(dev, crtc) -
+ vblwait->request.sequence) <= (1 << 23)) || dev->irq_enabled == 0);
+
+ microtime(&now);
+ vblwait->reply.tval_sec = now.tv_sec;
+ vblwait->reply.tval_usec = now.tv_usec;
+ vblwait->reply.sequence = drm_vblank_count(dev, crtc);
drm_vblank_put(dev, crtc);
return (ret);
@@ -367,6 +360,6 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
void
drm_handle_vblank(struct drm_device *dev, int crtc)
{
- atomic_inc(&dev->vblank[crtc].vbl_count);
- wakeup(&dev->vblank[crtc]);
+ dev->vblank->vb_crtcs[crtc].vbl_count++;
+ wakeup(&dev->vblank->vb_crtcs[crtc]);
}
diff --git a/sys/dev/pci/drm/i915_irq.c b/sys/dev/pci/drm/i915_irq.c
index ddae0f78138..9ac3585cc71 100644
--- a/sys/dev/pci/drm/i915_irq.c
+++ b/sys/dev/pci/drm/i915_irq.c
@@ -409,7 +409,7 @@ i915_driver_irq_install(struct drm_device *dev)
if (dev_priv->irqh == NULL)
return (ENOENT);
- dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+ dev->vblank->vb_max = 0xffffff; /* only 24 bits of frame count */
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
diff --git a/sys/dev/pci/drm/radeon_irq.c b/sys/dev/pci/drm/radeon_irq.c
index 544a3f3d32e..675de199612 100644
--- a/sys/dev/pci/drm/radeon_irq.c
+++ b/sys/dev/pci/drm/radeon_irq.c
@@ -347,7 +347,7 @@ radeon_driver_irq_install(struct drm_device * dev)
atomic_set(&dev_priv->swi_emitted, 0);
- dev->max_vblank_count = 0x001fffff;
+ dev->vblank->vb_max = 0x001fffff;
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);