]>
Commit | Line | Data |
---|---|---|
94bb598e DA |
1 | /* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */ |
2 | /* | |
1da177e4 | 3 | * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. |
b5e89ed5 | 4 | * |
1da177e4 LT |
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�zer <michel@daenzer.net> | |
31 | */ | |
32 | ||
33 | #include "drmP.h" | |
34 | #include "drm.h" | |
35 | #include "radeon_drm.h" | |
36 | #include "radeon_drv.h" | |
37 | ||
b5e89ed5 DA |
38 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, |
39 | u32 mask) | |
6921e331 DA |
40 | { |
41 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; | |
42 | if (irqs) | |
43 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | |
44 | return irqs; | |
45 | } | |
46 | ||
1da177e4 LT |
47 | /* Interrupts - Used for device synchronization and flushing in the |
48 | * following circumstances: | |
49 | * | |
50 | * - Exclusive FB access with hw idle: | |
51 | * - Wait for GUI Idle (?) interrupt, then do normal flush. | |
52 | * | |
53 | * - Frame throttling, NV_fence: | |
54 | * - Drop marker irq's into command stream ahead of time. | |
55 | * - Wait on irq's with lock *not held* | |
56 | * - Check each for termination condition | |
57 | * | |
58 | * - Internally in cp_getbuffer, etc: | |
59 | * - as above, but wait with lock held??? | |
60 | * | |
61 | * NOTE: These functions are misleadingly named -- the irq's aren't | |
62 | * tied to dma at all, this is just a hangover from dri prehistory. | |
63 | */ | |
64 | ||
b5e89ed5 | 65 | irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) |
1da177e4 LT |
66 | { |
67 | drm_device_t *dev = (drm_device_t *) arg; | |
b5e89ed5 DA |
68 | drm_radeon_private_t *dev_priv = |
69 | (drm_radeon_private_t *) dev->dev_private; | |
70 | u32 stat; | |
1da177e4 LT |
71 | |
72 | /* Only consider the bits we're interested in - others could be used | |
73 | * outside the DRM | |
74 | */ | |
b5e89ed5 | 75 | stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | |
ddbee333 DA |
76 | RADEON_CRTC_VBLANK_STAT | |
77 | RADEON_CRTC2_VBLANK_STAT)); | |
1da177e4 LT |
78 | if (!stat) |
79 | return IRQ_NONE; | |
80 | ||
ddbee333 DA |
81 | stat &= dev_priv->irq_enable_reg; |
82 | ||
1da177e4 LT |
83 | /* SW interrupt */ |
84 | if (stat & RADEON_SW_INT_TEST) { | |
b5e89ed5 | 85 | DRM_WAKEUP(&dev_priv->swi_queue); |
1da177e4 LT |
86 | } |
87 | ||
88 | /* VBLANK interrupt */ | |
ddbee333 DA |
89 | if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { |
90 | int vblank_crtc = dev_priv->vblank_crtc; | |
91 | ||
92 | if ((vblank_crtc & | |
93 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) == | |
94 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | |
95 | if (stat & RADEON_CRTC_VBLANK_STAT) | |
96 | atomic_inc(&dev->vbl_received); | |
97 | if (stat & RADEON_CRTC2_VBLANK_STAT) | |
98 | atomic_inc(&dev->vbl_received2); | |
99 | } else if (((stat & RADEON_CRTC_VBLANK_STAT) && | |
100 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) || | |
101 | ((stat & RADEON_CRTC2_VBLANK_STAT) && | |
102 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC2))) | |
103 | atomic_inc(&dev->vbl_received); | |
104 | ||
1da177e4 | 105 | DRM_WAKEUP(&dev->vbl_queue); |
b5e89ed5 | 106 | drm_vbl_send_signals(dev); |
1da177e4 LT |
107 | } |
108 | ||
1da177e4 LT |
109 | return IRQ_HANDLED; |
110 | } | |
111 | ||
b5e89ed5 | 112 | static int radeon_emit_irq(drm_device_t * dev) |
1da177e4 LT |
113 | { |
114 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
115 | unsigned int ret; | |
116 | RING_LOCALS; | |
117 | ||
118 | atomic_inc(&dev_priv->swi_emitted); | |
119 | ret = atomic_read(&dev_priv->swi_emitted); | |
120 | ||
b5e89ed5 DA |
121 | BEGIN_RING(4); |
122 | OUT_RING_REG(RADEON_LAST_SWI_REG, ret); | |
123 | OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); | |
124 | ADVANCE_RING(); | |
125 | COMMIT_RING(); | |
1da177e4 LT |
126 | |
127 | return ret; | |
128 | } | |
129 | ||
b5e89ed5 | 130 | static int radeon_wait_irq(drm_device_t * dev, int swi_nr) |
1da177e4 | 131 | { |
b5e89ed5 DA |
132 | drm_radeon_private_t *dev_priv = |
133 | (drm_radeon_private_t *) dev->dev_private; | |
1da177e4 LT |
134 | int ret = 0; |
135 | ||
b5e89ed5 DA |
136 | if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) |
137 | return 0; | |
1da177e4 LT |
138 | |
139 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | |
140 | ||
b5e89ed5 DA |
141 | DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, |
142 | RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); | |
1da177e4 LT |
143 | |
144 | return ret; | |
145 | } | |
146 | ||
ddbee333 DA |
147 | int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned int *sequence, |
148 | int crtc) | |
1da177e4 | 149 | { |
b5e89ed5 DA |
150 | drm_radeon_private_t *dev_priv = |
151 | (drm_radeon_private_t *) dev->dev_private; | |
1da177e4 LT |
152 | unsigned int cur_vblank; |
153 | int ret = 0; | |
ddbee333 DA |
154 | int ack = 0; |
155 | atomic_t *counter; | |
b5e89ed5 DA |
156 | if (!dev_priv) { |
157 | DRM_ERROR("%s called with no initialization\n", __FUNCTION__); | |
1da177e4 LT |
158 | return DRM_ERR(EINVAL); |
159 | } | |
160 | ||
ddbee333 DA |
161 | if (crtc == DRM_RADEON_VBLANK_CRTC1) { |
162 | counter = &dev->vbl_received; | |
163 | ack |= RADEON_CRTC_VBLANK_STAT; | |
164 | } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { | |
165 | counter = &dev->vbl_received2; | |
166 | ack |= RADEON_CRTC2_VBLANK_STAT; | |
167 | } else | |
168 | return DRM_ERR(EINVAL); | |
169 | ||
170 | radeon_acknowledge_irqs(dev_priv, ack); | |
1da177e4 LT |
171 | |
172 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | |
173 | ||
174 | /* Assume that the user has missed the current sequence number | |
175 | * by about a day rather than she wants to wait for years | |
b5e89ed5 | 176 | * using vertical blanks... |
1da177e4 | 177 | */ |
b5e89ed5 | 178 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, |
ddbee333 | 179 | (((cur_vblank = atomic_read(counter)) |
b5e89ed5 | 180 | - *sequence) <= (1 << 23))); |
1da177e4 LT |
181 | |
182 | *sequence = cur_vblank; | |
183 | ||
184 | return ret; | |
185 | } | |
186 | ||
ddbee333 DA |
187 | int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) |
188 | { | |
189 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1); | |
190 | } | |
191 | ||
192 | int radeon_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence) | |
193 | { | |
194 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2); | |
195 | } | |
196 | ||
1da177e4 LT |
197 | /* Needs the lock as it touches the ring. |
198 | */ | |
b5e89ed5 | 199 | int radeon_irq_emit(DRM_IOCTL_ARGS) |
1da177e4 LT |
200 | { |
201 | DRM_DEVICE; | |
202 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
203 | drm_radeon_irq_emit_t emit; | |
204 | int result; | |
205 | ||
b5e89ed5 | 206 | LOCK_TEST_WITH_RETURN(dev, filp); |
1da177e4 | 207 | |
b5e89ed5 DA |
208 | if (!dev_priv) { |
209 | DRM_ERROR("%s called with no initialization\n", __FUNCTION__); | |
1da177e4 LT |
210 | return DRM_ERR(EINVAL); |
211 | } | |
212 | ||
b5e89ed5 DA |
213 | DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data, |
214 | sizeof(emit)); | |
1da177e4 | 215 | |
b5e89ed5 | 216 | result = radeon_emit_irq(dev); |
1da177e4 | 217 | |
b5e89ed5 DA |
218 | if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { |
219 | DRM_ERROR("copy_to_user\n"); | |
1da177e4 LT |
220 | return DRM_ERR(EFAULT); |
221 | } | |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
1da177e4 LT |
226 | /* Doesn't need the hardware lock. |
227 | */ | |
b5e89ed5 | 228 | int radeon_irq_wait(DRM_IOCTL_ARGS) |
1da177e4 LT |
229 | { |
230 | DRM_DEVICE; | |
231 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
232 | drm_radeon_irq_wait_t irqwait; | |
233 | ||
b5e89ed5 DA |
234 | if (!dev_priv) { |
235 | DRM_ERROR("%s called with no initialization\n", __FUNCTION__); | |
1da177e4 LT |
236 | return DRM_ERR(EINVAL); |
237 | } | |
238 | ||
b5e89ed5 DA |
239 | DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data, |
240 | sizeof(irqwait)); | |
1da177e4 | 241 | |
b5e89ed5 | 242 | return radeon_wait_irq(dev, irqwait.irq_seq); |
1da177e4 LT |
243 | } |
244 | ||
ddbee333 DA |
245 | static void radeon_enable_interrupt(drm_device_t *dev) |
246 | { | |
247 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
248 | ||
249 | dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE; | |
250 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1) | |
251 | dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK; | |
252 | ||
253 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2) | |
254 | dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK; | |
255 | ||
256 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | |
257 | dev_priv->irq_enabled = 1; | |
258 | } | |
259 | ||
1da177e4 LT |
260 | /* drm_dma.h hooks |
261 | */ | |
b5e89ed5 DA |
262 | void radeon_driver_irq_preinstall(drm_device_t * dev) |
263 | { | |
1da177e4 | 264 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 265 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 | 266 | |
b5e89ed5 DA |
267 | /* Disable *all* interrupts */ |
268 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | |
1da177e4 LT |
269 | |
270 | /* Clear bits if they're already high */ | |
6921e331 | 271 | radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | |
ddbee333 DA |
272 | RADEON_CRTC_VBLANK_STAT | |
273 | RADEON_CRTC2_VBLANK_STAT)); | |
1da177e4 LT |
274 | } |
275 | ||
b5e89ed5 DA |
276 | void radeon_driver_irq_postinstall(drm_device_t * dev) |
277 | { | |
1da177e4 | 278 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 279 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 | 280 | |
b5e89ed5 DA |
281 | atomic_set(&dev_priv->swi_emitted, 0); |
282 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | |
1da177e4 | 283 | |
ddbee333 | 284 | radeon_enable_interrupt(dev); |
1da177e4 LT |
285 | } |
286 | ||
b5e89ed5 DA |
287 | void radeon_driver_irq_uninstall(drm_device_t * dev) |
288 | { | |
1da177e4 | 289 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 290 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 LT |
291 | if (!dev_priv) |
292 | return; | |
293 | ||
ddbee333 DA |
294 | dev_priv->irq_enabled = 0; |
295 | ||
1da177e4 | 296 | /* Disable *all* interrupts */ |
b5e89ed5 | 297 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 | 298 | } |
ddbee333 DA |
299 | |
300 | ||
301 | int radeon_vblank_crtc_get(drm_device_t *dev) | |
302 | { | |
303 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
304 | u32 flag; | |
305 | u32 value; | |
306 | ||
307 | flag = RADEON_READ(RADEON_GEN_INT_CNTL); | |
308 | value = 0; | |
309 | ||
310 | if (flag & RADEON_CRTC_VBLANK_MASK) | |
311 | value |= DRM_RADEON_VBLANK_CRTC1; | |
312 | ||
313 | if (flag & RADEON_CRTC2_VBLANK_MASK) | |
314 | value |= DRM_RADEON_VBLANK_CRTC2; | |
315 | return value; | |
316 | } | |
317 | ||
318 | int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value) | |
319 | { | |
320 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
321 | if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | |
322 | DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value); | |
323 | return DRM_ERR(EINVAL); | |
324 | } | |
325 | dev_priv->vblank_crtc = (unsigned int)value; | |
326 | radeon_enable_interrupt(dev); | |
327 | return 0; | |
328 | } |