2006-01-02 20:14:23 +11:00
/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
2005-04-16 15:20:36 -07:00
*/
2006-01-02 20:14:23 +11:00
/*
2005-04-16 15:20:36 -07:00
* Copyright 2003 Tungsten Graphics , Inc . , Cedar Park , Texas .
* All Rights Reserved .
2005-06-23 22:46:46 +10:00
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sub license , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
* OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND NON - INFRINGEMENT .
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND / OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT ,
* TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
2006-01-02 20:14:23 +11:00
*/
2005-04-16 15:20:36 -07:00
# include "drmP.h"
# include "drm.h"
# include "i915_drm.h"
# include "i915_drv.h"
# define MAX_NOPID ((u32)~0)
2008-07-29 12:10:39 -07:00
/** These are the interrupts used by the driver */
# define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
2008-08-05 19:37:25 +01:00
I915_ASLE_INTERRUPT | \
2008-09-30 12:14:26 -07:00
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
2008-08-05 19:37:25 +01:00
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT )
2008-07-29 12:10:39 -07:00
2008-08-05 19:37:25 +01:00
void
2008-07-29 12:10:39 -07:00
i915_enable_irq ( drm_i915_private_t * dev_priv , u32 mask )
{
if ( ( dev_priv - > irq_mask_reg & mask ) ! = 0 ) {
dev_priv - > irq_mask_reg & = ~ mask ;
I915_WRITE ( IMR , dev_priv - > irq_mask_reg ) ;
( void ) I915_READ ( IMR ) ;
}
}
static inline void
i915_disable_irq ( drm_i915_private_t * dev_priv , u32 mask )
{
if ( ( dev_priv - > irq_mask_reg & mask ) ! = mask ) {
dev_priv - > irq_mask_reg | = mask ;
I915_WRITE ( IMR , dev_priv - > irq_mask_reg ) ;
( void ) I915_READ ( IMR ) ;
}
}
2008-09-30 12:14:26 -07:00
/**
* 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 ;
}
2006-10-24 23:37:43 +10:00
/**
* Emit blits for scheduled buffer swaps .
*
* This function will be called with the HW lock held .
2008-10-16 21:18:27 -07:00
* Because this function must grab the ring mutex ( dev - > struct_mutex ) ,
* it can no longer run at soft irq time . We ' ll fix this when we do
* the DRI2 swap buffer work .
2006-10-24 23:37:43 +10:00
*/
2007-07-11 15:53:27 +10:00
static void i915_vblank_tasklet ( struct drm_device * dev )
2006-10-24 23:37:43 +10:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-05-07 12:15:39 +10:00
unsigned long irqflags ;
2006-12-11 18:32:27 +11:00
struct list_head * list , * tmp , hits , * hit ;
2008-05-07 12:15:39 +10:00
int nhits , nrects , slice [ 2 ] , upper [ 2 ] , lower [ 2 ] , i ;
2008-09-30 12:14:26 -07:00
unsigned counter [ 2 ] ;
2007-07-11 15:27:12 +10:00
struct drm_drawable_info * drw ;
2006-12-11 18:32:27 +11:00
drm_i915_sarea_t * sarea_priv = dev_priv - > sarea_priv ;
2008-05-07 12:15:39 +10:00
u32 cpp = dev_priv - > cpp ;
2006-12-11 18:32:27 +11:00
u32 cmd = ( cpp = = 4 ) ? ( XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB )
: XY_SRC_COPY_BLT_CMD ;
2008-04-21 16:31:10 +10:00
u32 src_pitch = sarea_priv - > pitch * cpp ;
u32 dst_pitch = sarea_priv - > pitch * cpp ;
u32 ropcpp = ( 0xcc < < 16 ) | ( ( cpp - 1 ) < < 24 ) ;
2006-12-11 18:32:27 +11:00
RING_LOCALS ;
2006-10-24 23:37:43 +10:00
2008-10-16 21:18:27 -07:00
mutex_lock ( & dev - > struct_mutex ) ;
2008-07-01 12:32:52 -07:00
if ( IS_I965G ( dev ) & & sarea_priv - > front_tiled ) {
2008-04-21 16:31:10 +10:00
cmd | = XY_SRC_COPY_BLT_DST_TILED ;
dst_pitch > > = 2 ;
}
2008-07-01 12:32:52 -07:00
if ( IS_I965G ( dev ) & & sarea_priv - > back_tiled ) {
2008-04-21 16:31:10 +10:00
cmd | = XY_SRC_COPY_BLT_SRC_TILED ;
src_pitch > > = 2 ;
}
2008-10-18 19:39:29 -07:00
counter [ 0 ] = drm_vblank_count ( dev , 0 ) ;
counter [ 1 ] = drm_vblank_count ( dev , 1 ) ;
2008-09-30 12:14:26 -07:00
2006-10-24 23:37:43 +10:00
DRM_DEBUG ( " \n " ) ;
2006-12-11 18:32:27 +11:00
INIT_LIST_HEAD ( & hits ) ;
nhits = nrects = 0 ;
2008-05-07 12:15:39 +10:00
spin_lock_irqsave ( & dev_priv - > swaps_lock , irqflags ) ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
/* Find buffer swaps scheduled for this vertical blank */
2006-10-24 23:37:43 +10:00
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 ) ;
2008-10-16 21:18:27 -07:00
int pipe = vbl_swap - > pipe ;
2006-10-24 23:37:43 +10:00
2008-09-30 12:14:26 -07:00
if ( ( counter [ pipe ] - vbl_swap - > sequence ) > ( 1 < < 23 ) )
2006-12-11 18:32:27 +11:00
continue ;
list_del ( list ) ;
dev_priv - > swaps_pending - - ;
2008-09-30 12:14:26 -07:00
drm_vblank_put ( dev , pipe ) ;
2006-12-11 18:32:27 +11:00
spin_unlock ( & dev_priv - > swaps_lock ) ;
spin_lock ( & dev - > drw_lock ) ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
drw = drm_get_drawable_info ( dev , vbl_swap - > drw_id ) ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
list_for_each ( hit , & hits ) {
drm_i915_vbl_swap_t * swap_cmp =
list_entry ( hit , drm_i915_vbl_swap_t , head ) ;
2007-07-11 15:27:12 +10:00
struct drm_drawable_info * drw_cmp =
2006-12-11 18:32:27 +11:00
drm_get_drawable_info ( dev , swap_cmp - > drw_id ) ;
2006-10-24 23:37:43 +10:00
2008-10-16 21:18:27 -07:00
/* Make sure both drawables are still
* around and have some rectangles before
* we look inside to order them for the
* blts below .
*/
if ( drw_cmp & & drw_cmp - > num_rects > 0 & &
drw & & drw - > num_rects > 0 & &
2006-12-11 18:32:27 +11:00
drw_cmp - > rects [ 0 ] . y1 > drw - > rects [ 0 ] . y1 ) {
list_add_tail ( list , hit ) ;
break ;
2006-10-24 23:37:43 +10:00
}
2006-12-11 18:32:27 +11:00
}
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
spin_unlock ( & dev - > drw_lock ) ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
/* List of hits was empty, or we reached the end of it */
if ( hit = = & hits )
list_add_tail ( list , hits . prev ) ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
nhits + + ;
2006-10-24 23:37:43 +10:00
2006-12-11 18:32:27 +11:00
spin_lock ( & dev_priv - > swaps_lock ) ;
}
2008-05-07 12:15:39 +10:00
if ( nhits = = 0 ) {
spin_unlock_irqrestore ( & dev_priv - > swaps_lock , irqflags ) ;
2008-10-16 21:18:27 -07:00
mutex_unlock ( & dev - > struct_mutex ) ;
2008-04-22 16:03:07 +10:00
return ;
2008-05-07 12:15:39 +10:00
}
spin_unlock ( & dev_priv - > swaps_lock ) ;
2006-12-11 18:32:27 +11:00
2008-04-22 16:03:07 +10:00
i915_kernel_lost_context ( dev ) ;
2006-12-11 18:32:27 +11:00
2008-05-07 12:15:39 +10:00
if ( IS_I965G ( dev ) ) {
BEGIN_LP_RING ( 4 ) ;
OUT_RING ( GFX_OP_DRAWRECT_INFO_I965 ) ;
OUT_RING ( 0 ) ;
OUT_RING ( ( ( sarea_priv - > width - 1 ) & 0xffff ) | ( ( sarea_priv - > height - 1 ) < < 16 ) ) ;
OUT_RING ( 0 ) ;
ADVANCE_LP_RING ( ) ;
} else {
BEGIN_LP_RING ( 6 ) ;
2008-04-22 16:03:07 +10:00
2008-05-07 12:15:39 +10:00
OUT_RING ( GFX_OP_DRAWRECT_INFO ) ;
OUT_RING ( 0 ) ;
OUT_RING ( 0 ) ;
OUT_RING ( sarea_priv - > width | sarea_priv - > height < < 16 ) ;
OUT_RING ( sarea_priv - > width | sarea_priv - > height < < 16 ) ;
OUT_RING ( 0 ) ;
ADVANCE_LP_RING ( ) ;
}
sarea_priv - > ctxOwner = DRM_KERNEL_CONTEXT ;
upper [ 0 ] = upper [ 1 ] = 0 ;
slice [ 0 ] = max ( sarea_priv - > pipeA_h / nhits , 1 ) ;
slice [ 1 ] = max ( sarea_priv - > pipeB_h / nhits , 1 ) ;
lower [ 0 ] = sarea_priv - > pipeA_y + slice [ 0 ] ;
lower [ 1 ] = sarea_priv - > pipeB_y + slice [ 0 ] ;
2006-12-11 18:32:27 +11:00
spin_lock ( & dev - > drw_lock ) ;
/* Emit blits for buffer swaps, partitioning both outputs into as many
* slices as there are buffer swaps scheduled in order to avoid tearing
* ( based on the assumption that a single buffer swap would always
* complete before scanout starts ) .
*/
for ( i = 0 ; i + + < nhits ;
upper [ 0 ] = lower [ 0 ] , lower [ 0 ] + = slice [ 0 ] ,
upper [ 1 ] = lower [ 1 ] , lower [ 1 ] + = slice [ 1 ] ) {
if ( i = = nhits )
lower [ 0 ] = lower [ 1 ] = sarea_priv - > height ;
list_for_each ( hit , & hits ) {
drm_i915_vbl_swap_t * swap_hit =
list_entry ( hit , drm_i915_vbl_swap_t , head ) ;
2007-07-11 15:27:12 +10:00
struct drm_clip_rect * rect ;
2008-10-16 21:18:27 -07:00
int num_rects , pipe ;
2006-12-11 18:32:27 +11:00
unsigned short top , bottom ;
drw = drm_get_drawable_info ( dev , swap_hit - > drw_id ) ;
2008-10-16 21:18:27 -07:00
/* The drawable may have been destroyed since
* the vblank swap was queued
*/
2006-12-11 18:32:27 +11:00
if ( ! drw )
continue ;
rect = drw - > rects ;
2008-10-16 21:18:27 -07:00
pipe = swap_hit - > pipe ;
top = upper [ pipe ] ;
bottom = lower [ pipe ] ;
2006-12-11 18:32:27 +11:00
for ( num_rects = drw - > num_rects ; num_rects - - ; rect + + ) {
int y1 = max ( rect - > y1 , top ) ;
int y2 = min ( rect - > y2 , bottom ) ;
if ( y1 > = y2 )
continue ;
BEGIN_LP_RING ( 8 ) ;
OUT_RING ( cmd ) ;
2008-04-21 16:31:10 +10:00
OUT_RING ( ropcpp | dst_pitch ) ;
2006-12-11 18:32:27 +11:00
OUT_RING ( ( y1 < < 16 ) | rect - > x1 ) ;
OUT_RING ( ( y2 < < 16 ) | rect - > x2 ) ;
2008-05-07 12:15:39 +10:00
OUT_RING ( sarea_priv - > front_offset ) ;
2006-12-11 18:32:27 +11:00
OUT_RING ( ( y1 < < 16 ) | rect - > x1 ) ;
2008-04-21 16:31:10 +10:00
OUT_RING ( src_pitch ) ;
2008-05-07 12:15:39 +10:00
OUT_RING ( sarea_priv - > back_offset ) ;
2006-12-11 18:32:27 +11:00
ADVANCE_LP_RING ( ) ;
}
2006-10-24 23:37:43 +10:00
}
}
2008-05-07 12:15:39 +10:00
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2008-10-16 21:18:27 -07:00
mutex_unlock ( & dev - > struct_mutex ) ;
2006-12-11 18:32:27 +11:00
list_for_each_safe ( hit , tmp , & hits ) {
drm_i915_vbl_swap_t * swap_hit =
list_entry ( hit , drm_i915_vbl_swap_t , head ) ;
list_del ( hit ) ;
drm_free ( swap_hit , sizeof ( * swap_hit ) , DRM_MEM_DRIVER ) ;
}
2006-10-24 23:37:43 +10:00
}
2008-10-18 19:39:29 -07:00
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
u32 i915_get_vblank_counter ( struct drm_device * dev , int pipe )
2008-09-30 12:14:26 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
unsigned long high_frame ;
unsigned long low_frame ;
u32 high1 , high2 , low , count ;
high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH ;
low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL ;
if ( ! i915_pipe_enabled ( dev , pipe ) ) {
DRM_ERROR ( " trying to get vblank count for disabled pipe %d \n " , pipe ) ;
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
* 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 ;
}
2008-09-01 16:45:29 -07:00
void
2008-10-16 21:18:27 -07:00
i915_vblank_work_handler ( struct work_struct * work )
2008-09-01 16:45:29 -07:00
{
2008-10-16 21:18:27 -07:00
drm_i915_private_t * dev_priv = container_of ( work , drm_i915_private_t ,
vblank_work ) ;
struct drm_device * dev = dev_priv - > dev ;
unsigned long irqflags ;
if ( dev - > lock . hw_lock = = NULL ) {
i915_vblank_tasklet ( dev ) ;
return ;
}
2008-09-01 16:45:29 -07:00
2008-10-16 21:18:27 -07:00
spin_lock_irqsave ( & dev - > tasklet_lock , irqflags ) ;
dev - > locked_tasklet_func = i915_vblank_tasklet ;
spin_unlock_irqrestore ( & dev - > tasklet_lock , irqflags ) ;
/* Try to get the lock now, if this fails, the lock
* holder will execute the tasklet during unlock
*/
if ( ! drm_lock_take ( & dev - > lock , DRM_KERNEL_CONTEXT ) )
return ;
dev - > lock . lock_time = jiffies ;
atomic_inc ( & dev - > counts [ _DRM_STAT_LOCKS ] ) ;
spin_lock_irqsave ( & dev - > tasklet_lock , irqflags ) ;
dev - > locked_tasklet_func = NULL ;
spin_unlock_irqrestore ( & dev - > tasklet_lock , irqflags ) ;
2008-09-01 16:45:29 -07:00
i915_vblank_tasklet ( dev ) ;
2008-10-16 21:18:27 -07:00
drm_lock_free ( & dev - > lock , DRM_KERNEL_CONTEXT ) ;
2008-09-01 16:45:29 -07:00
}
2005-04-16 15:20:36 -07:00
irqreturn_t i915_driver_irq_handler ( DRM_IRQ_ARGS )
{
2007-07-11 15:53:27 +10:00
struct drm_device * dev = ( struct drm_device * ) arg ;
2005-04-16 15:20:36 -07:00
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-07-29 12:10:39 -07:00
u32 iir ;
2008-09-30 12:14:26 -07:00
u32 pipea_stats , pipeb_stats ;
int vblank = 0 ;
2006-03-20 18:34:29 +11:00
2008-10-06 15:14:12 -07:00
atomic_inc ( & dev_priv - > irq_received ) ;
2008-07-29 12:10:39 -07:00
if ( dev - > pdev - > msi_enabled )
I915_WRITE ( IMR , ~ 0 ) ;
iir = I915_READ ( IIR ) ;
2006-10-24 23:37:43 +10:00
2008-07-29 12:10:39 -07:00
if ( iir = = 0 ) {
if ( dev - > pdev - > msi_enabled ) {
I915_WRITE ( IMR , dev_priv - > irq_mask_reg ) ;
( void ) I915_READ ( IMR ) ;
}
2008-05-07 12:15:39 +10:00
return IRQ_NONE ;
2008-07-29 12:10:39 -07:00
}
2008-05-07 12:15:39 +10:00
2008-09-30 12:14:26 -07:00
/*
* Clear the PIPE ( A | B ) STAT regs before the IIR otherwise
* we may get extra interrupts .
*/
if ( iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT ) {
pipea_stats = I915_READ ( PIPEASTAT ) ;
if ( ! ( dev_priv - > vblank_pipe & DRM_I915_VBLANK_PIPE_A ) )
pipea_stats & = ~ ( PIPE_START_VBLANK_INTERRUPT_ENABLE |
PIPE_VBLANK_INTERRUPT_ENABLE ) ;
else if ( pipea_stats & ( PIPE_START_VBLANK_INTERRUPT_STATUS |
PIPE_VBLANK_INTERRUPT_STATUS ) ) {
vblank + + ;
2008-10-18 19:39:29 -07:00
drm_handle_vblank ( dev , 0 ) ;
2008-09-30 12:14:26 -07:00
}
2008-05-07 12:15:39 +10:00
2008-09-30 12:14:26 -07:00
I915_WRITE ( PIPEASTAT , pipea_stats ) ;
}
if ( iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT ) {
pipeb_stats = I915_READ ( PIPEBSTAT ) ;
/* Ack the event */
I915_WRITE ( PIPEBSTAT , pipeb_stats ) ;
/* The vblank interrupt gets enabled even if we didn't ask for
it , so make sure it ' s shut down again */
if ( ! ( dev_priv - > vblank_pipe & DRM_I915_VBLANK_PIPE_B ) )
pipeb_stats & = ~ ( PIPE_START_VBLANK_INTERRUPT_ENABLE |
PIPE_VBLANK_INTERRUPT_ENABLE ) ;
else if ( pipeb_stats & ( PIPE_START_VBLANK_INTERRUPT_STATUS |
PIPE_VBLANK_INTERRUPT_STATUS ) ) {
vblank + + ;
2008-10-18 19:39:29 -07:00
drm_handle_vblank ( dev , 1 ) ;
2008-09-30 12:14:26 -07:00
}
2008-05-07 12:15:39 +10:00
2008-09-30 12:14:26 -07:00
if ( pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS )
opregion_asle_intr ( dev ) ;
I915_WRITE ( PIPEBSTAT , pipeb_stats ) ;
2006-01-02 20:14:23 +11:00
}
2005-04-16 15:20:36 -07:00
2008-07-30 12:06:12 -07:00
I915_WRITE ( IIR , iir ) ;
if ( dev - > pdev - > msi_enabled )
I915_WRITE ( IMR , dev_priv - > irq_mask_reg ) ;
( void ) I915_READ ( IIR ) ; /* Flush posted writes */
2008-08-05 19:37:25 +01:00
2008-08-20 11:20:13 -04:00
if ( dev_priv - > sarea_priv )
dev_priv - > sarea_priv - > last_dispatch =
READ_BREADCRUMB ( dev_priv ) ;
2008-09-30 12:14:26 -07:00
2008-07-30 12:06:12 -07:00
if ( iir & I915_USER_INTERRUPT ) {
dev_priv - > mm . irq_gem_seqno = i915_get_gem_seqno ( dev ) ;
DRM_WAKEUP ( & dev_priv - > irq_queue ) ;
}
if ( iir & I915_ASLE_INTERRUPT )
opregion_asle_intr ( dev ) ;
2008-09-30 12:14:26 -07:00
2008-10-16 21:18:27 -07:00
if ( vblank & & dev_priv - > swaps_pending > 0 )
schedule_work ( & dev_priv - > vblank_work ) ;
2008-08-05 19:37:25 +01:00
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}
2008-05-07 12:15:39 +10:00
static int i915_emit_irq ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
RING_LOCALS ;
i915_kernel_lost_context ( dev ) ;
2008-01-24 15:58:57 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2008-08-20 11:20:13 -04:00
dev_priv - > counter + + ;
2006-08-12 16:29:24 +10:00
if ( dev_priv - > counter > 0x7FFFFFFFUL )
2008-08-20 11:20:13 -04:00
dev_priv - > counter = 1 ;
if ( dev_priv - > sarea_priv )
dev_priv - > sarea_priv - > last_enqueue = dev_priv - > counter ;
2006-08-12 16:29:24 +10:00
BEGIN_LP_RING ( 6 ) ;
2008-07-29 11:54:06 -07:00
OUT_RING ( MI_STORE_DWORD_INDEX ) ;
OUT_RING ( 5 < < MI_STORE_DWORD_INDEX_SHIFT ) ;
2006-08-12 16:29:24 +10:00
OUT_RING ( dev_priv - > counter ) ;
OUT_RING ( 0 ) ;
2005-04-16 15:20:36 -07:00
OUT_RING ( 0 ) ;
2008-07-29 11:54:06 -07:00
OUT_RING ( MI_USER_INTERRUPT ) ;
2005-04-16 15:20:36 -07:00
ADVANCE_LP_RING ( ) ;
2007-11-05 12:50:58 +10:00
2006-08-12 16:29:24 +10:00
return dev_priv - > counter ;
2005-04-16 15:20:36 -07:00
}
2008-07-30 12:06:12 -07:00
void i915_user_irq_get ( struct drm_device * dev )
2008-07-29 12:10:39 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-10-16 11:31:38 -07:00
unsigned long irqflags ;
2008-07-29 12:10:39 -07:00
2008-10-16 11:31:38 -07:00
spin_lock_irqsave ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-07-29 12:10:39 -07:00
if ( dev - > irq_enabled & & ( + + dev_priv - > user_irq_refcount = = 1 ) )
i915_enable_irq ( dev_priv , I915_USER_INTERRUPT ) ;
2008-10-16 11:31:38 -07:00
spin_unlock_irqrestore ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-07-29 12:10:39 -07:00
}
2008-09-30 12:14:26 -07:00
void i915_user_irq_put ( struct drm_device * dev )
2008-07-29 12:10:39 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-10-16 11:31:38 -07:00
unsigned long irqflags ;
2008-07-29 12:10:39 -07:00
2008-10-16 11:31:38 -07:00
spin_lock_irqsave ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-07-29 12:10:39 -07:00
BUG_ON ( dev - > irq_enabled & & dev_priv - > user_irq_refcount < = 0 ) ;
if ( dev - > irq_enabled & & ( - - dev_priv - > user_irq_refcount = = 0 ) )
i915_disable_irq ( dev_priv , I915_USER_INTERRUPT ) ;
2008-10-16 11:31:38 -07:00
spin_unlock_irqrestore ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-07-29 12:10:39 -07:00
}
2007-07-11 15:53:27 +10:00
static int i915_wait_irq ( struct drm_device * dev , int irq_nr )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
int ret = 0 ;
2008-01-24 15:58:57 +10:00
DRM_DEBUG ( " irq_nr=%d breadcrumb=%d \n " , irq_nr ,
2005-04-16 15:20:36 -07:00
READ_BREADCRUMB ( dev_priv ) ) ;
2008-07-29 12:10:39 -07:00
if ( READ_BREADCRUMB ( dev_priv ) > = irq_nr ) {
2008-08-20 11:20:13 -04:00
if ( dev_priv - > sarea_priv ) {
dev_priv - > sarea_priv - > last_dispatch =
READ_BREADCRUMB ( dev_priv ) ;
}
2005-04-16 15:20:36 -07:00
return 0 ;
2008-07-29 12:10:39 -07:00
}
2005-04-16 15:20:36 -07:00
2008-08-20 11:20:13 -04:00
if ( dev_priv - > sarea_priv )
dev_priv - > sarea_priv - > perf_boxes | = I915_BOX_WAIT ;
2005-04-16 15:20:36 -07:00
2008-07-29 12:10:39 -07:00
i915_user_irq_get ( dev ) ;
2005-04-16 15:20:36 -07:00
DRM_WAIT_ON ( ret , dev_priv - > irq_queue , 3 * DRM_HZ ,
READ_BREADCRUMB ( dev_priv ) > = irq_nr ) ;
2008-07-29 12:10:39 -07:00
i915_user_irq_put ( dev ) ;
2005-04-16 15:20:36 -07:00
2007-08-25 19:22:43 +10:00
if ( ret = = - EBUSY ) {
2008-01-24 15:58:57 +10:00
DRM_ERROR ( " EBUSY -- rec: %d emitted: %d \n " ,
2005-04-16 15:20:36 -07:00
READ_BREADCRUMB ( dev_priv ) , ( int ) dev_priv - > counter ) ;
}
2008-08-20 11:20:13 -04:00
if ( dev_priv - > sarea_priv )
dev_priv - > sarea_priv - > last_dispatch =
READ_BREADCRUMB ( dev_priv ) ;
2008-05-07 12:15:39 +10:00
return ret ;
}
2005-04-16 15:20:36 -07:00
/* Needs the lock as it touches the ring.
*/
2007-09-03 12:06:45 +10:00
int i915_irq_emit ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
2007-09-03 12:06:45 +10:00
drm_i915_irq_emit_t * emit = data ;
2005-04-16 15:20:36 -07:00
int result ;
2008-09-01 16:45:29 -07:00
RING_LOCK_TEST_WITH_RETURN ( dev , file_priv ) ;
2005-04-16 15:20:36 -07:00
if ( ! dev_priv ) {
2008-01-24 15:58:57 +10:00
DRM_ERROR ( " called with no initialization \n " ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
2008-09-01 16:45:29 -07:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
result = i915_emit_irq ( dev ) ;
2008-09-01 16:45:29 -07:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
if ( DRM_COPY_TO_USER ( emit - > irq_seq , & result , sizeof ( int ) ) ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " copy_to_user \n " ) ;
2007-08-25 19:22:43 +10:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}
/* Doesn't need the hardware lock.
*/
2007-09-03 12:06:45 +10:00
int i915_irq_wait ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
2007-09-03 12:06:45 +10:00
drm_i915_irq_wait_t * irqwait = data ;
2005-04-16 15:20:36 -07:00
if ( ! dev_priv ) {
2008-01-24 15:58:57 +10:00
DRM_ERROR ( " called with no initialization \n " ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
2007-09-03 12:06:45 +10:00
return i915_wait_irq ( dev , irqwait - > irq_seq ) ;
2005-04-16 15:20:36 -07:00
}
2008-10-18 19:39:29 -07:00
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
int i915_enable_vblank ( struct drm_device * dev , int pipe )
2008-09-30 12:14:26 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
u32 pipestat_reg = 0 ;
u32 pipestat ;
2008-10-16 11:31:38 -07:00
u32 interrupt = 0 ;
unsigned long irqflags ;
2008-09-30 12:14:26 -07:00
switch ( pipe ) {
case 0 :
pipestat_reg = PIPEASTAT ;
2008-10-16 11:31:38 -07:00
interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT ;
2008-09-30 12:14:26 -07:00
break ;
case 1 :
pipestat_reg = PIPEBSTAT ;
2008-10-16 11:31:38 -07:00
interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT ;
2008-09-30 12:14:26 -07:00
break ;
default :
DRM_ERROR ( " tried to enable vblank on non-existent pipe %d \n " ,
pipe ) ;
2008-10-16 11:31:38 -07:00
return 0 ;
2008-09-30 12:14:26 -07:00
}
2008-10-16 11:31:38 -07:00
spin_lock_irqsave ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-10-17 15:41:26 -07:00
/* Enabling vblank events in IMR comes before PIPESTAT write, or
* there ' s a race where the PIPESTAT vblank bit gets set to 1 , so
* the OR of enabled PIPESTAT bits goes to 1 , so the PIPExEVENT in
* ISR flashes to 1 , but the IIR bit doesn ' t get set to 1 because
* IMR masks it . It doesn ' t ever get set after we clear the masking
* in IMR because the ISR bit is edge , not level - triggered , on the
* OR of PIPESTAT bits .
*/
i915_enable_irq ( dev_priv , interrupt ) ;
2008-10-16 11:31:38 -07:00
pipestat = I915_READ ( pipestat_reg ) ;
if ( IS_I965G ( dev ) )
pipestat | = PIPE_START_VBLANK_INTERRUPT_ENABLE ;
else
pipestat | = PIPE_VBLANK_INTERRUPT_ENABLE ;
/* Clear any stale interrupt status */
pipestat | = ( PIPE_START_VBLANK_INTERRUPT_STATUS |
PIPE_VBLANK_INTERRUPT_STATUS ) ;
I915_WRITE ( pipestat_reg , pipestat ) ;
( void ) I915_READ ( pipestat_reg ) ; /* Posting read */
spin_unlock_irqrestore ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-09-30 12:14:26 -07:00
return 0 ;
}
2008-10-18 19:39:29 -07:00
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
void i915_disable_vblank ( struct drm_device * dev , int pipe )
2008-09-30 12:14:26 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
u32 pipestat_reg = 0 ;
u32 pipestat ;
2008-10-16 11:31:38 -07:00
u32 interrupt = 0 ;
unsigned long irqflags ;
2008-09-30 12:14:26 -07:00
switch ( pipe ) {
case 0 :
pipestat_reg = PIPEASTAT ;
2008-10-16 11:31:38 -07:00
interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT ;
2008-09-30 12:14:26 -07:00
break ;
case 1 :
pipestat_reg = PIPEBSTAT ;
2008-10-16 11:31:38 -07:00
interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT ;
2008-09-30 12:14:26 -07:00
break ;
default :
DRM_ERROR ( " tried to disable vblank on non-existent pipe %d \n " ,
pipe ) ;
2008-10-16 11:31:38 -07:00
return ;
2008-09-30 12:14:26 -07:00
break ;
}
2008-10-16 11:31:38 -07:00
spin_lock_irqsave ( & dev_priv - > user_irq_lock , irqflags ) ;
i915_disable_irq ( dev_priv , interrupt ) ;
pipestat = I915_READ ( pipestat_reg ) ;
pipestat & = ~ ( PIPE_START_VBLANK_INTERRUPT_ENABLE |
PIPE_VBLANK_INTERRUPT_ENABLE ) ;
/* Clear any stale interrupt status */
pipestat | = ( PIPE_START_VBLANK_INTERRUPT_STATUS |
PIPE_VBLANK_INTERRUPT_STATUS ) ;
I915_WRITE ( pipestat_reg , pipestat ) ;
( void ) I915_READ ( pipestat_reg ) ; /* Posting read */
spin_unlock_irqrestore ( & dev_priv - > user_irq_lock , irqflags ) ;
2008-09-30 12:14:26 -07:00
}
2006-06-24 17:07:34 +10:00
/* Set the vblank monitor pipe
*/
2007-09-03 12:06:45 +10:00
int i915_vblank_pipe_set ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2006-06-24 17:07:34 +10:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
if ( ! dev_priv ) {
2008-01-24 15:58:57 +10:00
DRM_ERROR ( " called with no initialization \n " ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-06-24 17:07:34 +10:00
}
2006-10-25 00:08:23 +10:00
return 0 ;
2006-06-24 17:07:34 +10:00
}
2007-09-03 12:06:45 +10:00
int i915_vblank_pipe_get ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2006-06-24 17:07:34 +10:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
2007-09-03 12:06:45 +10:00
drm_i915_vblank_pipe_t * pipe = data ;
2006-06-24 17:07:34 +10:00
if ( ! dev_priv ) {
2008-01-24 15:58:57 +10:00
DRM_ERROR ( " called with no initialization \n " ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-06-24 17:07:34 +10:00
}
2008-09-30 12:14:26 -07:00
pipe - > pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B ;
2007-09-03 12:06:45 +10:00
2006-06-24 17:07:34 +10:00
return 0 ;
}
2006-10-24 23:37:43 +10:00
/**
* Schedule buffer swap at given vertical blank .
*/
2007-09-03 12:06:45 +10:00
int i915_vblank_swap ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2006-10-24 23:37:43 +10:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
2007-09-03 12:06:45 +10:00
drm_i915_vblank_swap_t * swap = data ;
2008-10-16 21:18:27 -07:00
drm_i915_vbl_swap_t * vbl_swap , * vbl_old ;
2008-10-18 19:39:29 -07:00
unsigned int pipe , seqtype , curseq ;
2006-10-25 00:12:52 +10:00
unsigned long irqflags ;
2006-10-24 23:37:43 +10:00
struct list_head * list ;
2008-09-30 12:14:26 -07:00
int ret ;
2006-10-24 23:37:43 +10:00
2008-08-20 11:20:13 -04:00
if ( ! dev_priv | | ! dev_priv - > sarea_priv ) {
2006-10-24 23:37:43 +10:00
DRM_ERROR ( " %s called with no initialization \n " , __func__ ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:37:43 +10:00
}
2008-05-07 12:15:39 +10:00
if ( dev_priv - > sarea_priv - > rotation ) {
2006-10-24 23:37:43 +10:00
DRM_DEBUG ( " Rotation not supported \n " ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:37:43 +10:00
}
2007-09-03 12:06:45 +10:00
if ( swap - > seqtype & ~ ( _DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
2008-05-07 12:15:39 +10:00
_DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS ) ) {
2007-09-03 12:06:45 +10:00
DRM_ERROR ( " Invalid sequence type 0x%x \n " , swap - > seqtype ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:38:54 +10:00
}
2008-10-18 19:39:29 -07:00
pipe = ( swap - > seqtype & _DRM_VBLANK_SECONDARY ) ? 1 : 0 ;
2006-10-24 23:38:54 +10:00
2007-09-03 12:06:45 +10:00
seqtype = swap - > seqtype & ( _DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE ) ;
2006-10-24 23:38:54 +10:00
if ( ! ( dev_priv - > vblank_pipe & ( 1 < < pipe ) ) ) {
DRM_ERROR ( " Invalid pipe %d \n " , pipe ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:37:43 +10:00
}
spin_lock_irqsave ( & dev - > drw_lock , irqflags ) ;
2007-09-03 12:06:45 +10:00
if ( ! drm_get_drawable_info ( dev , swap - > drawable ) ) {
2006-10-24 23:37:43 +10:00
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2007-09-03 12:06:45 +10:00
DRM_DEBUG ( " Invalid drawable ID %d \n " , swap - > drawable ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:37:43 +10:00
}
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2008-09-30 12:14:26 -07:00
/*
* We take the ref here and put it when the swap actually completes
* in the tasklet .
*/
ret = drm_vblank_get ( dev , pipe ) ;
if ( ret )
return ret ;
curseq = drm_vblank_count ( dev , pipe ) ;
2006-10-24 23:38:54 +10:00
2006-10-25 01:05:09 +10:00
if ( seqtype = = _DRM_VBLANK_RELATIVE )
2007-09-03 12:06:45 +10:00
swap - > sequence + = curseq ;
2006-10-25 01:05:09 +10:00
2007-09-03 12:06:45 +10:00
if ( ( curseq - swap - > sequence ) < = ( 1 < < 23 ) ) {
if ( swap - > seqtype & _DRM_VBLANK_NEXTONMISS ) {
swap - > sequence = curseq + 1 ;
2006-10-25 01:05:09 +10:00
} else {
2006-10-24 23:38:54 +10:00
DRM_DEBUG ( " Missed target sequence \n " ) ;
2008-09-30 12:14:26 -07:00
drm_vblank_put ( dev , pipe ) ;
2007-08-25 19:22:43 +10:00
return - EINVAL ;
2006-10-24 23:38:54 +10:00
}
}
2008-10-16 21:18:27 -07:00
vbl_swap = drm_calloc ( 1 , sizeof ( * vbl_swap ) , DRM_MEM_DRIVER ) ;
if ( ! vbl_swap ) {
DRM_ERROR ( " Failed to allocate memory to queue swap \n " ) ;
drm_vblank_put ( dev , pipe ) ;
return - ENOMEM ;
}
vbl_swap - > drw_id = swap - > drawable ;
vbl_swap - > pipe = pipe ;
vbl_swap - > sequence = swap - > sequence ;
2006-10-25 01:05:09 +10:00
spin_lock_irqsave ( & dev_priv - > swaps_lock , irqflags ) ;
2006-10-24 23:37:43 +10:00
list_for_each ( list , & dev_priv - > vbl_swaps . head ) {
2008-10-16 21:18:27 -07:00
vbl_old = list_entry ( list , drm_i915_vbl_swap_t , head ) ;
2006-10-24 23:37:43 +10:00
2008-10-16 21:18:27 -07:00
if ( vbl_old - > drw_id = = swap - > drawable & &
vbl_old - > pipe = = pipe & &
vbl_old - > sequence = = swap - > sequence ) {
2006-10-24 23:37:43 +10:00
spin_unlock_irqrestore ( & dev_priv - > swaps_lock , irqflags ) ;
2008-10-17 11:03:53 -07:00
drm_vblank_put ( dev , pipe ) ;
2008-10-16 21:18:27 -07:00
drm_free ( vbl_swap , sizeof ( * vbl_swap ) , DRM_MEM_DRIVER ) ;
2006-10-24 23:37:43 +10:00
DRM_DEBUG ( " Already scheduled \n " ) ;
return 0 ;
}
}
2008-10-16 21:18:27 -07:00
if ( dev_priv - > swaps_pending > = 10 ) {
2006-10-25 00:10:59 +10:00
DRM_DEBUG ( " Too many swaps queued \n " ) ;
2008-10-16 21:18:27 -07:00
DRM_DEBUG ( " pipe 0: %d pipe 1: %d \n " ,
2008-10-18 19:39:29 -07:00
drm_vblank_count ( dev , 0 ) ,
drm_vblank_count ( dev , 1 ) ) ;
2008-10-16 21:18:27 -07:00
list_for_each ( list , & dev_priv - > vbl_swaps . head ) {
vbl_old = list_entry ( list , drm_i915_vbl_swap_t , head ) ;
DRM_DEBUG ( " \t drw %x pipe %d seq %x \n " ,
vbl_old - > drw_id , vbl_old - > pipe ,
vbl_old - > sequence ) ;
}
spin_unlock_irqrestore ( & dev_priv - > swaps_lock , irqflags ) ;
2008-09-30 12:14:26 -07:00
drm_vblank_put ( dev , pipe ) ;
2008-10-16 21:18:27 -07:00
drm_free ( vbl_swap , sizeof ( * vbl_swap ) , DRM_MEM_DRIVER ) ;
2007-08-25 19:22:43 +10:00
return - EBUSY ;
2006-10-25 00:10:59 +10:00
}
2007-12-17 09:47:19 +10:00
list_add_tail ( & vbl_swap - > head , & dev_priv - > vbl_swaps . head ) ;
2006-10-24 23:37:43 +10:00
dev_priv - > swaps_pending + + ;
spin_unlock_irqrestore ( & dev_priv - > swaps_lock , irqflags ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
/* drm_dma.h hooks
*/
2007-07-11 15:53:27 +10:00
void i915_driver_irq_preinstall ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-09-30 12:14:26 -07:00
I915_WRITE ( HWSTAM , 0xeffe ) ;
I915_WRITE ( IMR , 0xffffffff ) ;
2008-07-29 12:10:39 -07:00
I915_WRITE ( IER , 0x0 ) ;
2005-04-16 15:20:36 -07:00
}
2008-09-30 12:14:26 -07:00
int i915_driver_irq_postinstall ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-09-30 12:14:26 -07:00
int ret , num_pipes = 2 ;
2005-04-16 15:20:36 -07:00
2007-05-26 05:56:14 +10:00
spin_lock_init ( & dev_priv - > swaps_lock ) ;
2006-10-24 23:37:43 +10:00
INIT_LIST_HEAD ( & dev_priv - > vbl_swaps . head ) ;
2008-10-16 21:18:27 -07:00
INIT_WORK ( & dev_priv - > vblank_work , i915_vblank_work_handler ) ;
2006-10-24 23:37:43 +10:00
dev_priv - > swaps_pending = 0 ;
2008-07-29 12:10:39 -07:00
/* Set initial unmasked IRQs to just the selected vblank pipes. */
dev_priv - > irq_mask_reg = ~ 0 ;
2008-09-30 12:14:26 -07:00
ret = drm_vblank_init ( dev , num_pipes ) ;
if ( ret )
return ret ;
dev_priv - > vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B ;
dev_priv - > irq_mask_reg & = ~ I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT ;
dev_priv - > irq_mask_reg & = ~ I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT ;
dev - > max_vblank_count = 0xffffff ; /* only 24 bits of frame count */
2008-07-29 12:10:39 -07:00
2008-08-05 19:37:25 +01:00
dev_priv - > irq_mask_reg & = I915_INTERRUPT_ENABLE_MASK ;
2008-07-29 12:10:39 -07:00
I915_WRITE ( IMR , dev_priv - > irq_mask_reg ) ;
I915_WRITE ( IER , I915_INTERRUPT_ENABLE_MASK ) ;
( void ) I915_READ ( IER ) ;
2008-08-05 19:37:25 +01:00
opregion_enable_asle ( dev ) ;
2005-04-16 15:20:36 -07:00
DRM_INIT_WAITQUEUE ( & dev_priv - > irq_queue ) ;
2008-09-30 12:14:26 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-07-11 15:53:27 +10:00
void i915_driver_irq_uninstall ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_i915_private_t * dev_priv = ( drm_i915_private_t * ) dev - > dev_private ;
2008-09-30 12:14:26 -07:00
u32 temp ;
2006-02-18 15:17:04 +11:00
2005-04-16 15:20:36 -07:00
if ( ! dev_priv )
return ;
2008-09-30 12:14:26 -07:00
dev_priv - > vblank_pipe = 0 ;
I915_WRITE ( HWSTAM , 0xffffffff ) ;
I915_WRITE ( IMR , 0xffffffff ) ;
2008-07-29 12:10:39 -07:00
I915_WRITE ( IER , 0x0 ) ;
2008-05-07 12:15:39 +10:00
2008-09-30 12:14:26 -07:00
temp = I915_READ ( PIPEASTAT ) ;
I915_WRITE ( PIPEASTAT , temp ) ;
temp = I915_READ ( PIPEBSTAT ) ;
I915_WRITE ( PIPEBSTAT , temp ) ;
2008-07-29 12:10:39 -07:00
temp = I915_READ ( IIR ) ;
I915_WRITE ( IIR , temp ) ;
2005-04-16 15:20:36 -07:00
}