Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / drm / radeon / radeon_irq.c
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  * $FreeBSD: src/sys/dev/drm/radeon_irq.c,v 1.2.2.1 2003/04/26 07:05:29 anholt Exp $
33  */
34
35 #include "dev/drm/radeon.h"
36 #include "dev/drm/drmP.h"
37 #include "dev/drm/drm.h"
38 #include "dev/drm/radeon_drm.h"
39 #include "dev/drm/radeon_drv.h"
40
41 /* Interrupts - Used for device synchronization and flushing in the
42  * following circumstances:
43  *
44  * - Exclusive FB access with hw idle:
45  *    - Wait for GUI Idle (?) interrupt, then do normal flush.
46  *
47  * - Frame throttling, NV_fence:
48  *    - Drop marker irq's into command stream ahead of time.
49  *    - Wait on irq's with lock *not held*
50  *    - Check each for termination condition
51  *
52  * - Internally in cp_getbuffer, etc:
53  *    - as above, but wait with lock held???
54  *
55  * NOTE: These functions are misleadingly named -- the irq's aren't
56  * tied to dma at all, this is just a hangover from dri prehistory.
57  */
58
59 void DRM(dma_service)( DRM_IRQ_ARGS )
60 {
61         drm_device_t *dev = (drm_device_t *) arg;
62         drm_radeon_private_t *dev_priv = 
63            (drm_radeon_private_t *)dev->dev_private;
64         u32 stat;
65
66         /* Only consider the bits we're interested in - others could be used
67          * outside the DRM
68          */
69         stat = RADEON_READ(RADEON_GEN_INT_STATUS)
70              & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
71         if (!stat)
72                 return;
73
74         /* SW interrupt */
75         if (stat & RADEON_SW_INT_TEST) {
76                 DRM_WAKEUP( &dev_priv->swi_queue );
77         }
78
79         /* VBLANK interrupt */
80         if (stat & RADEON_CRTC_VBLANK_STAT) {
81                 atomic_inc(&dev->vbl_received);
82                 DRM_WAKEUP(&dev->vbl_queue);
83                 DRM(vbl_send_signals)( dev );
84         }
85
86         /* Acknowledge interrupts we handle */
87         RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
88 }
89
90 static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
91 {
92         u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
93                 & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
94         if (tmp)
95                 RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
96 }
97
98 int radeon_emit_irq(drm_device_t *dev)
99 {
100         drm_radeon_private_t *dev_priv = dev->dev_private;
101         unsigned int ret;
102         RING_LOCALS;
103
104         atomic_inc(&dev_priv->swi_emitted);
105         ret = atomic_read(&dev_priv->swi_emitted);
106
107         BEGIN_RING( 4 );
108         OUT_RING_REG( RADEON_LAST_SWI_REG, ret );
109         OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE );
110         ADVANCE_RING(); 
111         COMMIT_RING();
112
113         return ret;
114 }
115
116
117 int radeon_wait_irq(drm_device_t *dev, int swi_nr)
118 {
119         drm_radeon_private_t *dev_priv = 
120            (drm_radeon_private_t *)dev->dev_private;
121         int ret = 0;
122
123         if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)  
124                 return 0; 
125
126         dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
127
128         /* This is a hack to work around mysterious freezes on certain
129          * systems:
130          */ 
131         radeon_acknowledge_irqs( dev_priv );
132
133         DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, 
134                      RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr );
135
136         return ret;
137 }
138
139 int radeon_emit_and_wait_irq(drm_device_t *dev)
140 {
141         return radeon_wait_irq( dev, radeon_emit_irq(dev) );
142 }
143
144
145 int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
146 {
147         drm_radeon_private_t *dev_priv = 
148            (drm_radeon_private_t *)dev->dev_private;
149         unsigned int cur_vblank;
150         int ret = 0;
151
152         if ( !dev_priv ) {
153                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
154                 return DRM_ERR(EINVAL);
155         }
156
157         radeon_acknowledge_irqs( dev_priv );
158
159         dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
160
161         /* Assume that the user has missed the current sequence number
162          * by about a day rather than she wants to wait for years
163          * using vertical blanks... 
164          */
165         DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, 
166                      ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
167                          - *sequence ) <= (1<<23) ) );
168
169         *sequence = cur_vblank;
170
171         return ret;
172 }
173
174
175 /* Needs the lock as it touches the ring.
176  */
177 int radeon_irq_emit( DRM_IOCTL_ARGS )
178 {
179         DRM_DEVICE;
180         drm_radeon_private_t *dev_priv = dev->dev_private;
181         drm_radeon_irq_emit_t emit;
182         int result;
183
184         LOCK_TEST_WITH_RETURN( dev, filp );
185
186         if ( !dev_priv ) {
187                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
188                 return DRM_ERR(EINVAL);
189         }
190
191         DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data,
192                                   sizeof(emit) );
193
194         result = radeon_emit_irq( dev );
195
196         if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) {
197                 DRM_ERROR( "copy_to_user\n" );
198                 return DRM_ERR(EFAULT);
199         }
200
201         return 0;
202 }
203
204
205 /* Doesn't need the hardware lock.
206  */
207 int radeon_irq_wait( DRM_IOCTL_ARGS )
208 {
209         DRM_DEVICE;
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 DRM_ERR(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 */
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
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         DRM_INIT_WAITQUEUE( &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
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 }