xref: /titanic_50/usr/src/uts/intel/io/drm/i915_irq.c (revision 532877c46d04a2d0b254f9b5797720078adcea07)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /* BEGIN CSTYLED */
7 
8 /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
9  */
10 /**************************************************************************
11  *
12  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
13  * All Rights Reserved.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the
17  * "Software"), to deal in the Software without restriction, including
18  * without limitation the rights to use, copy, modify, merge, publish,
19  * distribute, sub license, and/or sell copies of the Software, and to
20  * permit persons to whom the Software is furnished to do so, subject to
21  * the following conditions:
22  *
23  * The above copyright notice and this permission notice (including the
24  * next paragraph) shall be included in all copies or substantial portions
25  * of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
30  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
31  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
32  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
33  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34  *
35  **************************************************************************/
36 
37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
38 
39 #include "drmP.h"
40 #include "drm.h"
41 #include "i915_drm.h"
42 #include "i915_drv.h"
43 
44 #define USER_INT_FLAG 0x2
45 #define MAX_NOPID ((u32)~0)
46 #define READ_BREADCRUMB(dev_priv)  (((u32*)(dev_priv->hw_status_page))[5])
47 
48 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
49 {
50 	drm_device_t *dev = (drm_device_t *) arg;
51 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
52 	u16 temp;
53 
54         temp = I915_READ16(I915REG_INT_IDENTITY_R);
55         temp &= USER_INT_FLAG;
56 
57 	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
58 
59         if (temp == 0) {
60                 return (IRQ_NONE);
61         }
62         I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
63 	DRM_WAKEUP(&dev_priv->irq_queue);
64 
65         return IRQ_HANDLED;
66 }
67 
68 static int i915_emit_irq(drm_device_t * dev)
69 {
70 	drm_i915_private_t *dev_priv = dev->dev_private;
71 	u32 ret;
72 	RING_LOCALS;
73 
74 	i915_kernel_lost_context(dev);
75 
76 	DRM_DEBUG("%s\n", __FUNCTION__);
77 
78 	ret = dev_priv->counter;
79 
80 	/*NOSTRICT*/
81 	BEGIN_LP_RING(2);
82 	OUT_RING(0);
83 	OUT_RING(GFX_OP_USER_INTERRUPT);
84 	ADVANCE_LP_RING();
85 	/*LINT*/
86 
87 	return ret;
88 }
89 
90 static int i915_wait_irq(drm_device_t * dev, int irq_nr)
91 {
92 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
93 	int ret = 0;
94 
95 	DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
96 		  READ_BREADCRUMB(dev_priv));
97 
98 	if (READ_BREADCRUMB(dev_priv) >= irq_nr)
99 		return 0;
100 
101 	dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
102 
103 	DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
104 		    READ_BREADCRUMB(dev_priv) >= irq_nr);
105 
106 	if (ret == -EBUSY) {
107 		DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
108 			  __FUNCTION__,
109 			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
110 	}
111 
112 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
113 	return ret;
114 }
115 
116 /* Needs the lock as it touches the ring.
117  */
118 /*ARGSUSED*/
119 int i915_irq_emit(DRM_IOCTL_ARGS)
120 {
121 	DRM_DEVICE;
122 	drm_i915_private_t *dev_priv = dev->dev_private;
123 	drm_i915_irq_emit_t emit;
124 	int result;
125 
126 	LOCK_TEST_WITH_RETURN(dev, filp);
127 
128 	if (!dev_priv) {
129 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
130 		return DRM_ERR(EINVAL);
131 	}
132 
133 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
134 		drm_i915_irq_emit32_t irq_emit32;
135 
136 		DRM_COPY_FROM_USER_IOCTL(irq_emit32,
137 			(drm_i915_irq_emit32_t __user *) data,
138 			sizeof (drm_i915_irq_emit32_t));
139 		emit.irq_seq = (int __user *)(uintptr_t)irq_emit32.irq_seq;
140 	} else
141 		DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
142 			sizeof(emit));
143 
144 	result = i915_emit_irq(dev);
145 
146 	if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
147 		DRM_ERROR("copy_to_user\n");
148 		return DRM_ERR(EFAULT);
149 	}
150 
151 	return 0;
152 }
153 
154 /* Doesn't need the hardware lock.
155  */
156 /*ARGSUSED*/
157 int i915_irq_wait(DRM_IOCTL_ARGS)
158 {
159 	DRM_DEVICE;
160 	drm_i915_private_t *dev_priv = dev->dev_private;
161 	drm_i915_irq_wait_t irqwait;
162 
163 	if (!dev_priv) {
164 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
165 		return DRM_ERR(EINVAL);
166 	}
167 
168 	DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
169 				 sizeof(irqwait));
170 
171 	return i915_wait_irq(dev, irqwait.irq_seq);
172 }
173 
174 /* drm_dma.h hooks
175 */
176 void i915_driver_irq_preinstall(drm_device_t * dev)
177 {
178 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
179 
180 	I915_WRITE16(I915REG_HWSTAM, 0xfffe);
181 	I915_WRITE16(I915REG_INT_MASK_R, 0x0);
182 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
183 }
184 
185 void i915_driver_irq_postinstall(drm_device_t * dev)
186 {
187 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
188 
189 	I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG);
190 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
191 }
192 
193 void i915_driver_irq_uninstall(drm_device_t * dev)
194 {
195 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
196 	if (!dev_priv)
197 		return;
198 
199 	I915_WRITE16(I915REG_HWSTAM, 0xffff);
200 	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
201 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
202 #if defined(__SOLARIS__) || defined(sun)
203         cv_destroy(&dev_priv->irq_queue);
204 #endif
205 }
206