radeon_irq.c revision 119098
1193323Sed/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-
2193323Sed *
3193323Sed * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
4193323Sed *
5193323Sed * The Weather Channel (TM) funded Tungsten Graphics to develop the
6193323Sed * initial release of the Radeon 8500 driver under the XFree86 license.
7193323Sed * This notice must be preserved.
8193323Sed *
9193323Sed * Permission is hereby granted, free of charge, to any person obtaining a
10193323Sed * copy of this software and associated documentation files (the "Software"),
11193323Sed * to deal in the Software without restriction, including without limitation
12193323Sed * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13193323Sed * and/or sell copies of the Software, and to permit persons to whom the
14193323Sed * Software is furnished to do so, subject to the following conditions:
15193323Sed *
16193323Sed * The above copyright notice and this permission notice (including the next
17193323Sed * paragraph) shall be included in all copies or substantial portions of the
18193323Sed * Software.
19193323Sed *
20193323Sed * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21193323Sed * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22193323Sed * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23193323Sed * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24193323Sed * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25193323Sed * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26193323Sed * DEALINGS IN THE SOFTWARE.
27193323Sed *
28193323Sed * Authors:
29193323Sed *    Keith Whitwell <keith@tungstengraphics.com>
30193323Sed *    Michel D�nzer <michel@daenzer.net>
31193323Sed *
32193323Sed * $FreeBSD: head/sys/dev/drm/radeon_irq.c 119098 2003-08-19 02:57:31Z anholt $
33193323Sed */
34193323Sed
35193323Sed#include "dev/drm/radeon.h"
36193323Sed#include "dev/drm/drmP.h"
37193323Sed#include "dev/drm/drm.h"
38193323Sed#include "dev/drm/radeon_drm.h"
39193323Sed#include "dev/drm/radeon_drv.h"
40193323Sed
41193323Sed/* Interrupts - Used for device synchronization and flushing in the
42193323Sed * following circumstances:
43193323Sed *
44193323Sed * - Exclusive FB access with hw idle:
45193323Sed *    - Wait for GUI Idle (?) interrupt, then do normal flush.
46193323Sed *
47193323Sed * - Frame throttling, NV_fence:
48193323Sed *    - Drop marker irq's into command stream ahead of time.
49193323Sed *    - Wait on irq's with lock *not held*
50193323Sed *    - Check each for termination condition
51193323Sed *
52193323Sed * - Internally in cp_getbuffer, etc:
53193323Sed *    - as above, but wait with lock held???
54193323Sed *
55193323Sed * NOTE: These functions are misleadingly named -- the irq's aren't
56193323Sed * tied to dma at all, this is just a hangover from dri prehistory.
57193323Sed */
58193323Sed
59193323Sedirqreturn_t DRM(dma_service)( DRM_IRQ_ARGS )
60193323Sed{
61193323Sed	drm_device_t *dev = (drm_device_t *) arg;
62193323Sed	drm_radeon_private_t *dev_priv =
63193323Sed	   (drm_radeon_private_t *)dev->dev_private;
64193323Sed   	u32 stat;
65193323Sed
66193323Sed	/* Only consider the bits we're interested in - others could be used
67193323Sed	 * outside the DRM
68193323Sed	 */
69193323Sed	stat = RADEON_READ(RADEON_GEN_INT_STATUS)
70193323Sed	     & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
71193323Sed	if (!stat)
72193323Sed		return IRQ_NONE;
73193323Sed
74193323Sed	/* SW interrupt */
75193323Sed	if (stat & RADEON_SW_INT_TEST) {
76193323Sed		DRM_WAKEUP( &dev_priv->swi_queue );
77193323Sed	}
78193323Sed
79193323Sed	/* VBLANK interrupt */
80193323Sed	if (stat & RADEON_CRTC_VBLANK_STAT) {
81193323Sed		atomic_inc(&dev->vbl_received);
82193323Sed		DRM_WAKEUP(&dev->vbl_queue);
83193323Sed		DRM(vbl_send_signals)( dev );
84193323Sed	}
85193323Sed
86193323Sed	/* Acknowledge interrupts we handle */
87193323Sed	RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
88193323Sed	return IRQ_HANDLED;
89193323Sed}
90193323Sed
91193323Sedstatic __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
92193323Sed{
93193323Sed	u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
94193323Sed		& (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
95193323Sed	if (tmp)
96193323Sed		RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
97193323Sed}
98193323Sed
99193323Sedint radeon_emit_irq(drm_device_t *dev)
100193323Sed{
101193323Sed	drm_radeon_private_t *dev_priv = dev->dev_private;
102193323Sed	unsigned int ret;
103193323Sed	RING_LOCALS;
104193323Sed
105193323Sed	atomic_inc(&dev_priv->swi_emitted);
106193323Sed	ret = atomic_read(&dev_priv->swi_emitted);
107193323Sed
108193323Sed	BEGIN_RING( 4 );
109193323Sed	OUT_RING_REG( RADEON_LAST_SWI_REG, ret );
110193323Sed	OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE );
111193323Sed	ADVANCE_RING();
112193323Sed 	COMMIT_RING();
113193323Sed
114193323Sed	return ret;
115193323Sed}
116193323Sed
117193323Sed
118193323Sedint radeon_wait_irq(drm_device_t *dev, int swi_nr)
119193323Sed{
120193323Sed  	drm_radeon_private_t *dev_priv =
121193323Sed	   (drm_radeon_private_t *)dev->dev_private;
122193323Sed	int ret = 0;
123193323Sed
124193323Sed 	if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
125193323Sed 		return 0;
126193323Sed
127193323Sed	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
128193323Sed
129193323Sed	/* This is a hack to work around mysterious freezes on certain
130193323Sed	 * systems:
131193323Sed	 */
132193323Sed	radeon_acknowledge_irqs( dev_priv );
133193323Sed
134193323Sed	DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ,
135193323Sed		     RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr );
136193323Sed
137193323Sed	return ret;
138193323Sed}
139193323Sed
140193323Sedint radeon_emit_and_wait_irq(drm_device_t *dev)
141193323Sed{
142193323Sed	return radeon_wait_irq( dev, radeon_emit_irq(dev) );
143193323Sed}
144193323Sed
145193323Sed
146193323Sedint DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
147193323Sed{
148193323Sed  	drm_radeon_private_t *dev_priv =
149193323Sed	   (drm_radeon_private_t *)dev->dev_private;
150193323Sed	unsigned int cur_vblank;
151193323Sed	int ret = 0;
152193323Sed
153193323Sed	if ( !dev_priv ) {
154193323Sed		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
155193323Sed		return DRM_ERR(EINVAL);
156193323Sed	}
157193323Sed
158193323Sed	radeon_acknowledge_irqs( dev_priv );
159193323Sed
160193323Sed	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
161193323Sed
162195340Sed	/* Assume that the user has missed the current sequence number
163193323Sed	 * by about a day rather than she wants to wait for years
164193323Sed	 * using vertical blanks...
165193323Sed	 */
166193323Sed	DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ,
167193323Sed		     ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
168193323Sed			 - *sequence ) <= (1<<23) ) );
169193323Sed
170193323Sed	*sequence = cur_vblank;
171193323Sed
172193323Sed	return ret;
173193323Sed}
174193323Sed
175193323Sed
176193323Sed/* Needs the lock as it touches the ring.
177193323Sed */
178193323Sedint radeon_irq_emit( DRM_IOCTL_ARGS )
179193323Sed{
180193323Sed	DRM_DEVICE;
181193323Sed	drm_radeon_private_t *dev_priv = dev->dev_private;
182193323Sed	drm_radeon_irq_emit_t emit;
183193323Sed	int result;
184193323Sed
185193323Sed	LOCK_TEST_WITH_RETURN( dev, filp );
186193323Sed
187193323Sed	if ( !dev_priv ) {
188193323Sed		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
189193323Sed		return DRM_ERR(EINVAL);
190193323Sed	}
191193323Sed
192193323Sed	DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data,
193193323Sed				  sizeof(emit) );
194193323Sed
195193323Sed	result = radeon_emit_irq( dev );
196193323Sed
197193323Sed	if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) {
198193323Sed		DRM_ERROR( "copy_to_user\n" );
199193323Sed		return DRM_ERR(EFAULT);
200193323Sed	}
201193323Sed
202193323Sed	return 0;
203193323Sed}
204193323Sed
205193323Sed
206193323Sed/* Doesn't need the hardware lock.
207193323Sed */
208193323Sedint radeon_irq_wait( DRM_IOCTL_ARGS )
209193323Sed{
210193323Sed	DRM_DEVICE;
211193323Sed	drm_radeon_private_t *dev_priv = dev->dev_private;
212193323Sed	drm_radeon_irq_wait_t irqwait;
213193323Sed
214193323Sed	if ( !dev_priv ) {
215193323Sed		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
216193323Sed		return DRM_ERR(EINVAL);
217193323Sed	}
218193323Sed
219193323Sed	DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data,
220193323Sed				  sizeof(irqwait) );
221193323Sed
222193323Sed	return radeon_wait_irq( dev, irqwait.irq_seq );
223193323Sed}
224193323Sed
225193323Sed
226193323Sed/* drm_dma.h hooks
227193323Sed*/
228193323Sedvoid DRM(driver_irq_preinstall)( drm_device_t *dev ) {
229193323Sed	drm_radeon_private_t *dev_priv =
230193323Sed		(drm_radeon_private_t *)dev->dev_private;
231193323Sed
232193323Sed 	/* Disable *all* interrupts */
233193323Sed      	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
234193323Sed
235193323Sed	/* Clear bits if they're already high */
236193323Sed	radeon_acknowledge_irqs( dev_priv );
237193323Sed}
238193323Sed
239193323Sedvoid DRM(driver_irq_postinstall)( drm_device_t *dev ) {
240193323Sed	drm_radeon_private_t *dev_priv =
241193323Sed		(drm_radeon_private_t *)dev->dev_private;
242193323Sed
243193323Sed   	atomic_set(&dev_priv->swi_emitted, 0);
244193323Sed	DRM_INIT_WAITQUEUE( &dev_priv->swi_queue );
245193323Sed
246193323Sed	/* Turn on SW and VBL ints */
247193323Sed   	RADEON_WRITE( RADEON_GEN_INT_CNTL,
248193323Sed		      RADEON_CRTC_VBLANK_MASK |
249193323Sed		      RADEON_SW_INT_ENABLE );
250193323Sed}
251193323Sed
252193323Sedvoid DRM(driver_irq_uninstall)( drm_device_t *dev ) {
253193323Sed	drm_radeon_private_t *dev_priv =
254193323Sed		(drm_radeon_private_t *)dev->dev_private;
255193323Sed	if (!dev_priv)
256193323Sed		return;
257193323Sed
258193323Sed	/* Disable *all* interrupts */
259193323Sed	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
260193323Sed}
261193323Sed