int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *);
- int (*context_ctor) (struct drm_device * dev, int context);
- int (*context_dtor) (struct drm_device * dev, int context);
- int (*kernel_context_switch) (struct drm_device * dev, int old,
+ int (*context_ctor) (struct drm_device *dev, int context);
+ int (*context_dtor) (struct drm_device *dev, int context);
+ int (*kernel_context_switch) (struct drm_device *dev, int old,
int new);
- void (*kernel_context_switch_unlock) (struct drm_device *dev);
- int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence);
- int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence);
+ void (*kernel_context_switch_unlock) (struct drm_device * dev);
+ /**
+ * get_vblank_counter - get raw hardware vblank counter
+ * @dev: DRM device
+ * @crtc: counter to fetch
+ *
+ * Driver callback for fetching a raw hardware vblank counter
+ * for @crtc. If a device doesn't have a hardware counter, the
+ * driver can simply return the value of drm_vblank_count and
+ * make the enable_vblank() and disable_vblank() hooks into no-ops,
+ * leaving interrupts enabled at all times.
+ *
+ * Wraparound handling and loss of events due to modesetting is dealt
+ * with in the DRM core code.
+ *
+ * RETURNS
+ * Raw vblank counter value.
+ */
+ u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
+
+ /**
+ * enable_vblank - enable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Enable vblank interrupts for @crtc. If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ *
+ * RETURNS
+ * Zero on success, appropriate errno if the given @crtc's vblank
+ * interrupt cannot be enabled.
+ */
+ int (*enable_vblank) (struct drm_device *dev, int crtc);
+
+ /**
+ * disable_vblank - disable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Disable vblank interrupts for @crtc. If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ */
+ void (*disable_vblank) (struct drm_device *dev, int crtc);
- int (*dri_library_name) (struct drm_device * dev, char * buf);
+ int (*dri_library_name) (struct drm_device *dev, char * buf);
/**
* Called by \c drm_device_is_agp. Typically used to determine if a
/* these have to be filled in */
irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
- void (*irq_preinstall) (struct drm_device * dev);
- int (*irq_postinstall) (struct drm_device * dev);
- void (*irq_uninstall) (struct drm_device * dev);
+ void (*irq_preinstall) (struct drm_device *dev);
- void (*irq_postinstall) (struct drm_device *dev);
++ int (*irq_postinstall) (struct drm_device *dev);
+ void (*irq_uninstall) (struct drm_device *dev);
void (*reclaim_buffers) (struct drm_device *dev,
struct drm_file *file_priv);
void (*reclaim_buffers_locked) (struct drm_device *dev,
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
-
+ DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl,
+ DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl,
+ DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl,
+ DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH),
dev->irq_enabled = 1;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
+ DRM_DEBUG("irq=%d\n", dev->irq);
- if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
- init_waitqueue_head(&dev->vbl_queue);
-
- spin_lock_init(&dev->vbl_lock);
-
- INIT_LIST_HEAD(&dev->vbl_sigs);
- INIT_LIST_HEAD(&dev->vbl_sigs2);
-
- dev->vbl_pending = 0;
- }
-
/* Before installing handler */
dev->driver->irq_preinstall(dev);
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA
-- | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
++ | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.lastclose = mach64_driver_lastclose,
-- .vblank_wait = mach64_driver_vblank_wait,
++ .get_vblank_counter = mach64_get_vblank_counter,
++ .enable_vblank = mach64_enable_vblank,
++ .disable_vblank = mach64_disable_vblank,
.irq_preinstall = mach64_driver_irq_preinstall,
.irq_postinstall = mach64_driver_irq_postinstall,
.irq_uninstall = mach64_driver_irq_uninstall,
pipea_stats = I915_READ(I915REG_PIPEASTAT);
pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
-
+
temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
#if 0
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+ DRM_DEBUG("flag=%08x\n", temp);
#endif
if (temp == 0)
return IRQ_NONE;
#endif
}
- if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- int vblank_pipe = dev_priv->vblank_pipe;
-
- if ((vblank_pipe &
- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & VSYNC_PIPEA_FLAG)
- atomic_inc(&dev->vbl_received);
- if (temp & VSYNC_PIPEB_FLAG)
- atomic_inc(&dev->vbl_received2);
- } else if (((temp & VSYNC_PIPEA_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & VSYNC_PIPEB_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
- atomic_inc(&dev->vbl_received);
-
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ /*
+ * Use drm_update_vblank_counter here to deal with potential lost
+ * interrupts
+ */
+ if (temp & VSYNC_PIPEA_FLAG)
+ drm_handle_vblank(dev, 0);
+ if (temp & VSYNC_PIPEB_FLAG)
+ drm_handle_vblank(dev, 1);
+ if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
- I915_WRITE(I915REG_PIPEASTAT,
+ I915_WRITE(I915REG_PIPEASTAT,
pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
I915_VBLANK_CLEAR);
I915_WRITE(I915REG_PIPEBSTAT,
return ret;
}
-static int i915_driver_vblank_do_wait(struct drm_device *dev,
- unsigned int *sequence,
- atomic_t *counter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1<<23)));
-
- *sequence = cur_vblank;
-
- return ret;
-}
-
-int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
-
/* Needs the lock as it touches the ring.
*/
- int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
+ int i915_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_irq_emit_t *emit = data;
* Initialize the hardware status page IRQ location.
*/
- I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21));
+ I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
+ return 0;
}
void i915_driver_irq_uninstall(struct drm_device * dev)
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
++ atomic_t vbl_received; /**< Number of vblanks received. */
++
u32 front_offset_pitch;
u32 back_offset_pitch;
u32 depth_offset_pitch;
struct drm_file *file_priv);
extern int mach64_get_param(struct drm_device *dev, void *data,
struct drm_file *file_priv);
--extern int mach64_driver_vblank_wait(struct drm_device * dev,
-- unsigned int *sequence);
++extern u32 mach64_get_vblank_counter(struct drm_device *dev, int crtc);
++extern int mach64_enable_vblank(struct drm_device *dev, int crtc);
++extern void mach64_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS);
--extern void mach64_driver_irq_preinstall(struct drm_device * dev);
--extern void mach64_driver_irq_postinstall(struct drm_device * dev);
--extern void mach64_driver_irq_uninstall(struct drm_device * dev);
++extern void mach64_driver_irq_preinstall(struct drm_device *dev);
++extern int mach64_driver_irq_postinstall(struct drm_device *dev);
++extern void mach64_driver_irq_uninstall(struct drm_device *dev);
/* ================================================================
* Registers
irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
{
-- struct drm_device *dev = (struct drm_device *) arg;
-- drm_mach64_private_t *dev_priv =
-- (drm_mach64_private_t *) dev->dev_private;
++ struct drm_device *dev = arg;
++ drm_mach64_private_t *dev_priv = dev->dev_private;
int status;
status = MACH64_READ(MACH64_CRTC_INT_CNTL);
(status & ~MACH64_CRTC_INT_ACKS)
| MACH64_CRTC_VBLANK_INT);
-- atomic_inc(&dev->vbl_received);
-- DRM_WAKEUP(&dev->vbl_queue);
-- drm_vbl_send_signals(dev);
++ atomic_inc(&dev_priv->vbl_received);
++ drm_handle_vblank(dev, 0);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
--int mach64_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
++u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc)
{
-- unsigned int cur_vblank;
-- int ret = 0;
--
-- /* Assume that the user has missed the current sequence number
-- * by about a day rather than she wants to wait for years
-- * using vertical blanks...
-- */
-- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-- (((cur_vblank = atomic_read(&dev->vbl_received))
-- - *sequence) <= (1 << 23)));
++ const drm_mach64_private_t *const dev_priv = dev->dev_private;
++
++ if (crtc != 0) {
++ return 0;
++ }
++
++ return atomic_read(&dev_priv->vbl_received);
++}
-- *sequence = cur_vblank;
++int mach64_enable_vblank(struct drm_device * dev, int crtc)
++{
++ drm_mach64_private_t *dev_priv = dev->dev_private;
++ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
++
++ if (crtc != 0) {
++ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc);
++ return 0;
++ }
++
++ DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
++
++ /* Turn on VBLANK interrupt */
++ MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
++ | MACH64_CRTC_VBLANK_INT_EN);
-- return ret;
++ return 0;
}
--/* drm_dma.h hooks
--*/
--void mach64_driver_irq_preinstall(struct drm_device * dev)
--{
-- drm_mach64_private_t *dev_priv =
-- (drm_mach64_private_t *) dev->dev_private;
++void mach64_disable_vblank(struct drm_device * dev, int crtc)
++{
++ drm_mach64_private_t *dev_priv = dev->dev_private;
u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
-- DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
++ DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
/* Disable and clear VBLANK interrupt */
MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
| MACH64_CRTC_VBLANK_INT);
}
--void mach64_driver_irq_postinstall(struct drm_device * dev)
++/* drm_dma.h hooks
++*/
++void mach64_driver_irq_preinstall(struct drm_device * dev)
{
-- drm_mach64_private_t *dev_priv =
-- (drm_mach64_private_t *) dev->dev_private;
++ drm_mach64_private_t *dev_priv = dev->dev_private;
-- /* Turn on VBLANK interrupt */
-- MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
-- | MACH64_CRTC_VBLANK_INT_EN);
++ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
-- DRM_DEBUG("after install CRTC_INT_CTNL: 0x%08x\n",
-- MACH64_READ(MACH64_CRTC_INT_CNTL));
++ DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
++ mach64_disable_vblank(dev,0);
++}
++
++int mach64_driver_irq_postinstall(struct drm_device * dev)
++{
++ return drm_vblank_init(dev, 1);
}
void mach64_driver_irq_uninstall(struct drm_device * dev)
{
-- drm_mach64_private_t *dev_priv =
-- (drm_mach64_private_t *) dev->dev_private;
++ drm_mach64_private_t *dev_priv = dev->dev_private;
if (!dev_priv)
return;
-- /* Disable and clear VBLANK interrupt */
-- MACH64_WRITE(MACH64_CRTC_INT_CNTL,
-- (MACH64_READ(MACH64_CRTC_INT_CNTL) &
-- ~MACH64_CRTC_VBLANK_INT_EN)
-- | MACH64_CRTC_VBLANK_INT);
++ mach64_disable_vblank(dev, 0);
DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
MACH64_READ(MACH64_CRTC_INT_CNTL));
handled = 1;
}
- return (handled) ? IRQ_HANDLED : IRQ_NONE;
+ if (handled)
+ return IRQ_HANDLED;
+ return IRQ_NONE;
}
-int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int mga_enable_vblank(struct drm_device *dev, int crtc)
{
- unsigned int cur_vblank;
- int ret = 0;
+ drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
- - *sequence) <= (1 << 23)));
+ if (crtc != 0) {
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return 0;
+ }
- *sequence = cur_vblank;
+ MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+ return 0;
+}
- return ret;
+
+void mga_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0) {
+ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+ crtc);
+ }
+
+ /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
+ * a nice hardware counter that tracks the number of refreshes when
+ * the interrupt is disabled, and the kernel doesn't know the refresh
+ * rate to calculate an estimate.
+ */
+ /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
}
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
u32 scratch_ages[5];
+ unsigned int crtc_last_cnt;
+ unsigned int crtc2_last_cnt;
+
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
+ unsigned long fb_aper_offset;
} drm_radeon_private_t;
return ret;
}
-static int radeon_driver_vblank_do_wait(struct drm_device * dev,
- unsigned int *sequence, int crtc)
+u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
- int ack = 0;
- atomic_t *counter;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ u32 crtc_cnt_reg, crtc_status_reg;
+
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
- static unsigned time_diff(struct timeval *now,struct timeval *then)
+ static unsigned time_diff(struct timeval *now,struct timeval *then)
{
- return (now->tv_usec >= then->tv_usec) ?
- now->tv_usec - then->tv_usec :
- 1000000 - (then->tv_usec - now->tv_usec);
+ return (now->tv_usec >= then->tv_usec) ?
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
}
+u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
+}
+
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1;
}
- if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+ if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
DRM_DEBUG("US per vblank is: %u\n",
- dev_priv->usec_per_vblank);
+ dev_priv->usec_per_vblank);
}
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ drm_handle_vblank(dev, 0);
handled = 1;
}
-
- for (i=0; i<dev_priv->num_irqs; ++i) {
+
+ for (i = 0; i < dev_priv->num_irqs; ++i) {
if (status & cur_irq->pending_mask) {
- atomic_inc( &cur_irq->irq_received );
- DRM_WAKEUP( &cur_irq->irq_queue );
+ atomic_inc(&cur_irq->irq_received);
+ DRM_WAKEUP(&cur_irq->irq_queue);
handled = 1;
#ifdef VIA_HAVE_DMABLIT
if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
return -EINVAL;
}
- viadrv_acknowledge_irqs(dev_priv);
-
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
-
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received)) -
- *sequence) <= (1 << 23)));
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+ return 0;
+}
- *sequence = cur_vblank;
- return ret;
+void via_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0)
+ DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
-
- /*
- * FIXME: implement proper interrupt disable by using the vblank
- * counter register (if available).
- */
}
static int