From db689c7b95613237cec904c3f6ee27e8c2bf7ce0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Jun 2007 10:44:21 -0700 Subject: Initial checkin of vblank rework. Code attempts to reduce the number of vblank interrupt in order to save power. --- shared-core/i915_irq.c | 164 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 41 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index dc00f983..1019c942 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -92,8 +92,8 @@ static void i915_vblank_tasklet(drm_device_t *dev) unsigned long irqflags; struct list_head *list, *tmp, hits, *hit; int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; - unsigned counter[2] = { atomic_read(&dev->vbl_received), - atomic_read(&dev->vbl_received2) }; + unsigned counter[2] = { atomic_read(&dev->vblank_count[0]), + atomic_read(&dev->vblank_count[1]) }; drm_drawable_info_t *drw; drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; u32 cpp = dev_priv->cpp, offsets[3]; @@ -313,14 +313,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) (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); + atomic_inc(&dev->vblank_count[0]); if (temp & VSYNC_PIPEB_FLAG) - atomic_inc(&dev->vbl_received2); + atomic_inc(&dev->vblank_count[1]); } 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); + atomic_inc(&dev->vblank_count[0]); DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); @@ -410,37 +410,6 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return ret; } -static int i915_driver_vblank_do_wait(drm_device_t *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("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(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(drm_device_t *dev, unsigned int *sequence) -{ - return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); -} - -int i915_driver_vblank_wait2(drm_device_t *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(DRM_IOCTL_ARGS) @@ -489,15 +458,99 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static void i915_enable_interrupt (drm_device_t *dev) +void i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->irq_enable_reg = USER_INT_FLAG; - if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) + switch (crtc) { + case 0: dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; - if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) + break; + case 1: dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; + break; + default: + DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", + crtc); + break; + } + + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); +} + +void i915_disable_vblank(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + switch (crtc) { + case 0: + dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; + break; + case 1: + dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG; + break; + default: + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + break; + } + + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); +} + +static u32 i915_vblank_counter(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + u32 high1, high2, low, count; + + /* + * High & low register fields aren't synchronized, so make sure + * we get a low value that's stable across two reads of the high + * register. + */ + do { + high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> + PIPE_FRAME_LOW_SHIFT); + high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + } while (high1 != high2); + + count = (high1 << 8) | low; + + return count; +} + +u32 i915_get_vblank_counter(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + return i915_vblank_counter(dev, crtc) + dev_priv->vblank_offset[crtc]; +} + +void i915_premodeset(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + dev_priv->vblank_premodeset[crtc] = i915_vblank_counter(dev, crtc); +} + +void i915_postmodeset(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 new; + + new = i915_vblank_counter(dev, crtc); + dev_priv->vblank_offset[crtc] = dev_priv->vblank_premodeset[crtc] - new; +} + +static void i915_enable_interrupt (drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + dev_priv->irq_enable_reg |= USER_INT_FLAG; I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; @@ -607,7 +660,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); - curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + curseq = atomic_read(&dev->vblank_count[pipe]); if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; @@ -714,6 +767,7 @@ void i915_driver_irq_preinstall(drm_device_t * dev) void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int i; spin_lock_init(&dev_priv->swaps_lock); INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); @@ -721,6 +775,34 @@ void i915_driver_irq_postinstall(drm_device_t * dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; + dev_priv->irq_enable_reg = 0; + dev->vblank_count = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); + if (!dev->vblank_count) { + DRM_ERROR("out of memory\n"); + return; + } + dev->vbl_pending = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); + if (!dev->vbl_pending) { + DRM_ERROR("out of memory\n"); + kfree(dev->vblank_count); + return; + } + dev->last_vblank = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); + if (!dev->last_vblank) { + DRM_ERROR("out of memory\n"); + kfree(dev->vblank_count); + return; + } + + /* Zero per-crtc vblank stuff */ + for (i = 0; i < 2; i++) { + atomic_set(&dev->vbl_pending[i], 0); + atomic_set(&dev->vblank_count[i], 0); + dev->last_vblank[i] = 0; + dev_priv->vblank_offset[i] = 0; + } + + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); -- cgit v1.2.3 From ca47fa90b73d0eac73fb7d1ba712d81e180eae7d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Jun 2007 13:35:41 -0700 Subject: Update vblank code: - move pre/post modeset ioctl to core - fixup i915 buffer swap - fix outstanding signal count code - create new core vblank init routine - test (works with glxgears) - simplify i915 interrupt handler --- shared-core/i915_irq.c | 143 +++++++++++++++++++------------------------------ 1 file changed, 54 insertions(+), 89 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 1019c942..0f4d1a81 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -117,12 +117,14 @@ static void i915_vblank_tasklet(drm_device_t *dev) list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { drm_i915_vbl_swap_t *vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + int crtc = vbl_swap->pipe; if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) continue; list_del(list); dev_priv->swaps_pending--; + drm_vblank_put(dev, crtc); spin_unlock(&dev_priv->swaps_lock); spin_lock(&dev->drw_lock); @@ -274,6 +276,32 @@ static void i915_vblank_tasklet(drm_device_t *dev) } } +u32 i915_get_vblank_counter(drm_device_t *dev, int crtc) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + u32 high1, high2, low, count; + + /* + * High & low register fields aren't synchronized, so make sure + * we get a low value that's stable across two reads of the high + * register. + */ + do { + high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> + PIPE_FRAME_LOW_SHIFT); + high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + } while (high1 != high2); + + count = (high1 << 8) | low; + + return count; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -306,22 +334,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #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->vblank_count[0]); - if (temp & VSYNC_PIPEB_FLAG) - atomic_inc(&dev->vblank_count[1]); - } 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->vblank_count[0]); + if (temp & VSYNC_PIPEA_FLAG) + atomic_add(i915_get_vblank_counter(dev, 0), + &dev->vblank_count[0]); + if (temp & VSYNC_PIPEB_FLAG) + atomic_add(i915_get_vblank_counter(dev, 1), + &dev->vblank_count[1]); + if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); @@ -461,6 +481,9 @@ int i915_irq_wait(DRM_IOCTL_ARGS) void i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + if (crtc > dev_priv->vblank_pipe) + return; switch (crtc) { case 0: @@ -481,6 +504,9 @@ void i915_enable_vblank(drm_device_t *dev, int crtc) void i915_disable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + if (crtc > dev_priv->vblank_pipe) + return; switch (crtc) { case 0: @@ -498,54 +524,6 @@ void i915_disable_vblank(drm_device_t *dev, int crtc) I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } -static u32 i915_vblank_counter(drm_device_t *dev, int crtc) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; - u32 high1, high2, low, count; - - /* - * High & low register fields aren't synchronized, so make sure - * we get a low value that's stable across two reads of the high - * register. - */ - do { - high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> - PIPE_FRAME_LOW_SHIFT); - high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - } while (high1 != high2); - - count = (high1 << 8) | low; - - return count; -} - -u32 i915_get_vblank_counter(drm_device_t *dev, int crtc) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - return i915_vblank_counter(dev, crtc) + dev_priv->vblank_offset[crtc]; -} - -void i915_premodeset(drm_device_t *dev, int crtc) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - dev_priv->vblank_premodeset[crtc] = i915_vblank_counter(dev, crtc); -} - -void i915_postmodeset(drm_device_t *dev, int crtc) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - u32 new; - - new = i915_vblank_counter(dev, crtc); - dev_priv->vblank_offset[crtc] = dev_priv->vblank_premodeset[crtc] - new; -} - static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -660,6 +638,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + drm_vblank_get(dev, pipe); curseq = atomic_read(&dev->vblank_count[pipe]); if (seqtype == _DRM_VBLANK_RELATIVE) @@ -670,6 +649,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence = curseq + 1; } else { DRM_DEBUG("Missed target sequence\n"); + drm_vblank_put(dev, pipe); return DRM_ERR(EINVAL); } } @@ -690,6 +670,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable); + drm_vblank_put(dev, pipe); return DRM_ERR(EINVAL); } @@ -697,6 +678,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + drm_vblank_put(dev, pipe); return 0; } } @@ -712,6 +694,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP); spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); + drm_vblank_put(dev, pipe); return 0; } } @@ -720,6 +703,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (dev_priv->swaps_pending >= 100) { DRM_DEBUG("Too many swaps queued\n"); + drm_vblank_put(dev, pipe); return DRM_ERR(EBUSY); } @@ -727,6 +711,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (!vbl_swap) { DRM_ERROR("Failed to allocate memory to queue swap\n"); + drm_vblank_put(dev, pipe); return DRM_ERR(ENOMEM); } @@ -764,10 +749,10 @@ void i915_driver_irq_preinstall(drm_device_t * dev) I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); } -void i915_driver_irq_postinstall(drm_device_t * dev) +int i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int i; + int ret, num_pipes = 2; spin_lock_init(&dev_priv->swaps_lock); INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); @@ -776,31 +761,10 @@ void i915_driver_irq_postinstall(drm_device_t * dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = 0; - dev->vblank_count = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); - if (!dev->vblank_count) { - DRM_ERROR("out of memory\n"); - return; - } - dev->vbl_pending = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); - if (!dev->vbl_pending) { - DRM_ERROR("out of memory\n"); - kfree(dev->vblank_count); - return; - } - dev->last_vblank = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL); - if (!dev->last_vblank) { - DRM_ERROR("out of memory\n"); - kfree(dev->vblank_count); - return; - } - /* Zero per-crtc vblank stuff */ - for (i = 0; i < 2; i++) { - atomic_set(&dev->vbl_pending[i], 0); - atomic_set(&dev->vblank_count[i], 0); - dev->last_vblank[i] = 0; - dev_priv->vblank_offset[i] = 0; - } + ret = drm_vblank_init(dev, num_pipes); + if (ret) + return ret; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ @@ -812,6 +776,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) */ I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21)); + return 0; } void i915_driver_irq_uninstall(drm_device_t * dev) -- cgit v1.2.3 From 1a4b9294a29379ea6e9fd6fb315317f391232d4b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Jun 2007 16:29:09 -0700 Subject: Remove unnecessary (and uncommented!) read barrier from the interrupt path. It doesn't appear to serve any useful purpose. --- shared-core/i915_irq.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0f4d1a81..46b97e39 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -323,7 +323,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE16(I915REG_INT_IDENTITY_R, temp); (void) I915_READ16(I915REG_INT_IDENTITY_R); - DRM_READMEMORYBARRIER(); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); -- cgit v1.2.3 From b06268294afb47e62949984d73905344dd160262 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 14 Jun 2007 11:32:31 -0700 Subject: Comment new vblank routines and fixup several issues: - use correct refcount variable in get/put routines - extract counter update from drm_vblank_get - make signal handling callback per-crtc - update interrupt handling logic, drivers should use drm_handle_vblank - move wakeup and counter update logic to new drm_handle_vblank routine - fixup usage of get/put in light of counter update extraction - fix longstanding bug in signal code, update pending counter only *after* we're sure we'll setup signal handling --- shared-core/i915_irq.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 46b97e39..e91add9d 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -92,8 +92,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) unsigned long irqflags; struct list_head *list, *tmp, hits, *hit; int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; - unsigned counter[2] = { atomic_read(&dev->vblank_count[0]), - atomic_read(&dev->vblank_count[1]) }; + unsigned counter[2]; drm_drawable_info_t *drw; drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; u32 cpp = dev_priv->cpp, offsets[3]; @@ -105,6 +104,9 @@ static void i915_vblank_tasklet(drm_device_t *dev) (cpp << 23) | (1 << 24); RING_LOCALS; + counter[0] = drm_vblank_count(dev, 0); + counter[1] = drm_vblank_count(dev, 1); + DRM_DEBUG("\n"); INIT_LIST_HEAD(&hits); @@ -333,16 +335,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #endif } + /* + * Use drm_update_vblank_counter here to deal with potential lost + * interrupts + */ if (temp & VSYNC_PIPEA_FLAG) - atomic_add(i915_get_vblank_counter(dev, 0), - &dev->vblank_count[0]); + drm_handle_vblank(dev, 0); if (temp & VSYNC_PIPEB_FLAG) - atomic_add(i915_get_vblank_counter(dev, 1), - &dev->vblank_count[1]); + drm_handle_vblank(dev, 1); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { DRM_WAKEUP(&dev->vbl_queue); - drm_vbl_send_signals(dev); if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); @@ -477,12 +480,12 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -void i915_enable_vblank(drm_device_t *dev, int crtc) +int i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (crtc > dev_priv->vblank_pipe) - return; + if (dev_priv->vblank_pipe != (1 << crtc)) + return -EINVAL; switch (crtc) { case 0: @@ -498,6 +501,8 @@ void i915_enable_vblank(drm_device_t *dev, int crtc) } I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + + return 0; } void i915_disable_vblank(drm_device_t *dev, int crtc) @@ -597,6 +602,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) unsigned int pipe, seqtype, curseq; unsigned long irqflags; struct list_head *list; + int ret; if (!dev_priv) { DRM_ERROR("%s called with no initialization\n", __func__); @@ -637,8 +643,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); - drm_vblank_get(dev, pipe); - curseq = atomic_read(&dev->vblank_count[pipe]); + drm_update_vblank_count(dev, pipe); + curseq = drm_vblank_count(dev, pipe); if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; @@ -648,7 +654,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence = curseq + 1; } else { DRM_DEBUG("Missed target sequence\n"); - drm_vblank_put(dev, pipe); return DRM_ERR(EINVAL); } } @@ -669,7 +674,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable); - drm_vblank_put(dev, pipe); return DRM_ERR(EINVAL); } @@ -677,7 +681,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); - drm_vblank_put(dev, pipe); return 0; } } @@ -693,7 +696,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP); spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); - drm_vblank_put(dev, pipe); return 0; } } @@ -702,7 +704,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (dev_priv->swaps_pending >= 100) { DRM_DEBUG("Too many swaps queued\n"); - drm_vblank_put(dev, pipe); return DRM_ERR(EBUSY); } @@ -710,12 +711,15 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) if (!vbl_swap) { DRM_ERROR("Failed to allocate memory to queue swap\n"); - drm_vblank_put(dev, pipe); return DRM_ERR(ENOMEM); } DRM_DEBUG("\n"); + ret = drm_vblank_get(dev, pipe); + if (ret) + return ret; + vbl_swap->drw_id = swap.drawable; vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; -- cgit v1.2.3 From 1000d88ddfcd0ae769125db37d4e78643a430caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:10:33 +0200 Subject: Fix memory leaks in vblank error paths. Also use drm_calloc instead of drm_alloc and memset, and use the size of the struct instead of the size of the pointer for allocation... --- shared-core/i915_irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index e91add9d..ad2cf9c2 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -707,7 +707,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EBUSY); } - vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { DRM_ERROR("Failed to allocate memory to queue swap\n"); @@ -717,8 +717,10 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); ret = drm_vblank_get(dev, pipe); - if (ret) + if (ret) { + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); return ret; + } vbl_swap->drw_id = swap.drawable; vbl_swap->pipe = pipe; -- cgit v1.2.3 From 914a810a82af6f82e69a94448570772f20a94953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:21:44 +0200 Subject: i915: Fix tests for vblank interrupts being enabled on CRTC by X server. --- shared-core/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ad2cf9c2..9861af97 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -484,7 +484,7 @@ int i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (dev_priv->vblank_pipe != (1 << crtc)) + if (!(dev_priv->vblank_pipe & (1 << crtc))) return -EINVAL; switch (crtc) { @@ -509,7 +509,7 @@ void i915_disable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (crtc > dev_priv->vblank_pipe) + if (!(dev_priv->vblank_pipe & (1 << crtc))) return; switch (crtc) { -- cgit v1.2.3 From 82e2c3304d3f1697537b73a2c888c8c6b1b6cdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Jun 2007 10:25:50 +0200 Subject: Wake up vblank waitqueue in drm_handle_vblank(). --- shared-core/i915_irq.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9861af97..00400fa2 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -345,8 +345,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) drm_handle_vblank(dev, 1); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - DRM_WAKEUP(&dev->vbl_queue); - if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); I915_WRITE(I915REG_PIPEASTAT, -- cgit v1.2.3 From 2d24455ed8b12df6d06d135cb70f02473d11f4b0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 18 Jun 2007 17:43:58 -0700 Subject: Remove broken CRTC enable checks and incorrect user irq enable in set_pipe routine. --- shared-core/i915_irq.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 00400fa2..713ec654 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -482,9 +482,6 @@ int i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (!(dev_priv->vblank_pipe & (1 << crtc))) - return -EINVAL; - switch (crtc) { case 0: dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; @@ -507,9 +504,6 @@ void i915_disable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (!(dev_priv->vblank_pipe & (1 << crtc))) - return; - switch (crtc) { case 0: dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; @@ -560,8 +554,6 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) dev_priv->vblank_pipe = pipe.pipe; - i915_enable_interrupt (dev); - return 0; } -- cgit v1.2.3 From 97dcd7fd25c18d5148619254229f8d94efb55b44 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 22 Jun 2007 11:06:51 -0700 Subject: more vblank rework - use a timer for disabling vblank events to avoid enable/disable calls too often - make i915 work with pre-965 chips again (would like to structure this better, but this hack works on my test system) --- shared-core/i915_irq.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 713ec654..c0c1bf9e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -285,6 +285,9 @@ u32 i915_get_vblank_counter(drm_device_t *dev, int crtc) unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; u32 high1, high2, low, count; + if (!IS_I965G(dev)) + return 0; + /* * High & low register fields aren't synchronized, so make sure * we get a low value that's stable across two reads of the high @@ -315,7 +318,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 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); @@ -324,7 +326,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); + (void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */ + + temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG | + VSYNC_PIPEB_FLAG); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -335,6 +340,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #endif } + if (!IS_I965G(dev)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->_vblank_count[0]); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->_vblank_count[1]); + } + /* * Use drm_update_vblank_counter here to deal with potential lost * interrupts @@ -482,6 +494,9 @@ int i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!IS_I965G(dev)) + return 0; + switch (crtc) { case 0: dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; @@ -504,6 +519,9 @@ void i915_disable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!IS_I965G(dev)) + return; + switch (crtc) { case 0: dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; @@ -763,6 +781,11 @@ int i915_driver_irq_postinstall(drm_device_t * dev) dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (!IS_I965G(dev)) { + dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); -- cgit v1.2.3 From 2db6400396ea5c8a5ce54fe9e211b9d01a11d506 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Dec 2007 09:50:45 +1000 Subject: drm: don't cast a pointer to pointer of list_head The casting is safe only when the list_head member is the first member of the structure. --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ee7c40b5..7e3d3f3b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -719,7 +719,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); - list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head); + list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head); dev_priv->swaps_pending++; DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); -- cgit v1.2.3 From 9ab620d661253f9b08f683a2a6f9ddee002015bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Thu, 3 Jan 2008 16:56:04 +1000 Subject: drm: cleanup DRM_DEBUG() parameters As DRM_DEBUG macro already prints out the __FUNCTION__ string (see drivers/char/drm/drmP.h), it is not worth doing this again. At some other places the ending "\n" was added. airlied:- I cleaned up a few that this patch missed also --- shared-core/i915_irq.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 7e3d3f3b..75952001 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -315,7 +315,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 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; @@ -372,7 +372,7 @@ int i915_emit_irq(struct drm_device *dev) i915_kernel_lost_context(dev); - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); i915_emit_breadcrumb(dev); @@ -411,7 +411,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = 0; - DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, + DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); if (READ_BREADCRUMB(dev_priv) >= irq_nr) @@ -423,8 +423,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) i915_user_irq_off(dev_priv); if (ret == -EBUSY) { - DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", - __FUNCTION__, + DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } @@ -441,7 +440,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, int ret = 0; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("called with no initialization\n"); return -EINVAL; } @@ -489,7 +488,7 @@ int i915_irq_emit(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("called with no initialization\n"); return -EINVAL; } @@ -512,7 +511,7 @@ int i915_irq_wait(struct drm_device *dev, void *data, drm_i915_irq_wait_t *irqwait = data; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("called with no initialization\n"); return -EINVAL; } @@ -542,13 +541,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, drm_i915_vblank_pipe_t *pipe = data; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("called with no initialization\n"); return -EINVAL; } if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, pipe->pipe); + DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); return -EINVAL; } @@ -567,7 +565,7 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, u16 flag; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("called with no initialization\n"); return -EINVAL; } -- cgit v1.2.3 From 5231a524f53babd127a576d7567671dafb29651b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 22 Jan 2008 14:39:28 +1100 Subject: Revert "Fix pipe<->plane mapping vs. vblank handling (again)" This reverts commit bfc29606e4a818897eebca46a5e23bbe7bc3ce25. This regresses i915 here for me I can't get greater than 0.333 fps with gears --- shared-core/i915_irq.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 75952001..4a968002 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -455,25 +455,12 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) { - atomic_t *counter; - - if (i915_get_pipe(dev, 0) == 0) - counter = &dev->vbl_received; - else - counter = &dev->vbl_received2; - return i915_driver_vblank_do_wait(dev, sequence, counter); + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); } int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) { - atomic_t *counter; - - if (i915_get_pipe(dev, 1) == 0) - counter = &dev->vbl_received; - else - counter = &dev->vbl_received2; - - return i915_driver_vblank_do_wait(dev, sequence, counter); + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); } /* Needs the lock as it touches the ring. -- cgit v1.2.3 From 893e311999d1565943899d73c56c674fc9b6e502 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 Jan 2008 13:11:29 -0800 Subject: i915 irq fixes Ack the IRQs correctly (PIPExSTAT first followed by IIR). Don't read vblank counter registers on disabled pipes (might hang otherwise). And deal with flipped pipe/plane mappings if present. --- shared-core/i915_irq.c | 119 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 32 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9b46b127..bef73b62 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -42,9 +42,9 @@ * @dev: DRM device * @plane: plane to look for * - * We need to get the pipe associated with a given plane to correctly perform - * vblank driven swapping, and they may not always be equal. So look up the - * pipe associated with @plane here. + * The Intel Mesa & 2D drivers call the vblank routines with a plane number + * rather than a pipe number, since they may not always be equal. This routine + * maps the given @plane back to a pipe number. */ static int i915_get_pipe(struct drm_device *dev, int plane) @@ -57,6 +57,46 @@ i915_get_pipe(struct drm_device *dev, int plane) return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; } +/** + * i915_get_plane - return the the plane associated with a given pipe + * @dev: DRM device + * @pipe: pipe to look for + * + * The Intel Mesa & 2D drivers call the vblank routines with a plane number + * rather than a plane number, since they may not always be equal. This routine + * maps the given @pipe back to a plane number. + */ +static int +i915_get_plane(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + if (i915_get_pipe(dev, 0) == pipe) + return 0; + return 1; +} + +/** + * i915_pipe_enabled - check if a pipe is enabled + * @dev: DRM device + * @pipe: pipe to check + * + * Reading certain registers when the pipe is disabled can hang the chip. + * Use this routine to make sure the PLL is running and the pipe is active + * before reading such registers if unsure. + */ +static int +i915_pipe_enabled(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; + + if (I915_READ(pipeconf) & PIPEACONF_ENABLE) + return 1; + + return 0; +} + /** * Emit a synchronous flip. * @@ -146,14 +186,14 @@ static void i915_vblank_tasklet(struct drm_device *dev) list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { drm_i915_vbl_swap_t *vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - int crtc = i915_get_pipe(dev, vbl_swap->plane); + int pipe = i915_get_pipe(dev, vbl_swap->plane); - if ((counter[crtc] - vbl_swap->sequence) > (1<<23)) + if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) continue; list_del(list); dev_priv->swaps_pending--; - drm_vblank_put(dev, crtc); + drm_vblank_put(dev, pipe); DRM_SPINUNLOCK(&dev_priv->swaps_lock); DRM_SPINLOCK(&dev->drw_lock); @@ -304,12 +344,23 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } -u32 i915_get_vblank_counter(struct drm_device *dev, int crtc) +u32 i915_get_vblank_counter(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + unsigned long high_frame; + unsigned long low_frame; u32 high1, high2, low, count; + int pipe; + + pipe = i915_get_pipe(dev, plane); + high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + + if (!i915_pipe_enabled(dev, pipe)) { + printk(KERN_ERR "trying to get vblank count for disabled " + "pipe %d\n", pipe); + return 0; + } /* * High & low register fields aren't synchronized, so make sure @@ -348,6 +399,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (temp == 0) return IRQ_NONE; + /* + * Clear the PIPE(A|B)STAT regs before the IIR otherwise + * we may get extra interrupts. + */ + if (temp & VSYNC_PIPEA_FLAG) { + drm_handle_vblank(dev, i915_get_plane(dev, 0)); + I915_WRITE(I915REG_PIPEASTAT, + pipea_stats | I915_VBLANK_INTERRUPT_ENABLE | + I915_VBLANK_CLEAR); + } + if (temp & VSYNC_PIPEB_FLAG) { + drm_handle_vblank(dev, i915_get_plane(dev, 1)); + I915_WRITE(I915REG_PIPEBSTAT, + pipeb_stats | I915_VBLANK_INTERRUPT_ENABLE | + I915_VBLANK_CLEAR); + } + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); (void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */ @@ -363,24 +431,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #endif } - /* - * 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, - pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| - I915_VBLANK_CLEAR); - I915_WRITE(I915REG_PIPEBSTAT, - pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| - I915_VBLANK_CLEAR); } return IRQ_HANDLED; @@ -494,11 +547,12 @@ int i915_irq_wait(struct drm_device *dev, void *data, return i915_wait_irq(dev, irqwait->irq_seq); } -int i915_enable_vblank(struct drm_device *dev, int crtc) +int i915_enable_vblank(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe = i915_get_pipe(dev, plane); - switch (crtc) { + switch (pipe) { case 0: dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; break; @@ -506,8 +560,8 @@ int i915_enable_vblank(struct drm_device *dev, int crtc) dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; break; default: - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", + pipe); break; } @@ -516,11 +570,12 @@ int i915_enable_vblank(struct drm_device *dev, int crtc) return 0; } -void i915_disable_vblank(struct drm_device *dev, int crtc) +void i915_disable_vblank(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe = i915_get_pipe(dev, plane); - switch (crtc) { + switch (pipe) { case 0: dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; break; @@ -528,8 +583,8 @@ void i915_disable_vblank(struct drm_device *dev, int crtc) dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG; break; default: - DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", - crtc); + DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", + pipe); break; } -- cgit v1.2.3 From 531f25cfe9d0319f78fe58260bfed08d5e3e8bcc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 Jan 2008 15:16:01 -0800 Subject: Correct vblank count value The frame count registers don't increment until the start of the next frame, so make sure we return an incremented count if called during the actual vblank period. --- shared-core/i915_irq.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index bef73b62..7ad21a97 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -69,8 +69,6 @@ i915_get_pipe(struct drm_device *dev, int plane) static int i915_get_plane(struct drm_device *dev, int pipe) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (i915_get_pipe(dev, 0) == pipe) return 0; return 1; @@ -349,12 +347,16 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; + unsigned long pipedsl, vblank, htotal; u32 high1, high2, low, count; int pipe; pipe = i915_get_pipe(dev, plane); high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + pipedsl = pipe ? PIPEBDSL : PIPEADSL; + vblank = pipe ? VBLANK_B : VBLANK_A; + htotal = pipe ? HTOTAL_B : HTOTAL_A; if (!i915_pipe_enabled(dev, pipe)) { printk(KERN_ERR "trying to get vblank count for disabled " @@ -378,6 +380,15 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) count = (high1 << 8) | low; + /* + * If we're in the middle of the vblank period, the + * above regs won't have been updated yet, so return + * an incremented count to stay accurate + */ + if ((I915_READ(pipedsl) >= (I915_READ(vblank) & VBLANK_START_MASK)) || + (I915_READ(pipedsl) < (I915_READ(htotal) & HACTIVE_MASK))) + count++; + return count; } -- cgit v1.2.3 From b5a34f5da50e22ecb80853f0f422beb90857dc2d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 23 Jan 2008 08:39:57 -0800 Subject: Fix thinko in get_vblank_counter Should use vtotal not htotal to figure out if we're in a vblank period. --- shared-core/i915_irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 7ad21a97..56bcac9c 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -347,7 +347,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; - unsigned long pipedsl, vblank, htotal; + unsigned long pipedsl, vblank, vtotal; u32 high1, high2, low, count; int pipe; @@ -356,7 +356,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; pipedsl = pipe ? PIPEBDSL : PIPEADSL; vblank = pipe ? VBLANK_B : VBLANK_A; - htotal = pipe ? HTOTAL_B : HTOTAL_A; + vtotal = pipe ? VTOTAL_B : VTOTAL_A; if (!i915_pipe_enabled(dev, pipe)) { printk(KERN_ERR "trying to get vblank count for disabled " @@ -386,7 +386,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) * an incremented count to stay accurate */ if ((I915_READ(pipedsl) >= (I915_READ(vblank) & VBLANK_START_MASK)) || - (I915_READ(pipedsl) < (I915_READ(htotal) & HACTIVE_MASK))) + (I915_READ(pipedsl) < (I915_READ(vtotal) & VACTIVE_MASK))) count++; return count; -- cgit v1.2.3 From c7ee6cc269c26d8e7ed98a16a272eca63daab201 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 24 Jan 2008 08:57:04 -0800 Subject: Remove broken 'in vblank' accounting We need to return an accurate vblank count to the callers of ->get_vblank_counter, and in the Intel case the actual frame count register isn't udpated until the next active line is displayed, so we need to return one more than the frame count register if we're currently in a vblank period. However, none of the various ways of doing this is working yet, so disable the logic for now. This may result in a few missed events, but should fix the hangs some people have seen due to the current code tripping the wraparound logic in drm_update_vblank_count. --- shared-core/i915_irq.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'shared-core/i915_irq.c') diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 56bcac9c..d463f6e6 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -341,22 +341,39 @@ static void i915_vblank_tasklet(struct drm_device *dev) drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); } } +#if 0 +static int i915_in_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long pipedsl, vblank, vtotal; + unsigned long vbl_start, vbl_end, cur_line; + + pipedsl = pipe ? PIPEBDSL : PIPEADSL; + vblank = pipe ? VBLANK_B : VBLANK_A; + vtotal = pipe ? VTOTAL_B : VTOTAL_A; + + vbl_start = I915_READ(vblank) & VBLANK_START_MASK; + vbl_end = (I915_READ(vblank) >> VBLANK_END_SHIFT) & VBLANK_END_MASK; + + cur_line = I915_READ(pipedsl); + + if (cur_line >= vbl_start) + return 1; + return 0; +} +#endif u32 i915_get_vblank_counter(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long high_frame; unsigned long low_frame; - unsigned long pipedsl, vblank, vtotal; u32 high1, high2, low, count; int pipe; pipe = i915_get_pipe(dev, plane); high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; - pipedsl = pipe ? PIPEBDSL : PIPEADSL; - vblank = pipe ? VBLANK_B : VBLANK_A; - vtotal = pipe ? VTOTAL_B : VTOTAL_A; if (!i915_pipe_enabled(dev, pipe)) { printk(KERN_ERR "trying to get vblank count for disabled " @@ -385,10 +402,10 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) * above regs won't have been updated yet, so return * an incremented count to stay accurate */ - if ((I915_READ(pipedsl) >= (I915_READ(vblank) & VBLANK_START_MASK)) || - (I915_READ(pipedsl) < (I915_READ(vtotal) & VACTIVE_MASK))) +#if 0 + if (i915_in_vblank(dev, pipe)) count++; - +#endif return count; } -- cgit v1.2.3