summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-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);