13446Smrj /* BEGIN CSTYLED */
23446Smrj
33446Smrj /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
43446Smrj */
54194Szw161486 /*
63446Smrj * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
711260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation.
83446Smrj * All Rights Reserved.
93446Smrj *
103446Smrj * Permission is hereby granted, free of charge, to any person obtaining a
113446Smrj * copy of this software and associated documentation files (the
123446Smrj * "Software"), to deal in the Software without restriction, including
133446Smrj * without limitation the rights to use, copy, modify, merge, publish,
143446Smrj * distribute, sub license, and/or sell copies of the Software, and to
153446Smrj * permit persons to whom the Software is furnished to do so, subject to
163446Smrj * the following conditions:
173446Smrj *
183446Smrj * The above copyright notice and this permission notice (including the
193446Smrj * next paragraph) shall be included in all copies or substantial portions
203446Smrj * of the Software.
213446Smrj *
223446Smrj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
233446Smrj * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
243446Smrj * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
253446Smrj * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
263446Smrj * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
273446Smrj * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
283446Smrj * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
293446Smrj *
304194Szw161486 */
314194Szw161486
324194Szw161486 /*
338832SMiao.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
344194Szw161486 * Use is subject to license terms.
354194Szw161486 */
363446Smrj
373446Smrj #include "drmP.h"
383446Smrj #include "drm.h"
393446Smrj #include "i915_drm.h"
403446Smrj #include "i915_drv.h"
413446Smrj
424194Szw161486
433446Smrj #define MAX_NOPID ((u32)~0)
444194Szw161486
4511260SMiao.Chen@Sun.COM /**
4611260SMiao.Chen@Sun.COM * Interrupts that are always left unmasked.
4711260SMiao.Chen@Sun.COM *
4811260SMiao.Chen@Sun.COM * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
4911260SMiao.Chen@Sun.COM * we leave them always unmasked in IMR and then control enabling them through
5011260SMiao.Chen@Sun.COM * PIPESTAT alone.
518832SMiao.Chen@Sun.COM */
5211260SMiao.Chen@Sun.COM
5311260SMiao.Chen@Sun.COM #define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
5411260SMiao.Chen@Sun.COM I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
5511260SMiao.Chen@Sun.COM I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
5611260SMiao.Chen@Sun.COM I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
5711260SMiao.Chen@Sun.COM
5811260SMiao.Chen@Sun.COM /** Interrupts that we mask and unmask at runtime. */
5911260SMiao.Chen@Sun.COM #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
6011260SMiao.Chen@Sun.COM
6111260SMiao.Chen@Sun.COM /** These are all of the interrupts used by the driver */
6211260SMiao.Chen@Sun.COM #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
6311260SMiao.Chen@Sun.COM I915_INTERRUPT_ENABLE_VAR)
648832SMiao.Chen@Sun.COM
65*11359SMiao.Chen@Sun.COM void
igdng_enable_irq(drm_i915_private_t * dev_priv,u32 mask,int gfx_irq)66*11359SMiao.Chen@Sun.COM igdng_enable_irq(drm_i915_private_t *dev_priv, u32 mask, int gfx_irq)
67*11359SMiao.Chen@Sun.COM {
68*11359SMiao.Chen@Sun.COM if (gfx_irq && ((dev_priv->gt_irq_mask_reg & mask) != 0)) {
69*11359SMiao.Chen@Sun.COM dev_priv->gt_irq_mask_reg &= ~mask;
70*11359SMiao.Chen@Sun.COM I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
71*11359SMiao.Chen@Sun.COM (void) I915_READ(GTIMR);
72*11359SMiao.Chen@Sun.COM } else if ((dev_priv->irq_mask_reg & mask) != 0) {
73*11359SMiao.Chen@Sun.COM dev_priv->irq_mask_reg &= ~mask;
74*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
75*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIMR);
76*11359SMiao.Chen@Sun.COM
77*11359SMiao.Chen@Sun.COM }
78*11359SMiao.Chen@Sun.COM }
79*11359SMiao.Chen@Sun.COM
80*11359SMiao.Chen@Sun.COM static inline void
igdng_disable_irq(drm_i915_private_t * dev_priv,u32 mask,int gfx_irq)81*11359SMiao.Chen@Sun.COM igdng_disable_irq(drm_i915_private_t *dev_priv, u32 mask, int gfx_irq)
82*11359SMiao.Chen@Sun.COM {
83*11359SMiao.Chen@Sun.COM if (gfx_irq && ((dev_priv->gt_irq_mask_reg & mask) != mask)) {
84*11359SMiao.Chen@Sun.COM dev_priv->gt_irq_mask_reg |= mask;
85*11359SMiao.Chen@Sun.COM I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
86*11359SMiao.Chen@Sun.COM (void) I915_READ(GTIMR);
87*11359SMiao.Chen@Sun.COM } else if ((dev_priv->irq_mask_reg & mask) != mask) {
88*11359SMiao.Chen@Sun.COM dev_priv->irq_mask_reg |= mask;
89*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
90*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIMR);
91*11359SMiao.Chen@Sun.COM }
92*11359SMiao.Chen@Sun.COM }
93*11359SMiao.Chen@Sun.COM
94*11359SMiao.Chen@Sun.COM /* For display hotplug interrupt */
95*11359SMiao.Chen@Sun.COM void
igdng_enable_display_irq(drm_i915_private_t * dev_priv,u32 mask)96*11359SMiao.Chen@Sun.COM igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
97*11359SMiao.Chen@Sun.COM {
98*11359SMiao.Chen@Sun.COM if ((dev_priv->irq_mask_reg & mask) != 0) {
99*11359SMiao.Chen@Sun.COM dev_priv->irq_mask_reg &= ~mask;
100*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
101*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIMR);
102*11359SMiao.Chen@Sun.COM }
103*11359SMiao.Chen@Sun.COM }
104*11359SMiao.Chen@Sun.COM
105*11359SMiao.Chen@Sun.COM #if 0
106*11359SMiao.Chen@Sun.COM static inline void
107*11359SMiao.Chen@Sun.COM igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
108*11359SMiao.Chen@Sun.COM {
109*11359SMiao.Chen@Sun.COM if ((dev_priv->irq_mask_reg & mask) != mask) {
110*11359SMiao.Chen@Sun.COM dev_priv->irq_mask_reg |= mask;
111*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
112*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIMR);
113*11359SMiao.Chen@Sun.COM }
114*11359SMiao.Chen@Sun.COM }
115*11359SMiao.Chen@Sun.COM #endif
116*11359SMiao.Chen@Sun.COM
1178832SMiao.Chen@Sun.COM static inline void
i915_enable_irq(drm_i915_private_t * dev_priv,uint32_t mask)1188832SMiao.Chen@Sun.COM i915_enable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
1198832SMiao.Chen@Sun.COM {
12011260SMiao.Chen@Sun.COM if ((dev_priv->irq_mask_reg & mask) != 0) {
12111260SMiao.Chen@Sun.COM dev_priv->irq_mask_reg &= ~mask;
12211260SMiao.Chen@Sun.COM I915_WRITE(IMR, dev_priv->irq_mask_reg);
12311260SMiao.Chen@Sun.COM (void) I915_READ(IMR);
12411260SMiao.Chen@Sun.COM }
1258832SMiao.Chen@Sun.COM }
1268832SMiao.Chen@Sun.COM
1278832SMiao.Chen@Sun.COM static inline void
i915_disable_irq(drm_i915_private_t * dev_priv,uint32_t mask)1288832SMiao.Chen@Sun.COM i915_disable_irq(drm_i915_private_t *dev_priv, uint32_t mask)
1298832SMiao.Chen@Sun.COM {
1308832SMiao.Chen@Sun.COM if ((dev_priv->irq_mask_reg & mask) != mask) {
13111260SMiao.Chen@Sun.COM dev_priv->irq_mask_reg |= mask;
13211260SMiao.Chen@Sun.COM I915_WRITE(IMR, dev_priv->irq_mask_reg);
13311260SMiao.Chen@Sun.COM (void) I915_READ(IMR);
13411260SMiao.Chen@Sun.COM }
13511260SMiao.Chen@Sun.COM }
13611260SMiao.Chen@Sun.COM
13711260SMiao.Chen@Sun.COM static inline uint32_t
i915_pipestat(int pipe)13811260SMiao.Chen@Sun.COM i915_pipestat(int pipe)
13911260SMiao.Chen@Sun.COM {
14011260SMiao.Chen@Sun.COM if (pipe == 0)
14111260SMiao.Chen@Sun.COM return PIPEASTAT;
14211260SMiao.Chen@Sun.COM if (pipe == 1)
14311260SMiao.Chen@Sun.COM return PIPEBSTAT;
14411260SMiao.Chen@Sun.COM return 0;
14511260SMiao.Chen@Sun.COM }
14611260SMiao.Chen@Sun.COM
14711260SMiao.Chen@Sun.COM void
i915_enable_pipestat(drm_i915_private_t * dev_priv,int pipe,uint32_t mask)14811260SMiao.Chen@Sun.COM i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, uint32_t mask)
14911260SMiao.Chen@Sun.COM {
15011260SMiao.Chen@Sun.COM if ((dev_priv->pipestat[pipe] & mask) != mask) {
15111260SMiao.Chen@Sun.COM u32 reg = i915_pipestat(pipe);
15211260SMiao.Chen@Sun.COM
15311260SMiao.Chen@Sun.COM dev_priv->pipestat[pipe] |= mask;
15411260SMiao.Chen@Sun.COM /* Enable the interrupt, clear any pending status */
15511260SMiao.Chen@Sun.COM I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
15611260SMiao.Chen@Sun.COM (void) I915_READ(reg);
1578832SMiao.Chen@Sun.COM }
1588832SMiao.Chen@Sun.COM }
1598832SMiao.Chen@Sun.COM
16011260SMiao.Chen@Sun.COM void
i915_disable_pipestat(drm_i915_private_t * dev_priv,int pipe,u32 mask)16111260SMiao.Chen@Sun.COM i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
16211260SMiao.Chen@Sun.COM {
16311260SMiao.Chen@Sun.COM if ((dev_priv->pipestat[pipe] & mask) != 0) {
16411260SMiao.Chen@Sun.COM u32 reg = i915_pipestat(pipe);
1658832SMiao.Chen@Sun.COM
16611260SMiao.Chen@Sun.COM dev_priv->pipestat[pipe] &= ~mask;
16711260SMiao.Chen@Sun.COM I915_WRITE(reg, dev_priv->pipestat[pipe]);
16811260SMiao.Chen@Sun.COM (void) I915_READ(reg);
16911260SMiao.Chen@Sun.COM }
1708832SMiao.Chen@Sun.COM }
1718832SMiao.Chen@Sun.COM
1728832SMiao.Chen@Sun.COM /**
1738832SMiao.Chen@Sun.COM * i915_pipe_enabled - check if a pipe is enabled
1748832SMiao.Chen@Sun.COM * @dev: DRM device
1758832SMiao.Chen@Sun.COM * @pipe: pipe to check
1768832SMiao.Chen@Sun.COM *
1778832SMiao.Chen@Sun.COM * Reading certain registers when the pipe is disabled can hang the chip.
1788832SMiao.Chen@Sun.COM * Use this routine to make sure the PLL is running and the pipe is active
1798832SMiao.Chen@Sun.COM * before reading such registers if unsure.
1808832SMiao.Chen@Sun.COM */
1818832SMiao.Chen@Sun.COM static int
i915_pipe_enabled(struct drm_device * dev,int pipe)1828832SMiao.Chen@Sun.COM i915_pipe_enabled(struct drm_device *dev, int pipe)
1838832SMiao.Chen@Sun.COM {
1848832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1858832SMiao.Chen@Sun.COM unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
1868832SMiao.Chen@Sun.COM
1878832SMiao.Chen@Sun.COM if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
1888832SMiao.Chen@Sun.COM return 1;
1898832SMiao.Chen@Sun.COM
1908832SMiao.Chen@Sun.COM return 0;
1918832SMiao.Chen@Sun.COM }
1928832SMiao.Chen@Sun.COM
i915_get_vblank_counter(struct drm_device * dev,int pipe)19311260SMiao.Chen@Sun.COM u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
1948832SMiao.Chen@Sun.COM {
1958832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1968832SMiao.Chen@Sun.COM unsigned long high_frame;
1978832SMiao.Chen@Sun.COM unsigned long low_frame;
1988832SMiao.Chen@Sun.COM u32 high1, high2, low, count;
1998832SMiao.Chen@Sun.COM
2008832SMiao.Chen@Sun.COM high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
2018832SMiao.Chen@Sun.COM low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
2028832SMiao.Chen@Sun.COM
2038832SMiao.Chen@Sun.COM if (!i915_pipe_enabled(dev, pipe)) {
20411260SMiao.Chen@Sun.COM DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
2058832SMiao.Chen@Sun.COM return 0;
2068832SMiao.Chen@Sun.COM }
2078832SMiao.Chen@Sun.COM
2088832SMiao.Chen@Sun.COM /*
2098832SMiao.Chen@Sun.COM * High & low register fields aren't synchronized, so make sure
2108832SMiao.Chen@Sun.COM * we get a low value that's stable across two reads of the high
2118832SMiao.Chen@Sun.COM * register.
2128832SMiao.Chen@Sun.COM */
2138832SMiao.Chen@Sun.COM do {
2148832SMiao.Chen@Sun.COM high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
2158832SMiao.Chen@Sun.COM PIPE_FRAME_HIGH_SHIFT);
2168832SMiao.Chen@Sun.COM low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
2178832SMiao.Chen@Sun.COM PIPE_FRAME_LOW_SHIFT);
2188832SMiao.Chen@Sun.COM high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
2198832SMiao.Chen@Sun.COM PIPE_FRAME_HIGH_SHIFT);
2208832SMiao.Chen@Sun.COM } while (high1 != high2);
2218832SMiao.Chen@Sun.COM
2228832SMiao.Chen@Sun.COM count = (high1 << 8) | low;
2238832SMiao.Chen@Sun.COM
2248832SMiao.Chen@Sun.COM return count;
2258832SMiao.Chen@Sun.COM }
2268832SMiao.Chen@Sun.COM
22711260SMiao.Chen@Sun.COM /**
22811260SMiao.Chen@Sun.COM * i915_capture_error_state - capture an error record for later analysis
22911260SMiao.Chen@Sun.COM * @dev: drm device
23011260SMiao.Chen@Sun.COM *
23111260SMiao.Chen@Sun.COM * Should be called when an error is detected (either a hang or an error
23211260SMiao.Chen@Sun.COM * interrupt) to capture error state from the time of the error. Fills
23311260SMiao.Chen@Sun.COM * out a structure which becomes available in debugfs for user level tools
23411260SMiao.Chen@Sun.COM * to pick up.
23511260SMiao.Chen@Sun.COM */
i915_capture_error_state(struct drm_device * dev)23611260SMiao.Chen@Sun.COM static void i915_capture_error_state(struct drm_device *dev)
23711260SMiao.Chen@Sun.COM {
23811260SMiao.Chen@Sun.COM struct drm_i915_private *dev_priv = dev->dev_private;
23911260SMiao.Chen@Sun.COM struct drm_i915_error_state *error;
24011260SMiao.Chen@Sun.COM
24111260SMiao.Chen@Sun.COM spin_lock_irqsave(&dev_priv->error_lock, flags);
24211260SMiao.Chen@Sun.COM #if 0
24311260SMiao.Chen@Sun.COM if (dev_priv->first_error)
24411260SMiao.Chen@Sun.COM goto out;
24511260SMiao.Chen@Sun.COM #endif
24611260SMiao.Chen@Sun.COM error = drm_alloc(sizeof(*error), DRM_MEM_DRIVER);
24711260SMiao.Chen@Sun.COM if (!error) {
24811260SMiao.Chen@Sun.COM DRM_DEBUG("out ot memory, not capturing error state\n");
24911260SMiao.Chen@Sun.COM goto out;
25011260SMiao.Chen@Sun.COM }
25111260SMiao.Chen@Sun.COM
25211260SMiao.Chen@Sun.COM error->eir = I915_READ(EIR);
25311260SMiao.Chen@Sun.COM error->pgtbl_er = I915_READ(PGTBL_ER);
25411260SMiao.Chen@Sun.COM error->pipeastat = I915_READ(PIPEASTAT);
25511260SMiao.Chen@Sun.COM error->pipebstat = I915_READ(PIPEBSTAT);
25611260SMiao.Chen@Sun.COM error->instpm = I915_READ(INSTPM);
25711260SMiao.Chen@Sun.COM if (!IS_I965G(dev)) {
25811260SMiao.Chen@Sun.COM error->ipeir = I915_READ(IPEIR);
25911260SMiao.Chen@Sun.COM error->ipehr = I915_READ(IPEHR);
26011260SMiao.Chen@Sun.COM error->instdone = I915_READ(INSTDONE);
26111260SMiao.Chen@Sun.COM error->acthd = I915_READ(ACTHD);
26211260SMiao.Chen@Sun.COM } else {
26311260SMiao.Chen@Sun.COM error->ipeir = I915_READ(IPEIR_I965);
26411260SMiao.Chen@Sun.COM error->ipehr = I915_READ(IPEHR_I965);
26511260SMiao.Chen@Sun.COM error->instdone = I915_READ(INSTDONE_I965);
26611260SMiao.Chen@Sun.COM error->instps = I915_READ(INSTPS);
26711260SMiao.Chen@Sun.COM error->instdone1 = I915_READ(INSTDONE1);
26811260SMiao.Chen@Sun.COM error->acthd = I915_READ(ACTHD_I965);
26911260SMiao.Chen@Sun.COM }
27011260SMiao.Chen@Sun.COM
27111260SMiao.Chen@Sun.COM (void) uniqtime(&error->time);
27211260SMiao.Chen@Sun.COM
27311260SMiao.Chen@Sun.COM dev_priv->first_error = error;
27411260SMiao.Chen@Sun.COM
27511260SMiao.Chen@Sun.COM DRM_DEBUG("Time: %ld s %ld us\n", error->time.tv_sec,
27611260SMiao.Chen@Sun.COM error->time.tv_usec);
27711260SMiao.Chen@Sun.COM DRM_DEBUG("EIR: 0x%08x\n", error->eir);
27811260SMiao.Chen@Sun.COM DRM_DEBUG(" PGTBL_ER: 0x%08x\n", error->pgtbl_er);
27911260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTPM: 0x%08x\n", error->instpm);
28011260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEIR: 0x%08x\n", error->ipeir);
28111260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEHR: 0x%08x\n", error->ipehr);
28211260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE: 0x%08x\n", error->instdone);
28311260SMiao.Chen@Sun.COM DRM_DEBUG(" ACTHD: 0x%08x\n", error->acthd);
28411260SMiao.Chen@Sun.COM DRM_DEBUG(" DMA_FADD_P: 0x%08x\n", I915_READ(0x2078));
28511260SMiao.Chen@Sun.COM if (IS_I965G(dev)) {
28611260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTPS: 0x%08x\n", error->instps);
28711260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE1: 0x%08x\n", error->instdone1);
28811260SMiao.Chen@Sun.COM }
28911260SMiao.Chen@Sun.COM drm_free(error, sizeof(*error), DRM_MEM_DRIVER);
29011260SMiao.Chen@Sun.COM out:
29111260SMiao.Chen@Sun.COM spin_unlock_irqrestore(&dev_priv->error_lock, flags);
29211260SMiao.Chen@Sun.COM }
29311260SMiao.Chen@Sun.COM
29411260SMiao.Chen@Sun.COM /**
29511260SMiao.Chen@Sun.COM * i915_handle_error - handle an error interrupt
29611260SMiao.Chen@Sun.COM * @dev: drm device
29711260SMiao.Chen@Sun.COM *
29811260SMiao.Chen@Sun.COM * Do some basic checking of regsiter state at error interrupt time and
29911260SMiao.Chen@Sun.COM * dump it to the syslog. Also call i915_capture_error_state() to make
30011260SMiao.Chen@Sun.COM * sure we get a record and make it available in debugfs. Fire a uevent
30111260SMiao.Chen@Sun.COM * so userspace knows something bad happened (should trigger collection
30211260SMiao.Chen@Sun.COM * of a ring dump etc.).
30311260SMiao.Chen@Sun.COM */
i915_handle_error(struct drm_device * dev)30411260SMiao.Chen@Sun.COM void i915_handle_error(struct drm_device *dev)
30511260SMiao.Chen@Sun.COM {
30611260SMiao.Chen@Sun.COM struct drm_i915_private *dev_priv = dev->dev_private;
30711260SMiao.Chen@Sun.COM u32 eir = I915_READ(EIR);
30811260SMiao.Chen@Sun.COM u32 pipea_stats = I915_READ(PIPEASTAT);
30911260SMiao.Chen@Sun.COM u32 pipeb_stats = I915_READ(PIPEBSTAT);
31011260SMiao.Chen@Sun.COM
31111260SMiao.Chen@Sun.COM i915_capture_error_state(dev);
31211260SMiao.Chen@Sun.COM
31311260SMiao.Chen@Sun.COM DRM_DEBUG("render error detected, EIR: 0x%08x\n",
31411260SMiao.Chen@Sun.COM eir);
31511260SMiao.Chen@Sun.COM
31611260SMiao.Chen@Sun.COM if (IS_G4X(dev)) {
31711260SMiao.Chen@Sun.COM if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
31811260SMiao.Chen@Sun.COM u32 ipeir = I915_READ(IPEIR_I965);
31911260SMiao.Chen@Sun.COM
32011260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEIR: 0x%08x\n",
32111260SMiao.Chen@Sun.COM I915_READ(IPEIR_I965));
32211260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEHR: 0x%08x\n",
32311260SMiao.Chen@Sun.COM I915_READ(IPEHR_I965));
32411260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE: 0x%08x\n",
32511260SMiao.Chen@Sun.COM I915_READ(INSTDONE_I965));
32611260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTPS: 0x%08x\n",
32711260SMiao.Chen@Sun.COM I915_READ(INSTPS));
32811260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE1: 0x%08x\n",
32911260SMiao.Chen@Sun.COM I915_READ(INSTDONE1));
33011260SMiao.Chen@Sun.COM DRM_DEBUG(" ACTHD: 0x%08x\n",
33111260SMiao.Chen@Sun.COM I915_READ(ACTHD_I965));
33211260SMiao.Chen@Sun.COM I915_WRITE(IPEIR_I965, ipeir);
33311260SMiao.Chen@Sun.COM (void)I915_READ(IPEIR_I965);
33411260SMiao.Chen@Sun.COM }
33511260SMiao.Chen@Sun.COM if (eir & GM45_ERROR_PAGE_TABLE) {
33611260SMiao.Chen@Sun.COM u32 pgtbl_err = I915_READ(PGTBL_ER);
33711260SMiao.Chen@Sun.COM DRM_DEBUG("page table error\n");
33811260SMiao.Chen@Sun.COM DRM_DEBUG(" PGTBL_ER: 0x%08x\n",
33911260SMiao.Chen@Sun.COM pgtbl_err);
34011260SMiao.Chen@Sun.COM I915_WRITE(PGTBL_ER, pgtbl_err);
34111260SMiao.Chen@Sun.COM (void)I915_READ(PGTBL_ER);
34211260SMiao.Chen@Sun.COM }
34311260SMiao.Chen@Sun.COM }
34411260SMiao.Chen@Sun.COM
34511260SMiao.Chen@Sun.COM if (IS_I9XX(dev)) {
34611260SMiao.Chen@Sun.COM if (eir & I915_ERROR_PAGE_TABLE) {
34711260SMiao.Chen@Sun.COM u32 pgtbl_err = I915_READ(PGTBL_ER);
34811260SMiao.Chen@Sun.COM DRM_DEBUG("page table error\n");
34911260SMiao.Chen@Sun.COM DRM_DEBUG("PGTBL_ER: 0x%08x\n",
35011260SMiao.Chen@Sun.COM pgtbl_err);
35111260SMiao.Chen@Sun.COM I915_WRITE(PGTBL_ER, pgtbl_err);
35211260SMiao.Chen@Sun.COM (void)I915_READ(PGTBL_ER);
35311260SMiao.Chen@Sun.COM }
35411260SMiao.Chen@Sun.COM }
35511260SMiao.Chen@Sun.COM
35611260SMiao.Chen@Sun.COM if (eir & I915_ERROR_MEMORY_REFRESH) {
35711260SMiao.Chen@Sun.COM DRM_DEBUG("memory refresh error\n");
35811260SMiao.Chen@Sun.COM DRM_DEBUG("PIPEASTAT: 0x%08x\n",
35911260SMiao.Chen@Sun.COM pipea_stats);
36011260SMiao.Chen@Sun.COM DRM_DEBUG("PIPEBSTAT: 0x%08x\n",
36111260SMiao.Chen@Sun.COM pipeb_stats);
36211260SMiao.Chen@Sun.COM /* pipestat has already been acked */
36311260SMiao.Chen@Sun.COM }
36411260SMiao.Chen@Sun.COM if (eir & I915_ERROR_INSTRUCTION) {
36511260SMiao.Chen@Sun.COM DRM_DEBUG("instruction error\n");
36611260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTPM: 0x%08x\n",
36711260SMiao.Chen@Sun.COM I915_READ(INSTPM));
36811260SMiao.Chen@Sun.COM if (!IS_I965G(dev)) {
36911260SMiao.Chen@Sun.COM u32 ipeir = I915_READ(IPEIR);
37011260SMiao.Chen@Sun.COM
37111260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEIR: 0x%08x\n",
37211260SMiao.Chen@Sun.COM I915_READ(IPEIR));
37311260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEHR: 0x%08x\n",
37411260SMiao.Chen@Sun.COM I915_READ(IPEHR));
37511260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE: 0x%08x\n",
37611260SMiao.Chen@Sun.COM I915_READ(INSTDONE));
37711260SMiao.Chen@Sun.COM DRM_DEBUG(" ACTHD: 0x%08x\n",
37811260SMiao.Chen@Sun.COM I915_READ(ACTHD));
37911260SMiao.Chen@Sun.COM I915_WRITE(IPEIR, ipeir);
38011260SMiao.Chen@Sun.COM (void)I915_READ(IPEIR);
38111260SMiao.Chen@Sun.COM } else {
38211260SMiao.Chen@Sun.COM u32 ipeir = I915_READ(IPEIR_I965);
38311260SMiao.Chen@Sun.COM
38411260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEIR: 0x%08x\n",
38511260SMiao.Chen@Sun.COM I915_READ(IPEIR_I965));
38611260SMiao.Chen@Sun.COM DRM_DEBUG(" IPEHR: 0x%08x\n",
38711260SMiao.Chen@Sun.COM I915_READ(IPEHR_I965));
38811260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE: 0x%08x\n",
38911260SMiao.Chen@Sun.COM I915_READ(INSTDONE_I965));
39011260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTPS: 0x%08x\n",
39111260SMiao.Chen@Sun.COM I915_READ(INSTPS));
39211260SMiao.Chen@Sun.COM DRM_DEBUG(" INSTDONE1: 0x%08x\n",
39311260SMiao.Chen@Sun.COM I915_READ(INSTDONE1));
39411260SMiao.Chen@Sun.COM DRM_DEBUG(" ACTHD: 0x%08x\n",
39511260SMiao.Chen@Sun.COM I915_READ(ACTHD_I965));
39611260SMiao.Chen@Sun.COM I915_WRITE(IPEIR_I965, ipeir);
39711260SMiao.Chen@Sun.COM (void)I915_READ(IPEIR_I965);
39811260SMiao.Chen@Sun.COM }
39911260SMiao.Chen@Sun.COM }
40011260SMiao.Chen@Sun.COM
40111260SMiao.Chen@Sun.COM I915_WRITE(EIR, eir);
40211260SMiao.Chen@Sun.COM (void)I915_READ(EIR);
40311260SMiao.Chen@Sun.COM eir = I915_READ(EIR);
40411260SMiao.Chen@Sun.COM if (eir) {
40511260SMiao.Chen@Sun.COM /*
40611260SMiao.Chen@Sun.COM * some errors might have become stuck,
40711260SMiao.Chen@Sun.COM * mask them.
40811260SMiao.Chen@Sun.COM */
40911260SMiao.Chen@Sun.COM DRM_DEBUG("EIR stuck: 0x%08x, masking\n", eir);
41011260SMiao.Chen@Sun.COM I915_WRITE(EMR, I915_READ(EMR) | eir);
41111260SMiao.Chen@Sun.COM I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
41211260SMiao.Chen@Sun.COM }
41311260SMiao.Chen@Sun.COM
41411260SMiao.Chen@Sun.COM }
41511260SMiao.Chen@Sun.COM
gm45_get_vblank_counter(struct drm_device * dev,int pipe)41611260SMiao.Chen@Sun.COM u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
41711260SMiao.Chen@Sun.COM {
41811260SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
41911260SMiao.Chen@Sun.COM int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;
42011260SMiao.Chen@Sun.COM
42111260SMiao.Chen@Sun.COM if (!i915_pipe_enabled(dev, pipe)) {
42211260SMiao.Chen@Sun.COM DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe);
42311260SMiao.Chen@Sun.COM return 0;
42411260SMiao.Chen@Sun.COM }
42511260SMiao.Chen@Sun.COM
42611260SMiao.Chen@Sun.COM return I915_READ(reg);
42711260SMiao.Chen@Sun.COM }
42811260SMiao.Chen@Sun.COM
igdng_irq_handler(struct drm_device * dev)429*11359SMiao.Chen@Sun.COM irqreturn_t igdng_irq_handler(struct drm_device *dev)
430*11359SMiao.Chen@Sun.COM {
431*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
432*11359SMiao.Chen@Sun.COM int ret = IRQ_NONE;
433*11359SMiao.Chen@Sun.COM u32 de_iir, gt_iir, de_ier;
434*11359SMiao.Chen@Sun.COM u32 new_de_iir, new_gt_iir;
435*11359SMiao.Chen@Sun.COM int vblank = 0;
436*11359SMiao.Chen@Sun.COM
437*11359SMiao.Chen@Sun.COM /* disable master interrupt before clearing iir */
438*11359SMiao.Chen@Sun.COM de_ier = I915_READ(DEIER);
439*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
440*11359SMiao.Chen@Sun.COM (void)I915_READ(DEIER);
441*11359SMiao.Chen@Sun.COM
442*11359SMiao.Chen@Sun.COM de_iir = I915_READ(DEIIR);
443*11359SMiao.Chen@Sun.COM gt_iir = I915_READ(GTIIR);
444*11359SMiao.Chen@Sun.COM
445*11359SMiao.Chen@Sun.COM for (;;) {
446*11359SMiao.Chen@Sun.COM if (de_iir == 0 && gt_iir == 0)
447*11359SMiao.Chen@Sun.COM break;
448*11359SMiao.Chen@Sun.COM
449*11359SMiao.Chen@Sun.COM ret = IRQ_HANDLED;
450*11359SMiao.Chen@Sun.COM
451*11359SMiao.Chen@Sun.COM I915_WRITE(DEIIR, de_iir);
452*11359SMiao.Chen@Sun.COM new_de_iir = I915_READ(DEIIR);
453*11359SMiao.Chen@Sun.COM I915_WRITE(GTIIR, gt_iir);
454*11359SMiao.Chen@Sun.COM new_gt_iir = I915_READ(GTIIR);
455*11359SMiao.Chen@Sun.COM
456*11359SMiao.Chen@Sun.COM if (dev_priv->sarea_priv) {
457*11359SMiao.Chen@Sun.COM dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
458*11359SMiao.Chen@Sun.COM
459*11359SMiao.Chen@Sun.COM }
460*11359SMiao.Chen@Sun.COM
461*11359SMiao.Chen@Sun.COM if (gt_iir & GT_USER_INTERRUPT) {
462*11359SMiao.Chen@Sun.COM dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
463*11359SMiao.Chen@Sun.COM DRM_WAKEUP(&dev_priv->irq_queue);
464*11359SMiao.Chen@Sun.COM }
465*11359SMiao.Chen@Sun.COM if (de_iir & DE_PIPEA_VBLANK) {
466*11359SMiao.Chen@Sun.COM vblank++;
467*11359SMiao.Chen@Sun.COM drm_handle_vblank(dev, 0);
468*11359SMiao.Chen@Sun.COM }
469*11359SMiao.Chen@Sun.COM
470*11359SMiao.Chen@Sun.COM if (de_iir & DE_PIPEB_VBLANK) {
471*11359SMiao.Chen@Sun.COM vblank++;
472*11359SMiao.Chen@Sun.COM drm_handle_vblank(dev, 1);
473*11359SMiao.Chen@Sun.COM }
474*11359SMiao.Chen@Sun.COM
475*11359SMiao.Chen@Sun.COM de_iir = new_de_iir;
476*11359SMiao.Chen@Sun.COM gt_iir = new_gt_iir;
477*11359SMiao.Chen@Sun.COM }
478*11359SMiao.Chen@Sun.COM
479*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, de_ier);
480*11359SMiao.Chen@Sun.COM (void)I915_READ(DEIER);
481*11359SMiao.Chen@Sun.COM
482*11359SMiao.Chen@Sun.COM return ret;
483*11359SMiao.Chen@Sun.COM }
484*11359SMiao.Chen@Sun.COM
i915_driver_irq_handler(DRM_IRQ_ARGS)4853446Smrj irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
4863446Smrj {
4878832SMiao.Chen@Sun.COM drm_device_t *dev = (drm_device_t *) (void *) arg;
4888832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
4898832SMiao.Chen@Sun.COM u32 iir;
4908832SMiao.Chen@Sun.COM u32 pipea_stats = 0, pipeb_stats = 0;
4918832SMiao.Chen@Sun.COM int vblank = 0;
49211260SMiao.Chen@Sun.COM
493*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev))
494*11359SMiao.Chen@Sun.COM return igdng_irq_handler(dev);
495*11359SMiao.Chen@Sun.COM
4968832SMiao.Chen@Sun.COM iir = I915_READ(IIR);
4973446Smrj
4988832SMiao.Chen@Sun.COM if (iir == 0) {
4998832SMiao.Chen@Sun.COM return IRQ_NONE;
5004194Szw161486 }
50111260SMiao.Chen@Sun.COM start:
5028832SMiao.Chen@Sun.COM
50311260SMiao.Chen@Sun.COM if (dev_priv->sarea_priv) {
50411260SMiao.Chen@Sun.COM if (dev_priv->hw_status_page)
50511260SMiao.Chen@Sun.COM dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
5068832SMiao.Chen@Sun.COM }
5078832SMiao.Chen@Sun.COM
5088832SMiao.Chen@Sun.COM I915_WRITE(IIR, iir);
5098832SMiao.Chen@Sun.COM
5108832SMiao.Chen@Sun.COM (void) I915_READ(IIR); /* Flush posted writes */
5114194Szw161486
51211260SMiao.Chen@Sun.COM
51311260SMiao.Chen@Sun.COM if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
51411260SMiao.Chen@Sun.COM i915_handle_error(dev);
51511260SMiao.Chen@Sun.COM
5168832SMiao.Chen@Sun.COM if (iir & I915_USER_INTERRUPT) {
51711260SMiao.Chen@Sun.COM dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
5188832SMiao.Chen@Sun.COM DRM_WAKEUP(&dev_priv->irq_queue);
5198832SMiao.Chen@Sun.COM }
5208832SMiao.Chen@Sun.COM
52111260SMiao.Chen@Sun.COM if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
52211260SMiao.Chen@Sun.COM pipea_stats = I915_READ(PIPEASTAT);
52311260SMiao.Chen@Sun.COM
52411260SMiao.Chen@Sun.COM /* The vblank interrupt gets enabled even if we didn't ask for
52511260SMiao.Chen@Sun.COM it, so make sure it's shut down again */
52611260SMiao.Chen@Sun.COM if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
52711260SMiao.Chen@Sun.COM pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
52811260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_ENABLE);
52911260SMiao.Chen@Sun.COM else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
53011260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_STATUS))
53111260SMiao.Chen@Sun.COM {
53211260SMiao.Chen@Sun.COM vblank++;
53311260SMiao.Chen@Sun.COM drm_handle_vblank(dev, 0);
53411260SMiao.Chen@Sun.COM }
5353446Smrj
53611260SMiao.Chen@Sun.COM I915_WRITE(PIPEASTAT, pipea_stats);
53711260SMiao.Chen@Sun.COM }
53811260SMiao.Chen@Sun.COM if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
53911260SMiao.Chen@Sun.COM pipeb_stats = I915_READ(PIPEBSTAT);
54011260SMiao.Chen@Sun.COM
54111260SMiao.Chen@Sun.COM /* The vblank interrupt gets enabled even if we didn't ask for
54211260SMiao.Chen@Sun.COM it, so make sure it's shut down again */
54311260SMiao.Chen@Sun.COM if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
54411260SMiao.Chen@Sun.COM pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
54511260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_ENABLE);
54611260SMiao.Chen@Sun.COM else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
54711260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_STATUS))
54811260SMiao.Chen@Sun.COM {
54911260SMiao.Chen@Sun.COM vblank++;
55011260SMiao.Chen@Sun.COM drm_handle_vblank(dev, 1);
55111260SMiao.Chen@Sun.COM }
55211260SMiao.Chen@Sun.COM
55311260SMiao.Chen@Sun.COM I915_WRITE(PIPEBSTAT, pipeb_stats);
55411260SMiao.Chen@Sun.COM }
55511260SMiao.Chen@Sun.COM return IRQ_HANDLED;
5568832SMiao.Chen@Sun.COM
5573446Smrj }
5583446Smrj
i915_emit_irq(drm_device_t * dev)5594194Szw161486 int i915_emit_irq(drm_device_t * dev)
5603446Smrj {
5614194Szw161486
5623446Smrj drm_i915_private_t *dev_priv = dev->dev_private;
5633446Smrj RING_LOCALS;
5643446Smrj
5653446Smrj i915_kernel_lost_context(dev);
56611260SMiao.Chen@Sun.COM
56711260SMiao.Chen@Sun.COM dev_priv->counter++;
56811260SMiao.Chen@Sun.COM if (dev_priv->counter > 0x7FFFFFFFUL)
56911260SMiao.Chen@Sun.COM dev_priv->counter = 1;
57011260SMiao.Chen@Sun.COM if (dev_priv->sarea_priv)
57111260SMiao.Chen@Sun.COM dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
5723446Smrj
57311260SMiao.Chen@Sun.COM #if defined(__i386)
57411260SMiao.Chen@Sun.COM if (IS_GM45(dev)) {
57511260SMiao.Chen@Sun.COM BEGIN_LP_RING(3);
57611260SMiao.Chen@Sun.COM OUT_RING(MI_STORE_DWORD_INDEX);
57711260SMiao.Chen@Sun.COM OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
57811260SMiao.Chen@Sun.COM OUT_RING(dev_priv->counter);
57911260SMiao.Chen@Sun.COM ADVANCE_LP_RING();
58011260SMiao.Chen@Sun.COM
58111260SMiao.Chen@Sun.COM (void) READ_BREADCRUMB(dev_priv);
58211260SMiao.Chen@Sun.COM BEGIN_LP_RING(2);
58311260SMiao.Chen@Sun.COM OUT_RING(0);
58411260SMiao.Chen@Sun.COM OUT_RING(MI_USER_INTERRUPT);
58511260SMiao.Chen@Sun.COM ADVANCE_LP_RING();
58611260SMiao.Chen@Sun.COM } else {
58711260SMiao.Chen@Sun.COM #endif /* __i386 */
58811260SMiao.Chen@Sun.COM BEGIN_LP_RING(4);
58911260SMiao.Chen@Sun.COM OUT_RING(MI_STORE_DWORD_INDEX);
59011260SMiao.Chen@Sun.COM OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
59111260SMiao.Chen@Sun.COM OUT_RING(dev_priv->counter);
5928832SMiao.Chen@Sun.COM OUT_RING(MI_USER_INTERRUPT);
5933446Smrj ADVANCE_LP_RING();
59411260SMiao.Chen@Sun.COM #if defined(__i386)
59511260SMiao.Chen@Sun.COM }
59611260SMiao.Chen@Sun.COM #endif /* __i386 */
59711260SMiao.Chen@Sun.COM
59811260SMiao.Chen@Sun.COM #if defined(__i386)
599*11359SMiao.Chen@Sun.COM if (IS_I965GM(dev) || IS_IGDNG(dev) || IS_GM45(dev))
60011260SMiao.Chen@Sun.COM #else
601*11359SMiao.Chen@Sun.COM if (IS_I965GM(dev) || IS_IGDNG(dev))
60211260SMiao.Chen@Sun.COM #endif /* __i386 */
60311260SMiao.Chen@Sun.COM {
60411260SMiao.Chen@Sun.COM (void) READ_BREADCRUMB(dev_priv);
60511260SMiao.Chen@Sun.COM BEGIN_LP_RING(2);
60611260SMiao.Chen@Sun.COM OUT_RING(0);
60711260SMiao.Chen@Sun.COM OUT_RING(0);
60811260SMiao.Chen@Sun.COM ADVANCE_LP_RING();
60911260SMiao.Chen@Sun.COM (void) READ_BREADCRUMB(dev_priv);
61011260SMiao.Chen@Sun.COM }
6114194Szw161486
6124194Szw161486 return dev_priv->counter;
6134194Szw161486 }
6143446Smrj
i915_user_irq_on(struct drm_device * dev)61511260SMiao.Chen@Sun.COM void i915_user_irq_on(struct drm_device *dev)
6164194Szw161486 {
61711260SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
6184194Szw161486 spin_lock(&dev_priv->user_irq_lock);
61911260SMiao.Chen@Sun.COM if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
620*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev))
621*11359SMiao.Chen@Sun.COM igdng_enable_irq(dev_priv, GT_USER_INTERRUPT, 1);
622*11359SMiao.Chen@Sun.COM else
623*11359SMiao.Chen@Sun.COM i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
6244194Szw161486 }
6254194Szw161486 spin_unlock(&dev_priv->user_irq_lock);
6264194Szw161486
6273446Smrj }
6284194Szw161486
i915_user_irq_off(struct drm_device * dev)62911260SMiao.Chen@Sun.COM void i915_user_irq_off(struct drm_device *dev)
6304194Szw161486 {
63111260SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
6324194Szw161486 spin_lock(&dev_priv->user_irq_lock);
63311260SMiao.Chen@Sun.COM if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
634*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev))
635*11359SMiao.Chen@Sun.COM igdng_disable_irq(dev_priv, GT_USER_INTERRUPT, 1);
636*11359SMiao.Chen@Sun.COM else
637*11359SMiao.Chen@Sun.COM i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
6384194Szw161486 }
6394194Szw161486 spin_unlock(&dev_priv->user_irq_lock);
6404194Szw161486 }
6414194Szw161486
6423446Smrj
i915_wait_irq(drm_device_t * dev,int irq_nr)6433446Smrj static int i915_wait_irq(drm_device_t * dev, int irq_nr)
6443446Smrj {
6453446Smrj drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
6463446Smrj int ret = 0;
647*11359SMiao.Chen@Sun.COM int wait_time = 0;
6483446Smrj
64911260SMiao.Chen@Sun.COM if (!dev_priv) {
65011260SMiao.Chen@Sun.COM DRM_ERROR("called with no initialization\n");
65111260SMiao.Chen@Sun.COM return -EINVAL;
65211260SMiao.Chen@Sun.COM }
6533446Smrj
654*11359SMiao.Chen@Sun.COM waitmore:
655*11359SMiao.Chen@Sun.COM wait_time++;
6568832SMiao.Chen@Sun.COM if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
65711260SMiao.Chen@Sun.COM if (dev_priv->sarea_priv) {
6588832SMiao.Chen@Sun.COM dev_priv->sarea_priv->last_dispatch =
6598832SMiao.Chen@Sun.COM READ_BREADCRUMB(dev_priv);
66011260SMiao.Chen@Sun.COM }
6618832SMiao.Chen@Sun.COM return 0;
6628832SMiao.Chen@Sun.COM }
6638832SMiao.Chen@Sun.COM DRM_DEBUG("i915_wait_irq: irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv));
66411260SMiao.Chen@Sun.COM i915_user_irq_on(dev);
6655804Scg149915 DRM_WAIT_ON(ret, &dev_priv->irq_queue, 3 * DRM_HZ,
6663446Smrj READ_BREADCRUMB(dev_priv) >= irq_nr);
66711260SMiao.Chen@Sun.COM i915_user_irq_off(dev);
6683446Smrj
66911260SMiao.Chen@Sun.COM if (ret == EBUSY) {
670*11359SMiao.Chen@Sun.COM if (wait_time > 5) {
6718832SMiao.Chen@Sun.COM DRM_DEBUG("%d: EBUSY -- rec: %d emitted: %d\n",
6728832SMiao.Chen@Sun.COM ret,
6733446Smrj READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
674*11359SMiao.Chen@Sun.COM return ret;
675*11359SMiao.Chen@Sun.COM }
676*11359SMiao.Chen@Sun.COM goto waitmore;
6773446Smrj }
6783446Smrj
6798832SMiao.Chen@Sun.COM if (dev_priv->sarea_priv)
6808832SMiao.Chen@Sun.COM dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
6814194Szw161486
682*11359SMiao.Chen@Sun.COM if (ret == EINTR) {
683*11359SMiao.Chen@Sun.COM if (wait_time > 5) {
684*11359SMiao.Chen@Sun.COM DRM_DEBUG("EINTR wait %d now %d", dev_priv->counter, READ_BREADCRUMB(dev_priv));
685*11359SMiao.Chen@Sun.COM return ret;
686*11359SMiao.Chen@Sun.COM }
687*11359SMiao.Chen@Sun.COM goto waitmore;
688*11359SMiao.Chen@Sun.COM }
689*11359SMiao.Chen@Sun.COM
6904194Szw161486 return ret;
6914194Szw161486 }
6924194Szw161486
6934194Szw161486
6943446Smrj /* Needs the lock as it touches the ring.
6953446Smrj */
6963446Smrj /*ARGSUSED*/
i915_irq_emit(DRM_IOCTL_ARGS)6973446Smrj int i915_irq_emit(DRM_IOCTL_ARGS)
6983446Smrj {
6993446Smrj DRM_DEVICE;
7003446Smrj drm_i915_private_t *dev_priv = dev->dev_private;
7013446Smrj drm_i915_irq_emit_t emit;
7023446Smrj int result;
7033446Smrj
7045804Scg149915 LOCK_TEST_WITH_RETURN(dev, fpriv);
7053446Smrj
7063446Smrj if (!dev_priv) {
7073446Smrj DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
7085804Scg149915 return (EINVAL);
7093446Smrj }
7103446Smrj
71111260SMiao.Chen@Sun.COM
7123446Smrj if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
7133446Smrj drm_i915_irq_emit32_t irq_emit32;
7143446Smrj
7155804Scg149915 DRM_COPYFROM_WITH_RETURN(&irq_emit32,
7163446Smrj (drm_i915_irq_emit32_t __user *) data,
7173446Smrj sizeof (drm_i915_irq_emit32_t));
7183446Smrj emit.irq_seq = (int __user *)(uintptr_t)irq_emit32.irq_seq;
7193446Smrj } else
7205804Scg149915 DRM_COPYFROM_WITH_RETURN(&emit,
7215804Scg149915 (drm_i915_irq_emit_t __user *) data, sizeof(emit));
7223446Smrj
72311260SMiao.Chen@Sun.COM spin_lock(&dev->struct_mutex);
7243446Smrj result = i915_emit_irq(dev);
72511260SMiao.Chen@Sun.COM spin_unlock(&dev->struct_mutex);
7263446Smrj
7273446Smrj if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
7283446Smrj DRM_ERROR("copy_to_user\n");
7295804Scg149915 return (EFAULT);
7303446Smrj }
7313446Smrj
7323446Smrj return 0;
7333446Smrj }
7343446Smrj
7353446Smrj /* Doesn't need the hardware lock.
7363446Smrj */
7373446Smrj /*ARGSUSED*/
i915_irq_wait(DRM_IOCTL_ARGS)7383446Smrj int i915_irq_wait(DRM_IOCTL_ARGS)
7393446Smrj {
7403446Smrj DRM_DEVICE;
7413446Smrj drm_i915_private_t *dev_priv = dev->dev_private;
7423446Smrj drm_i915_irq_wait_t irqwait;
7433446Smrj
7443446Smrj if (!dev_priv) {
7453446Smrj DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
7465804Scg149915 return (EINVAL);
7473446Smrj }
7483446Smrj
7495804Scg149915 DRM_COPYFROM_WITH_RETURN(&irqwait,
7505804Scg149915 (drm_i915_irq_wait_t __user *) data, sizeof(irqwait));
7513446Smrj
7523446Smrj return i915_wait_irq(dev, irqwait.irq_seq);
7533446Smrj }
7543446Smrj
igdng_enable_vblank(struct drm_device * dev,int pipe)755*11359SMiao.Chen@Sun.COM static void igdng_enable_vblank(struct drm_device *dev, int pipe)
756*11359SMiao.Chen@Sun.COM {
757*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
758*11359SMiao.Chen@Sun.COM u32 vblank;
759*11359SMiao.Chen@Sun.COM
760*11359SMiao.Chen@Sun.COM if (pipe == 0)
761*11359SMiao.Chen@Sun.COM vblank = DE_PIPEA_VBLANK;
762*11359SMiao.Chen@Sun.COM else
763*11359SMiao.Chen@Sun.COM vblank = DE_PIPEB_VBLANK;
764*11359SMiao.Chen@Sun.COM
765*11359SMiao.Chen@Sun.COM if ((dev_priv->de_irq_enable_reg & vblank) == 0) {
766*11359SMiao.Chen@Sun.COM igdng_enable_irq(dev_priv, vblank, 0);
767*11359SMiao.Chen@Sun.COM dev_priv->de_irq_enable_reg |= vblank;
768*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
769*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIER);
770*11359SMiao.Chen@Sun.COM }
771*11359SMiao.Chen@Sun.COM }
772*11359SMiao.Chen@Sun.COM
igdng_disable_vblank(struct drm_device * dev,int pipe)773*11359SMiao.Chen@Sun.COM static void igdng_disable_vblank(struct drm_device *dev, int pipe)
774*11359SMiao.Chen@Sun.COM {
775*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
776*11359SMiao.Chen@Sun.COM u32 vblank;
777*11359SMiao.Chen@Sun.COM
778*11359SMiao.Chen@Sun.COM if (pipe == 0)
779*11359SMiao.Chen@Sun.COM vblank = DE_PIPEA_VBLANK;
780*11359SMiao.Chen@Sun.COM else
781*11359SMiao.Chen@Sun.COM vblank = DE_PIPEB_VBLANK;
782*11359SMiao.Chen@Sun.COM
783*11359SMiao.Chen@Sun.COM if ((dev_priv->de_irq_enable_reg & vblank) != 0) {
784*11359SMiao.Chen@Sun.COM igdng_disable_irq(dev_priv, vblank, 0);
785*11359SMiao.Chen@Sun.COM dev_priv->de_irq_enable_reg &= ~vblank;
786*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
787*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIER);
788*11359SMiao.Chen@Sun.COM }
789*11359SMiao.Chen@Sun.COM }
790*11359SMiao.Chen@Sun.COM
i915_enable_vblank(struct drm_device * dev,int pipe)79111260SMiao.Chen@Sun.COM int i915_enable_vblank(struct drm_device *dev, int pipe)
7928832SMiao.Chen@Sun.COM {
7938832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
79411260SMiao.Chen@Sun.COM int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
79511260SMiao.Chen@Sun.COM u32 pipeconf;
7968832SMiao.Chen@Sun.COM
79711260SMiao.Chen@Sun.COM pipeconf = I915_READ(pipeconf_reg);
79811260SMiao.Chen@Sun.COM if (!(pipeconf & PIPEACONF_ENABLE))
79911260SMiao.Chen@Sun.COM return -EINVAL;
8008832SMiao.Chen@Sun.COM
80111260SMiao.Chen@Sun.COM spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
802*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev))
803*11359SMiao.Chen@Sun.COM igdng_enable_vblank(dev, pipe);
804*11359SMiao.Chen@Sun.COM else if (IS_I965G(dev))
80511260SMiao.Chen@Sun.COM i915_enable_pipestat(dev_priv, pipe,
80611260SMiao.Chen@Sun.COM PIPE_START_VBLANK_INTERRUPT_ENABLE);
80711260SMiao.Chen@Sun.COM else
80811260SMiao.Chen@Sun.COM i915_enable_pipestat(dev_priv, pipe,
80911260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_ENABLE);
81011260SMiao.Chen@Sun.COM spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
8118832SMiao.Chen@Sun.COM
8128832SMiao.Chen@Sun.COM return 0;
8138832SMiao.Chen@Sun.COM }
8148832SMiao.Chen@Sun.COM
i915_disable_vblank(struct drm_device * dev,int pipe)81511260SMiao.Chen@Sun.COM void i915_disable_vblank(struct drm_device *dev, int pipe)
8164194Szw161486 {
8174194Szw161486 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
8188832SMiao.Chen@Sun.COM
81911260SMiao.Chen@Sun.COM spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
820*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev))
821*11359SMiao.Chen@Sun.COM igdng_disable_vblank(dev, pipe);
822*11359SMiao.Chen@Sun.COM else
82311260SMiao.Chen@Sun.COM i915_disable_pipestat(dev_priv, pipe,
82411260SMiao.Chen@Sun.COM PIPE_VBLANK_INTERRUPT_ENABLE |
82511260SMiao.Chen@Sun.COM PIPE_START_VBLANK_INTERRUPT_ENABLE);
82611260SMiao.Chen@Sun.COM spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
8278832SMiao.Chen@Sun.COM }
8288832SMiao.Chen@Sun.COM
8298832SMiao.Chen@Sun.COM /* Set the vblank monitor pipe
8308832SMiao.Chen@Sun.COM */
8318832SMiao.Chen@Sun.COM /*ARGSUSED*/
i915_vblank_pipe_set(DRM_IOCTL_ARGS)8328832SMiao.Chen@Sun.COM int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
8338832SMiao.Chen@Sun.COM {
8348832SMiao.Chen@Sun.COM DRM_DEVICE;
8358832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = dev->dev_private;
8368832SMiao.Chen@Sun.COM
8378832SMiao.Chen@Sun.COM if (!dev_priv) {
8388832SMiao.Chen@Sun.COM DRM_ERROR("called with no initialization\n");
8398832SMiao.Chen@Sun.COM return (-EINVAL);
8408832SMiao.Chen@Sun.COM }
8418832SMiao.Chen@Sun.COM
8428832SMiao.Chen@Sun.COM return (0);
8438832SMiao.Chen@Sun.COM }
8448832SMiao.Chen@Sun.COM
8458832SMiao.Chen@Sun.COM /*ARGSUSED*/
i915_vblank_pipe_get(DRM_IOCTL_ARGS)8468832SMiao.Chen@Sun.COM int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
8478832SMiao.Chen@Sun.COM {
8488832SMiao.Chen@Sun.COM DRM_DEVICE;
8498832SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = dev->dev_private;
8508832SMiao.Chen@Sun.COM drm_i915_vblank_pipe_t pipe;
8518832SMiao.Chen@Sun.COM
8528832SMiao.Chen@Sun.COM if (!dev_priv) {
8538832SMiao.Chen@Sun.COM DRM_ERROR("called with no initialization\n");
8548832SMiao.Chen@Sun.COM return -EINVAL;
8558832SMiao.Chen@Sun.COM }
8568832SMiao.Chen@Sun.COM
8578832SMiao.Chen@Sun.COM DRM_COPYFROM_WITH_RETURN(&pipe, (drm_i915_vblank_pipe_t __user *)data, sizeof (pipe));
8588832SMiao.Chen@Sun.COM
8598832SMiao.Chen@Sun.COM pipe.pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
8608832SMiao.Chen@Sun.COM
8618832SMiao.Chen@Sun.COM return 0;
8628832SMiao.Chen@Sun.COM }
8638832SMiao.Chen@Sun.COM
8648832SMiao.Chen@Sun.COM /**
8658832SMiao.Chen@Sun.COM * Schedule buffer swap at given vertical blank.
8668832SMiao.Chen@Sun.COM */
8678832SMiao.Chen@Sun.COM /*ARGSUSED*/
i915_vblank_swap(DRM_IOCTL_ARGS)8688832SMiao.Chen@Sun.COM int i915_vblank_swap(DRM_IOCTL_ARGS)
8698832SMiao.Chen@Sun.COM {
87011260SMiao.Chen@Sun.COM /* The delayed swap mechanism was fundamentally racy, and has been
87111260SMiao.Chen@Sun.COM * removed. The model was that the client requested a delayed flip/swap
87211260SMiao.Chen@Sun.COM * from the kernel, then waited for vblank before continuing to perform
87311260SMiao.Chen@Sun.COM * rendering. The problem was that the kernel might wake the client
87411260SMiao.Chen@Sun.COM * up before it dispatched the vblank swap (since the lock has to be
87511260SMiao.Chen@Sun.COM * held while touching the ringbuffer), in which case the client would
87611260SMiao.Chen@Sun.COM * clear and start the next frame before the swap occurred, and
87711260SMiao.Chen@Sun.COM * flicker would occur in addition to likely missing the vblank.
87811260SMiao.Chen@Sun.COM *
87911260SMiao.Chen@Sun.COM * In the absence of this ioctl, userland falls back to a correct path
88011260SMiao.Chen@Sun.COM * of waiting for a vblank, then dispatching the swap on its own.
88111260SMiao.Chen@Sun.COM * Context switching to userland and back is plenty fast enough for
88211260SMiao.Chen@Sun.COM * meeting the requirements of vblank swapping.
88311260SMiao.Chen@Sun.COM */
88411260SMiao.Chen@Sun.COM return -EINVAL;
8858832SMiao.Chen@Sun.COM
8864194Szw161486 }
8874194Szw161486
8883446Smrj /* drm_dma.h hooks
8893446Smrj */
890*11359SMiao.Chen@Sun.COM
igdng_irq_preinstall(struct drm_device * dev)891*11359SMiao.Chen@Sun.COM static void igdng_irq_preinstall(struct drm_device *dev)
892*11359SMiao.Chen@Sun.COM {
893*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
894*11359SMiao.Chen@Sun.COM
895*11359SMiao.Chen@Sun.COM I915_WRITE(HWSTAM, 0xeffe);
896*11359SMiao.Chen@Sun.COM
897*11359SMiao.Chen@Sun.COM /* XXX hotplug from PCH */
898*11359SMiao.Chen@Sun.COM
899*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, 0xffffffff);
900*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, 0x0);
901*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIER);
902*11359SMiao.Chen@Sun.COM
903*11359SMiao.Chen@Sun.COM /* and GT */
904*11359SMiao.Chen@Sun.COM I915_WRITE(GTIMR, 0xffffffff);
905*11359SMiao.Chen@Sun.COM I915_WRITE(GTIER, 0x0);
906*11359SMiao.Chen@Sun.COM (void) I915_READ(GTIER);
907*11359SMiao.Chen@Sun.COM }
908*11359SMiao.Chen@Sun.COM
igdng_irq_postinstall(struct drm_device * dev)909*11359SMiao.Chen@Sun.COM static int igdng_irq_postinstall(struct drm_device *dev)
910*11359SMiao.Chen@Sun.COM {
911*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
912*11359SMiao.Chen@Sun.COM /* enable kind of interrupts always enabled */
913*11359SMiao.Chen@Sun.COM u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
914*11359SMiao.Chen@Sun.COM u32 render_mask = GT_USER_INTERRUPT;
915*11359SMiao.Chen@Sun.COM
916*11359SMiao.Chen@Sun.COM dev_priv->irq_mask_reg = ~display_mask;
917*11359SMiao.Chen@Sun.COM dev_priv->de_irq_enable_reg = display_mask;
918*11359SMiao.Chen@Sun.COM
919*11359SMiao.Chen@Sun.COM /* should always can generate irq */
920*11359SMiao.Chen@Sun.COM I915_WRITE(DEIIR, I915_READ(DEIIR));
921*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIIR);
922*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
923*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
924*11359SMiao.Chen@Sun.COM (void) I915_READ(DEIER);
925*11359SMiao.Chen@Sun.COM
926*11359SMiao.Chen@Sun.COM /* user interrupt should be enabled, but masked initial */
927*11359SMiao.Chen@Sun.COM dev_priv->gt_irq_mask_reg = 0xffffffff;
928*11359SMiao.Chen@Sun.COM dev_priv->gt_irq_enable_reg = render_mask;
929*11359SMiao.Chen@Sun.COM
930*11359SMiao.Chen@Sun.COM I915_WRITE(GTIIR, I915_READ(GTIIR));
931*11359SMiao.Chen@Sun.COM (void) I915_READ(GTIIR);
932*11359SMiao.Chen@Sun.COM I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
933*11359SMiao.Chen@Sun.COM I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
934*11359SMiao.Chen@Sun.COM (void) I915_READ(GTIER);
935*11359SMiao.Chen@Sun.COM
936*11359SMiao.Chen@Sun.COM return 0;
937*11359SMiao.Chen@Sun.COM }
938*11359SMiao.Chen@Sun.COM
igdng_irq_uninstall(struct drm_device * dev)939*11359SMiao.Chen@Sun.COM static void igdng_irq_uninstall(struct drm_device *dev)
940*11359SMiao.Chen@Sun.COM {
941*11359SMiao.Chen@Sun.COM drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
942*11359SMiao.Chen@Sun.COM I915_WRITE(HWSTAM, 0xffffffff);
943*11359SMiao.Chen@Sun.COM
944*11359SMiao.Chen@Sun.COM I915_WRITE(DEIMR, 0xffffffff);
945*11359SMiao.Chen@Sun.COM I915_WRITE(DEIER, 0x0);
946*11359SMiao.Chen@Sun.COM I915_WRITE(DEIIR, I915_READ(DEIIR));
947*11359SMiao.Chen@Sun.COM
948*11359SMiao.Chen@Sun.COM I915_WRITE(GTIMR, 0xffffffff);
949*11359SMiao.Chen@Sun.COM I915_WRITE(GTIER, 0x0);
950*11359SMiao.Chen@Sun.COM I915_WRITE(GTIIR, I915_READ(GTIIR));
951*11359SMiao.Chen@Sun.COM }
952*11359SMiao.Chen@Sun.COM
i915_driver_irq_preinstall(drm_device_t * dev)9538959SMiao.Chen@Sun.COM int i915_driver_irq_preinstall(drm_device_t * dev)
9543446Smrj {
9553446Smrj drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
9563446Smrj
9578959SMiao.Chen@Sun.COM if (!dev_priv->mmio_map)
9588959SMiao.Chen@Sun.COM return -EINVAL;
9598959SMiao.Chen@Sun.COM
960*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev)) {
961*11359SMiao.Chen@Sun.COM igdng_irq_preinstall(dev);
962*11359SMiao.Chen@Sun.COM return 0;
963*11359SMiao.Chen@Sun.COM }
964*11359SMiao.Chen@Sun.COM
96511260SMiao.Chen@Sun.COM I915_WRITE16(HWSTAM, 0xeffe);
96611260SMiao.Chen@Sun.COM I915_WRITE(PIPEASTAT, 0);
96711260SMiao.Chen@Sun.COM I915_WRITE(PIPEBSTAT, 0);
9688832SMiao.Chen@Sun.COM I915_WRITE(IMR, 0xffffffff);
96911260SMiao.Chen@Sun.COM I915_WRITE16(IER, 0x0);
97011260SMiao.Chen@Sun.COM (void) I915_READ(IER);
9718959SMiao.Chen@Sun.COM
9728959SMiao.Chen@Sun.COM return 0;
9733446Smrj }
9743446Smrj
i915_driver_irq_postinstall(drm_device_t * dev)9753446Smrj void i915_driver_irq_postinstall(drm_device_t * dev)
9763446Smrj {
97711260SMiao.Chen@Sun.COM int error_mask;
9783446Smrj drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
9793446Smrj
98011260SMiao.Chen@Sun.COM dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
98111260SMiao.Chen@Sun.COM
982*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev)) {
983*11359SMiao.Chen@Sun.COM (void) igdng_irq_postinstall(dev);
984*11359SMiao.Chen@Sun.COM DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
985*11359SMiao.Chen@Sun.COM return;
986*11359SMiao.Chen@Sun.COM }
987*11359SMiao.Chen@Sun.COM
98811260SMiao.Chen@Sun.COM /* Unmask the interrupts that we always want on. */
98911260SMiao.Chen@Sun.COM dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
99011260SMiao.Chen@Sun.COM
99111260SMiao.Chen@Sun.COM dev_priv->pipestat[0] = 0;
99211260SMiao.Chen@Sun.COM dev_priv->pipestat[1] = 0;
9934194Szw161486
99411260SMiao.Chen@Sun.COM /*
99511260SMiao.Chen@Sun.COM * Enable some error detection, note the instruction error mask
99611260SMiao.Chen@Sun.COM * bit is reserved, so we leave it masked.
99711260SMiao.Chen@Sun.COM */
99811260SMiao.Chen@Sun.COM if (IS_G4X(dev)) {
99911260SMiao.Chen@Sun.COM error_mask = ~(GM45_ERROR_PAGE_TABLE |
100011260SMiao.Chen@Sun.COM GM45_ERROR_MEM_PRIV |
100111260SMiao.Chen@Sun.COM GM45_ERROR_CP_PRIV |
100211260SMiao.Chen@Sun.COM I915_ERROR_MEMORY_REFRESH);
100311260SMiao.Chen@Sun.COM } else {
100411260SMiao.Chen@Sun.COM error_mask = ~(I915_ERROR_PAGE_TABLE |
100511260SMiao.Chen@Sun.COM I915_ERROR_MEMORY_REFRESH);
100611260SMiao.Chen@Sun.COM }
100711260SMiao.Chen@Sun.COM I915_WRITE(EMR, error_mask);
10084194Szw161486
100911260SMiao.Chen@Sun.COM /* Disable pipe interrupt enables, clear pending pipe status */
101011260SMiao.Chen@Sun.COM I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
101111260SMiao.Chen@Sun.COM I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
1012*11359SMiao.Chen@Sun.COM (void) I915_READ(PIPEASTAT);
1013*11359SMiao.Chen@Sun.COM (void) I915_READ(PIPEBSTAT);
101411260SMiao.Chen@Sun.COM /* Clear pending interrupt status */
101511260SMiao.Chen@Sun.COM I915_WRITE(IIR, I915_READ(IIR));
10165804Scg149915
1017*11359SMiao.Chen@Sun.COM (void) I915_READ(IIR);
101811260SMiao.Chen@Sun.COM I915_WRITE(IMR, dev_priv->irq_mask_reg);
101911260SMiao.Chen@Sun.COM I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
102011260SMiao.Chen@Sun.COM (void) I915_READ(IER);
10215804Scg149915
10228832SMiao.Chen@Sun.COM DRM_INIT_WAITQUEUE(&dev_priv->irq_queue, DRM_INTR_PRI(dev));
10234194Szw161486
10248832SMiao.Chen@Sun.COM return;
10253446Smrj }
10263446Smrj
i915_driver_irq_uninstall(drm_device_t * dev)10273446Smrj void i915_driver_irq_uninstall(drm_device_t * dev)
10283446Smrj {
10293446Smrj drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
103011260SMiao.Chen@Sun.COM if ((!dev_priv) || (dev->irq_enabled == 0))
10313446Smrj return;
10323446Smrj
10338832SMiao.Chen@Sun.COM dev_priv->vblank_pipe = 0;
10348832SMiao.Chen@Sun.COM
1035*11359SMiao.Chen@Sun.COM if (IS_IGDNG(dev)) {
1036*11359SMiao.Chen@Sun.COM igdng_irq_uninstall(dev);
1037*11359SMiao.Chen@Sun.COM DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
1038*11359SMiao.Chen@Sun.COM return;
1039*11359SMiao.Chen@Sun.COM }
1040*11359SMiao.Chen@Sun.COM
10418832SMiao.Chen@Sun.COM I915_WRITE(HWSTAM, 0xffffffff);
104211260SMiao.Chen@Sun.COM I915_WRITE(PIPEASTAT, 0);
104311260SMiao.Chen@Sun.COM I915_WRITE(PIPEBSTAT, 0);
10448832SMiao.Chen@Sun.COM I915_WRITE(IMR, 0xffffffff);
10458832SMiao.Chen@Sun.COM I915_WRITE(IER, 0x0);
10464194Szw161486
104711260SMiao.Chen@Sun.COM I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
104811260SMiao.Chen@Sun.COM I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
104911260SMiao.Chen@Sun.COM I915_WRITE(IIR, I915_READ(IIR));
10505804Scg149915
105111260SMiao.Chen@Sun.COM DRM_FINI_WAITQUEUE(&dev_priv->irq_queue);
10523446Smrj }
1053