1 /* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-
2  *
3  * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
4  *
5  * The Weather Channel (TM) funded Tungsten Graphics to develop the
6  * initial release of the Radeon 8500 driver under the XFree86 license.
7  * This notice must be preserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *
28  * Authors:
29  *    Keith Whitwell <keith@tungstengraphics.com>
30  *    Michel D�nzer <michel@daenzer.net>
31  */
32 
33 #include "radeon.h"
34 #include "drmP.h"
35 #include "drm.h"
36 #include "radeon_drm.h"
37 #include "radeon_drv.h"
38 #include "drm_os_linux.h"
39 
40 /* Interrupts - Used for device synchronization and flushing in the
41  * following circumstances:
42  *
43  * - Exclusive FB access with hw idle:
44  *    - Wait for GUI Idle (?) interrupt, then do normal flush.
45  *
46  * - Frame throttling, NV_fence:
47  *    - Drop marker irq's into command stream ahead of time.
48  *    - Wait on irq's with lock *not held*
49  *    - Check each for termination condition
50  *
51  * - Internally in cp_getbuffer, etc:
52  *    - as above, but wait with lock held???
53  *
54  * NOTE: These functions are misleadingly named -- the irq's aren't
55  * tied to dma at all, this is just a hangover from dri prehistory.
56  */
57 
DRM(dma_service)58 void DRM(dma_service)(int irq, void *arg, struct pt_regs *reg)
59 {
60 	drm_device_t *dev = (drm_device_t *) arg;
61 	drm_radeon_private_t *dev_priv =
62 	   (drm_radeon_private_t *)dev->dev_private;
63    	u32 stat;
64 
65 	stat = RADEON_READ(RADEON_GEN_INT_STATUS)
66 		& (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
67 	if (!stat)
68 		return;
69 
70 	/* SW interrupt */
71 	if (stat & RADEON_SW_INT_TEST) {
72 		wake_up_interruptible( &dev_priv->swi_queue );
73 	}
74 
75 	/* VBLANK interrupt */
76 	if (stat & RADEON_CRTC_VBLANK_STAT) {
77 		atomic_inc(&dev->vbl_received);
78 		wake_up_interruptible(&dev->vbl_queue);
79 		DRM(vbl_send_signals)(dev);
80 	}
81 
82 	/* Acknowledge all the bits in GEN_INT_STATUS -- seem to get
83 	 * more than we asked for...
84 	 */
85 	RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
86 }
87 
radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)88 static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
89 {
90 	u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
91 		& (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
92 	if (tmp)
93 		RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
94 }
95 
radeon_emit_irq(drm_device_t * dev)96 int radeon_emit_irq(drm_device_t *dev)
97 {
98 	drm_radeon_private_t *dev_priv = dev->dev_private;
99 	unsigned int ret;
100 	RING_LOCALS;
101 
102 	atomic_inc(&dev_priv->swi_emitted);
103 	ret = atomic_read(&dev_priv->swi_emitted);
104 
105 	BEGIN_RING( 4 );
106 	OUT_RING_REG( RADEON_LAST_SWI_REG, ret );
107 	OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE );
108 	ADVANCE_RING();
109  	COMMIT_RING();
110 
111 	return ret;
112 }
113 
114 
radeon_wait_irq(drm_device_t * dev,int swi_nr)115 int radeon_wait_irq(drm_device_t *dev, int swi_nr)
116 {
117   	drm_radeon_private_t *dev_priv =
118 	   (drm_radeon_private_t *)dev->dev_private;
119 	int ret = 0;
120 
121  	if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
122  		return 0;
123 
124 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
125 
126 	/* This is a hack to work around mysterious freezes on certain
127 	 * systems:
128 	 */
129 	radeon_acknowledge_irqs( dev_priv );
130 
131 	DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * HZ,
132 		     RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr );
133 
134 	return ret;
135 }
136 
radeon_emit_and_wait_irq(drm_device_t * dev)137 int radeon_emit_and_wait_irq(drm_device_t *dev)
138 {
139 	return radeon_wait_irq( dev, radeon_emit_irq(dev) );
140 }
141 
142 
DRM(vblank_wait)143 int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
144 {
145   	drm_radeon_private_t *dev_priv =
146 	   (drm_radeon_private_t *)dev->dev_private;
147 	unsigned int cur_vblank;
148 	int ret = 0;
149 
150 	if ( !dev_priv ) {
151 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
152 		return -EINVAL;
153 	}
154 
155 	radeon_acknowledge_irqs( dev_priv );
156 
157 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
158 
159 	/* Assume that the user has missed the current sequence number
160 	 * by about a day rather than she wants to wait for years
161 	 * using vertical blanks...
162 	 */
163 	DRM_WAIT_ON( ret, dev->vbl_queue, 3*HZ,
164 		     ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
165 			 - *sequence ) <= (1<<23) ) );
166 
167 	*sequence = cur_vblank;
168 
169 	return ret;
170 }
171 
172 
173 /* Needs the lock as it touches the ring.
174  */
radeon_irq_emit(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long data)175 int radeon_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
176 {
177 	drm_file_t	*priv	= filp->private_data;
178 	drm_device_t	*dev	= priv->dev;
179 	drm_radeon_private_t *dev_priv = dev->dev_private;
180 	drm_radeon_irq_emit_t emit;
181 	int result;
182 
183 	LOCK_TEST_WITH_RETURN( dev );
184 
185 	if ( !dev_priv ) {
186 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
187 		return -EINVAL;
188 	}
189 
190 	DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data,
191 				  sizeof(emit) );
192 
193 	result = radeon_emit_irq( dev );
194 
195 	if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) {
196 		DRM_ERROR( "copy_to_user\n" );
197 		return -EFAULT;
198 	}
199 
200 	return 0;
201 }
202 
203 
204 /* Doesn't need the hardware lock.
205  */
radeon_irq_wait(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long data)206 int radeon_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
207 {
208         drm_file_t      *priv   = filp->private_data;
209 	drm_device_t    *dev    = priv->dev;
210 	drm_radeon_private_t *dev_priv = dev->dev_private;
211 	drm_radeon_irq_wait_t irqwait;
212 
213 	if ( !dev_priv ) {
214 		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
215 		return -EINVAL;
216 	}
217 
218 	DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data,
219 				  sizeof(irqwait) );
220 
221 	return radeon_wait_irq( dev, irqwait.irq_seq );
222 }
223 
224 
225 /* drm_dma.h hooks
226 */
DRM(driver_irq_preinstall)227 void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
228 	drm_radeon_private_t *dev_priv =
229 		(drm_radeon_private_t *)dev->dev_private;
230 
231  	/* Disable *all* interrupts */
232       	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
233 
234 	/* Clear bits if they're already high */
235 	radeon_acknowledge_irqs( dev_priv );
236 }
237 
DRM(driver_irq_postinstall)238 void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
239 	drm_radeon_private_t *dev_priv =
240 		(drm_radeon_private_t *)dev->dev_private;
241 
242    	atomic_set(&dev_priv->swi_emitted, 0);
243 	init_waitqueue_head( &dev_priv->swi_queue );
244 
245 	/* Turn on SW and VBL ints */
246    	RADEON_WRITE( RADEON_GEN_INT_CNTL,
247 		      RADEON_CRTC_VBLANK_MASK |
248 		      RADEON_SW_INT_ENABLE );
249 }
250 
DRM(driver_irq_uninstall)251 void DRM(driver_irq_uninstall)( drm_device_t *dev ) {
252 	drm_radeon_private_t *dev_priv =
253 		(drm_radeon_private_t *)dev->dev_private;
254 	if ( dev_priv ) {
255 		/* Disable *all* interrupts */
256 		RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
257 	}
258 }
259