summaryrefslogtreecommitdiff
path: root/linux-core/mga_drv.c
AgeCommit message (Expand)Author
2006-10-20Bug #1746: Set dev_priv_size for the MGA driver.Tilman Sauerbeck
2006-10-14remove config.h from build no longer exists kbuild does itDave Airlie
2006-03-19fix issue in mga from kernelDave Airlie
2005-11-11cleanup ioctl/max_ioctl to use header file for extern symbolsDave Airlie
2005-10-11The Linux 2.6.9 (and earlier) fops structure does not contain aIan Romanick
2005-08-05Rename the driver hooks in the DRM to something a little moreEric Anholt
2005-06-29add mga and r128 32/64 bitsDave Airlie
2005-06-14Adds support for PCI cards to MGA DRMIan Romanick
2005-06-09Completely re-initialize DMA settingsIan Romanick
2005-05-27Modify drm_driver::device_is_agp to return a tri-state value to indicateIan Romanick
2005-05-21Change the MGA initialization and cleanup a bit. The dev_private structureIan Romanick
2005-05-16Added device_is_agp callback to drm_driver. This function is called by theIan Romanick
2004-11-09Fix more build problems on linux-coreJon Smirl
2004-11-06Convert more drivers for bsd-core, moving the ioctl definitions to sharedEric Anholt
2004-10-13Add a poll function that alternates between zero and normal poll return toJon Smirl
2004-10-12Breakout heads into their own data structures.Jon Smirl
2004-10-10Rename fn_tbl to driver. Core driver now uses pci_driver name whichJon Smirl
2004-09-30Lindent of core build. Drivers checked for no binary diffs. A few filesJon Smirl
2004-09-30Make fops per driver instead of global, remove default flush, poll, readJon Smirl
2004-09-27First check in for DRM that splits core from personality modulesJon Smirl
2004-09-231) switches from class_sysfs to drm sysfs implementation to allowJon Smirl
2004-08-24Merged drmfntbl-0-0-2Dave Airlie
2003-10-17- Move IRQ functions from drm_dma.h to new drm_irq.h and disentangle themEric Anholt
2003-06-19Revert the janitorial - that works is now on the new branchJose Fonseca
2003-06-03Split declarations/definitions in drm_scatter.h into drm_sg.h/drm_sg_tmp.hJose Fonseca
2002-07-05merged bsd-3-0-0-branchAlan Hourihane
2002-04-09Merged drmcommand-0-0-1Jens Owen
2001-07-23Fixes that allow the modules to be built into the kernelJeff Hartmann
2001-07-18Add module version name at a lower layer of the code, allows things to beJeff Hartmann
2001-07-16Added version string to the end of the kernel module name. This allowsJeff Hartmann
2001-03-21- Fix MGA header info.Gareth Hughes
2001-03-19Update version, date stamp.Gareth Hughes
2001-02-16- Clean up the way customization of the templates is done.Gareth Hughes
2001-02-15- Fix up merge.Gareth Hughes
2001-02-15Merge mga-1-0-0-branch into trunk.Gareth Hughes
2001-01-04Sync with Linux 2.4.0-prereleaseRik Faith
2000-12-30add blit ioctl, fix plnwt handlingKeith Whitwell
2000-11-15Sync with Linux 2.4.0-test11-pre5 Provide backward compatibility testedRik Faith
2000-09-29Audit calls to schedule() Remove tags from files shared with Linux kernelRik Faith
2000-09-28Fixed two things Rik pointed out in the last commitJeff Hartmann
2000-09-27Merged the mga-lock-debug-0-2-0-branch with the trunk. This includesJeff Hartmann
2000-09-24commit xfree86 4.0.1d-pre updateAlan Hourihane
2000-09-10Sync with 2.4.0-test8 kernel.Gareth Hughes
2000-09-06Sync with 2.4.0-test8-pre5 kernel.Gareth Hughes
2000-08-31Bump version number after kernel interface change.Keith Whitwell
2000-08-28Add compatibility header file to make Linux 2.4.0 kernel patches cleaner.Rik Faith
2000-08-26Sync with Linux 2.4.0-test7 Add signal blocking support to all driversRik Faith
2000-08-08Sync with Linux 2.4.0-test6-pre8Rik Faith
2000-08-04Sync with Linux 2.4.0-test6-pre2Rik Faith
2000-07-20More fixups for kernel build: EXPORT_SYMTAB warning removalRik Faith
ef='#n430'>430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
 */
/*
 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
 * All Rights Reserved.
 *
 * 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.
 *
 */

#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"

#define MAX_NOPID ((u32)~0)

/**
 * Interrupts that are always left unmasked.
 *
 * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
 * we leave them always unmasked in IMR and then control enabling them through
 * PIPESTAT alone.
 */
#define I915_INTERRUPT_ENABLE_FIX (I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
				   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)

/** Interrupts that we mask and unmask at runtime. */
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)

/** These are all of the interrupts used by the driver */
#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
				    I915_INTERRUPT_ENABLE_VAR)

static inline void
i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
	DRM_DEBUG("irq_enable_reg = 0x%08x, mask = 0x%08x\n",
	    dev_priv->irq_mask_reg, mask);
	mask &= I915_INTERRUPT_ENABLE_VAR;
	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)
{
	mask &= I915_INTERRUPT_ENABLE_VAR;
	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);
	}
}

static inline u32
i915_pipestat(int pipe)
{
	if (pipe == 0)
	    return PIPEASTAT;
	if (pipe == 1)
	    return PIPEBSTAT;
	return -EINVAL;
}

void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
{
	if ((dev_priv->pipestat[pipe] & mask) != mask) {
		u32 reg = i915_pipestat(pipe);

		dev_priv->pipestat[pipe] |= mask;
		/* Enable the interrupt, clear any pending status */
		I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
		(void) I915_READ(reg);
	}
}

void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
{
	if ((dev_priv->pipestat[pipe] & mask) != 0) {
		u32 reg = i915_pipestat(pipe);

		dev_priv->pipestat[pipe] &= ~mask;
		I915_WRITE(reg, dev_priv->pipestat[pipe]);
		(void) I915_READ(reg);
	}
}

/**
 * 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;
}

/* 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)
{
	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;
}

u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;

	if (!i915_pipe_enabled(dev, pipe)) {
		DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
		return 0;
	}

	return I915_READ(reg);
}

irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
	struct drm_device *dev = (struct drm_device *) arg;
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	u32 iir, new_iir;
	u32 pipea_stats, pipeb_stats;

	atomic_inc(&dev_priv->irq_received);

	for (iir = I915_READ(IIR) ; iir != 0 ; iir = new_iir) {

		pipea_stats = pipeb_stats = 0;

		/*
		 * Clear the PIPE(A|B)STAT regs before the IIR
		 */
		if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
			DRM_SPINLOCK(&dev_priv->user_irq_lock);
			pipea_stats = I915_READ(PIPEASTAT);
			I915_WRITE(PIPEASTAT, pipea_stats);
			DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
		}

		if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
			DRM_SPINLOCK(&dev_priv->user_irq_lock);
			pipeb_stats = I915_READ(PIPEBSTAT);
			I915_WRITE(PIPEBSTAT, pipeb_stats);
			DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
		}

		I915_WRITE(IIR, iir);
		new_iir = I915_READ(IIR);

		DRM_DEBUG("iir = 0x%08x, pipestats a = 0x%08x, b = 0x%08x\n",
		    iir, pipea_stats, pipeb_stats);

		if (dev_priv->sarea_priv)
			dev_priv->sarea_priv->last_dispatch =
			    READ_BREADCRUMB(dev_priv);

		if (iir & I915_USER_INTERRUPT) {
#ifdef I915_HAVE_GEM
			dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
#endif
			DRM_WAKEUP(&dev_priv->irq_queue);
		}

		if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS |
		    PIPE_VBLANK_INTERRUPT_STATUS))
			drm_handle_vblank(dev, 0);

		if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS |
		    PIPE_VBLANK_INTERRUPT_STATUS))
			drm_handle_vblank(dev, 1);
#ifdef __linux__
		if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
		    (iir & I915_ASLE_INTERRUPT))
			opregion_asle_intr(dev);
#endif
	}
}

static int i915_emit_irq(struct drm_device * dev)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

	i915_kernel_lost_context(dev);

	DRM_DEBUG("\n");

	dev_priv->counter++;
	if (dev_priv->counter > 0x7FFFFFFFUL)
		dev_priv->counter = 1;
	if (dev_priv->sarea_priv)
		dev_priv->sarea_priv->last_enqueue = dev_priv->counter;

	BEGIN_LP_RING(4);
	OUT_RING(MI_STORE_DWORD_INDEX);
	OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
	OUT_RING(dev_priv->counter);
	OUT_RING(MI_USER_INTERRUPT);
	ADVANCE_LP_RING();

	return dev_priv->counter;
}

void i915_user_irq_get(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	unsigned long irqflags;

	DRM_DEBUG("\n");
	DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags);
	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
		i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
	DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags);
}

void i915_user_irq_put(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	unsigned long irqflags;

	DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags);
#ifdef __linux__
	BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
#endif
	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
		i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
	DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags);
}

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("irq_nr=%d breadcrumb=%d\n", irq_nr,
		  READ_BREADCRUMB(dev_priv));

	if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
		if (dev_priv->sarea_priv) {
			dev_priv->sarea_priv->last_dispatch =
				READ_BREADCRUMB(dev_priv);
		}
		return 0;
	}

	if (dev_priv->sarea_priv)
		dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;

	i915_user_irq_get(dev);
	DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
		    READ_BREADCRUMB(dev_priv) >= irq_nr);
	i915_user_irq_put(dev);

	if (ret == -EBUSY) {
		DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
	}

	if (dev_priv->sarea_priv)
		dev_priv->sarea_priv->last_dispatch =
			READ_BREADCRUMB(dev_priv);

	return ret;
}

/* Needs the lock as it touches the ring.
 */
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;
	int result;

	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);

	if (!dev_priv) {
		DRM_ERROR("called with no initialization\n");
		return -EINVAL;
	}

	result = i915_emit_irq(dev);

	if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
		DRM_ERROR("copy_to_user\n");
		return -EFAULT;
	}

	return 0;
}

/* Doesn't need the hardware lock.
 */
int i915_irq_wait(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_irq_wait_t *irqwait = data;

	if (!dev_priv) {
		DRM_ERROR("called with no initialization\n");
		return -EINVAL;
	}

	return i915_wait_irq(dev, irqwait->irq_seq);
}

/* Called from drm generic code, passed 'crtc' which
 * we use as a pipe index
 */
int i915_enable_vblank(struct drm_device *dev, int pipe)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	unsigned long irqflags;
	u32 pipestat;

	/*
	 * Older chips didn't have the start vblank interrupt,
	 * but
	 */
	if (IS_I965G (dev))
		pipestat = PIPE_START_VBLANK_INTERRUPT_ENABLE;
	else
		pipestat = PIPE_VBLANK_INTERRUPT_ENABLE;

	DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags);
	i915_enable_pipestat(dev_priv, pipe, pipestat);
	DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags);
	return 0;
}

/* Called from drm generic code, passed 'crtc' which
 * we use as a pipe index
 */
void i915_disable_vblank(struct drm_device *dev, int pipe)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	unsigned long irqflags;

	DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags);
	i915_disable_pipestat(dev_priv, pipe,
	    PIPE_START_VBLANK_INTERRUPT_ENABLE | PIPE_VBLANK_INTERRUPT_ENABLE);
	DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags);
}

/* Set the vblank monitor pipe
 */
int i915_vblank_pipe_set(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
	drm_i915_private_t *dev_priv = dev->dev_private;

	if (!dev_priv) {
		DRM_ERROR("called with no initialization\n");
		return -EINVAL;
	}

	return 0;
}

int i915_vblank_pipe_get(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_vblank_pipe_t *pipe = data;

	if (!dev_priv) {
		DRM_ERROR("called with no initialization\n");
		return -EINVAL;
	}

	pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;

	return 0;
}

/**
 * Schedule buffer swap at given vertical blank.
 */
int i915_vblank_swap(struct drm_device *dev, void *data,
		     struct drm_file *file_priv)
{
	/* The delayed swap mechanism was fundamentally racy, and has been
	 * removed.  The model was that the client requested a delayed flip/swap
	 * from the kernel, then waited for vblank before continuing to perform
	 * rendering.  The problem was that the kernel might wake the client
	 * up before it dispatched the vblank swap (since the lock has to be
	 * held while touching the ringbuffer), in which case the client would
	 * clear and start the next frame before the swap occurred, and
	 * flicker would occur in addition to likely missing the vblank.
	 *
	 * In the absence of this ioctl, userland falls back to a correct path
	 * of waiting for a vblank, then dispatching the swap on its own.
	 * Context switching to userland and back is plenty fast enough for
	 * meeting the requirements of vblank swapping.
	 */

	return -EINVAL;
}

/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(struct drm_device * dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

	I915_WRITE(HWSTAM, 0xeffe);
	I915_WRITE(PIPEASTAT, 0);
	I915_WRITE(PIPEBSTAT, 0);
	I915_WRITE(IMR, 0xffffffff);
	I915_WRITE(IER, 0x0);
	(void) I915_READ(IER);
}

int i915_driver_irq_postinstall(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;

	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */

	/* Unmask the interrupts that we always want on. */
	dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;

	dev_priv->pipestat[0] = 0;
	dev_priv->pipestat[1] = 0;

	/* Disable pipe interrupt enables, clear pending pipe status */
	I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
	I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);

	/* Clear pending interrupt status */
	I915_WRITE(IIR, I915_READ(IIR));

	I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
	I915_WRITE(IMR, dev_priv->irq_mask_reg);
	(void) I915_READ(IER);
#ifdef __linux__
	opregion_enable_asle(dev);
#endif
	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);

	i915_enable_vblank(dev, 0);
	i915_enable_vblank(dev, 1);

	return 0;
}

void i915_driver_irq_uninstall(struct drm_device * dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

	if (!dev_priv)
		return;

	dev_priv->vblank_pipe = 0;

	I915_WRITE(HWSTAM, 0xffffffff);
	I915_WRITE(PIPEASTAT, 0);
	I915_WRITE(PIPEBSTAT, 0);
	I915_WRITE(IMR, 0xffffffff);
	I915_WRITE(IER, 0x0);

	I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
	I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
	I915_WRITE(IIR, I915_READ(IIR));
}