diff options
Diffstat (limited to 'drivers/char/drm/i915_irq.c')
-rw-r--r-- | drivers/char/drm/i915_irq.c | 597 |
1 files changed, 152 insertions, 445 deletions
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 023ce66ef3ab..f7f16e7a8bf3 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c | |||
@@ -38,109 +38,6 @@ | |||
38 | #define MAX_NOPID ((u32)~0) | 38 | #define MAX_NOPID ((u32)~0) |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * i915_get_pipe - return the the pipe associated with a given plane | ||
42 | * @dev: DRM device | ||
43 | * @plane: plane to look for | ||
44 | * | ||
45 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
46 | * rather than a pipe number, since they may not always be equal. This routine | ||
47 | * maps the given @plane back to a pipe number. | ||
48 | */ | ||
49 | static int | ||
50 | i915_get_pipe(struct drm_device *dev, int plane) | ||
51 | { | ||
52 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
53 | u32 dspcntr; | ||
54 | |||
55 | dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); | ||
56 | |||
57 | return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * i915_get_plane - return the the plane associated with a given pipe | ||
62 | * @dev: DRM device | ||
63 | * @pipe: pipe to look for | ||
64 | * | ||
65 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
66 | * rather than a plane number, since they may not always be equal. This routine | ||
67 | * maps the given @pipe back to a plane number. | ||
68 | */ | ||
69 | static int | ||
70 | i915_get_plane(struct drm_device *dev, int pipe) | ||
71 | { | ||
72 | if (i915_get_pipe(dev, 0) == pipe) | ||
73 | return 0; | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * i915_pipe_enabled - check if a pipe is enabled | ||
79 | * @dev: DRM device | ||
80 | * @pipe: pipe to check | ||
81 | * | ||
82 | * Reading certain registers when the pipe is disabled can hang the chip. | ||
83 | * Use this routine to make sure the PLL is running and the pipe is active | ||
84 | * before reading such registers if unsure. | ||
85 | */ | ||
86 | static int | ||
87 | i915_pipe_enabled(struct drm_device *dev, int pipe) | ||
88 | { | ||
89 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
90 | unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; | ||
91 | |||
92 | if (I915_READ(pipeconf) & PIPEACONF_ENABLE) | ||
93 | return 1; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * Emit a synchronous flip. | ||
100 | * | ||
101 | * This function must be called with the drawable spinlock held. | ||
102 | */ | ||
103 | static void | ||
104 | i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, | ||
105 | int plane) | ||
106 | { | ||
107 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
108 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | ||
109 | u16 x1, y1, x2, y2; | ||
110 | int pf_planes = 1 << plane; | ||
111 | |||
112 | /* If the window is visible on the other plane, we have to flip on that | ||
113 | * plane as well. | ||
114 | */ | ||
115 | if (plane == 1) { | ||
116 | x1 = sarea_priv->planeA_x; | ||
117 | y1 = sarea_priv->planeA_y; | ||
118 | x2 = x1 + sarea_priv->planeA_w; | ||
119 | y2 = y1 + sarea_priv->planeA_h; | ||
120 | } else { | ||
121 | x1 = sarea_priv->planeB_x; | ||
122 | y1 = sarea_priv->planeB_y; | ||
123 | x2 = x1 + sarea_priv->planeB_w; | ||
124 | y2 = y1 + sarea_priv->planeB_h; | ||
125 | } | ||
126 | |||
127 | if (x2 > 0 && y2 > 0) { | ||
128 | int i, num_rects = drw->num_rects; | ||
129 | struct drm_clip_rect *rect = drw->rects; | ||
130 | |||
131 | for (i = 0; i < num_rects; i++) | ||
132 | if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || | ||
133 | rect[i].x2 <= x1 || rect[i].y2 <= y1)) { | ||
134 | pf_planes = 0x3; | ||
135 | |||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | i915_dispatch_flip(dev, pf_planes, 1); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * Emit blits for scheduled buffer swaps. | 41 | * Emit blits for scheduled buffer swaps. |
145 | * | 42 | * |
146 | * This function will be called with the HW lock held. | 43 | * This function will be called with the HW lock held. |
@@ -148,19 +45,20 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, | |||
148 | static void i915_vblank_tasklet(struct drm_device *dev) | 45 | static void i915_vblank_tasklet(struct drm_device *dev) |
149 | { | 46 | { |
150 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 47 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
48 | unsigned long irqflags; | ||
151 | struct list_head *list, *tmp, hits, *hit; | 49 | struct list_head *list, *tmp, hits, *hit; |
152 | int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; | 50 | int nhits, nrects, slice[2], upper[2], lower[2], i; |
153 | unsigned counter[2]; | 51 | unsigned counter[2] = { atomic_read(&dev->vbl_received), |
52 | atomic_read(&dev->vbl_received2) }; | ||
154 | struct drm_drawable_info *drw; | 53 | struct drm_drawable_info *drw; |
155 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 54 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
156 | u32 cpp = dev_priv->cpp, offsets[3]; | 55 | u32 cpp = dev_priv->cpp; |
157 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | | 56 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | |
158 | XY_SRC_COPY_BLT_WRITE_ALPHA | | 57 | XY_SRC_COPY_BLT_WRITE_ALPHA | |
159 | XY_SRC_COPY_BLT_WRITE_RGB) | 58 | XY_SRC_COPY_BLT_WRITE_RGB) |
160 | : XY_SRC_COPY_BLT_CMD; | 59 | : XY_SRC_COPY_BLT_CMD; |
161 | u32 src_pitch = sarea_priv->pitch * cpp; | 60 | u32 src_pitch = sarea_priv->pitch * cpp; |
162 | u32 dst_pitch = sarea_priv->pitch * cpp; | 61 | u32 dst_pitch = sarea_priv->pitch * cpp; |
163 | /* COPY rop (0xcc), map cpp to magic color depth constants */ | ||
164 | u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); | 62 | u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); |
165 | RING_LOCALS; | 63 | RING_LOCALS; |
166 | 64 | ||
@@ -173,34 +71,24 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
173 | src_pitch >>= 2; | 71 | src_pitch >>= 2; |
174 | } | 72 | } |
175 | 73 | ||
176 | counter[0] = drm_vblank_count(dev, 0); | ||
177 | counter[1] = drm_vblank_count(dev, 1); | ||
178 | |||
179 | DRM_DEBUG("\n"); | 74 | DRM_DEBUG("\n"); |
180 | 75 | ||
181 | INIT_LIST_HEAD(&hits); | 76 | INIT_LIST_HEAD(&hits); |
182 | 77 | ||
183 | nhits = nrects = 0; | 78 | nhits = nrects = 0; |
184 | 79 | ||
185 | /* No irqsave/restore necessary. This tasklet may be run in an | 80 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
186 | * interrupt context or normal context, but we don't have to worry | ||
187 | * about getting interrupted by something acquiring the lock, because | ||
188 | * we are the interrupt context thing that acquires the lock. | ||
189 | */ | ||
190 | spin_lock(&dev_priv->swaps_lock); | ||
191 | 81 | ||
192 | /* Find buffer swaps scheduled for this vertical blank */ | 82 | /* Find buffer swaps scheduled for this vertical blank */ |
193 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 83 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
194 | drm_i915_vbl_swap_t *vbl_swap = | 84 | drm_i915_vbl_swap_t *vbl_swap = |
195 | list_entry(list, drm_i915_vbl_swap_t, head); | 85 | list_entry(list, drm_i915_vbl_swap_t, head); |
196 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
197 | 86 | ||
198 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) | 87 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) |
199 | continue; | 88 | continue; |
200 | 89 | ||
201 | list_del(list); | 90 | list_del(list); |
202 | dev_priv->swaps_pending--; | 91 | dev_priv->swaps_pending--; |
203 | drm_vblank_put(dev, pipe); | ||
204 | 92 | ||
205 | spin_unlock(&dev_priv->swaps_lock); | 93 | spin_unlock(&dev_priv->swaps_lock); |
206 | spin_lock(&dev->drw_lock); | 94 | spin_lock(&dev->drw_lock); |
@@ -238,23 +126,43 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
238 | spin_lock(&dev_priv->swaps_lock); | 126 | spin_lock(&dev_priv->swaps_lock); |
239 | } | 127 | } |
240 | 128 | ||
241 | spin_unlock(&dev_priv->swaps_lock); | 129 | if (nhits == 0) { |
242 | 130 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | |
243 | if (nhits == 0) | ||
244 | return; | 131 | return; |
132 | } | ||
133 | |||
134 | spin_unlock(&dev_priv->swaps_lock); | ||
245 | 135 | ||
246 | i915_kernel_lost_context(dev); | 136 | i915_kernel_lost_context(dev); |
247 | 137 | ||
248 | upper[0] = upper[1] = 0; | 138 | if (IS_I965G(dev)) { |
249 | slice[0] = max(sarea_priv->planeA_h / nhits, 1); | 139 | BEGIN_LP_RING(4); |
250 | slice[1] = max(sarea_priv->planeB_h / nhits, 1); | 140 | |
251 | lower[0] = sarea_priv->planeA_y + slice[0]; | 141 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); |
252 | lower[1] = sarea_priv->planeB_y + slice[0]; | 142 | OUT_RING(0); |
143 | OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16)); | ||
144 | OUT_RING(0); | ||
145 | ADVANCE_LP_RING(); | ||
146 | } else { | ||
147 | BEGIN_LP_RING(6); | ||
253 | 148 | ||
254 | offsets[0] = sarea_priv->front_offset; | 149 | OUT_RING(GFX_OP_DRAWRECT_INFO); |
255 | offsets[1] = sarea_priv->back_offset; | 150 | OUT_RING(0); |
256 | offsets[2] = sarea_priv->third_offset; | 151 | OUT_RING(0); |
257 | num_pages = sarea_priv->third_handle ? 3 : 2; | 152 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); |
153 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
154 | OUT_RING(0); | ||
155 | |||
156 | ADVANCE_LP_RING(); | ||
157 | } | ||
158 | |||
159 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | ||
160 | |||
161 | upper[0] = upper[1] = 0; | ||
162 | slice[0] = max(sarea_priv->pipeA_h / nhits, 1); | ||
163 | slice[1] = max(sarea_priv->pipeB_h / nhits, 1); | ||
164 | lower[0] = sarea_priv->pipeA_y + slice[0]; | ||
165 | lower[1] = sarea_priv->pipeB_y + slice[0]; | ||
258 | 166 | ||
259 | spin_lock(&dev->drw_lock); | 167 | spin_lock(&dev->drw_lock); |
260 | 168 | ||
@@ -266,8 +174,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
266 | for (i = 0; i++ < nhits; | 174 | for (i = 0; i++ < nhits; |
267 | upper[0] = lower[0], lower[0] += slice[0], | 175 | upper[0] = lower[0], lower[0] += slice[0], |
268 | upper[1] = lower[1], lower[1] += slice[1]) { | 176 | upper[1] = lower[1], lower[1] += slice[1]) { |
269 | int init_drawrect = 1; | ||
270 | |||
271 | if (i == nhits) | 177 | if (i == nhits) |
272 | lower[0] = lower[1] = sarea_priv->height; | 178 | lower[0] = lower[1] = sarea_priv->height; |
273 | 179 | ||
@@ -275,7 +181,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
275 | drm_i915_vbl_swap_t *swap_hit = | 181 | drm_i915_vbl_swap_t *swap_hit = |
276 | list_entry(hit, drm_i915_vbl_swap_t, head); | 182 | list_entry(hit, drm_i915_vbl_swap_t, head); |
277 | struct drm_clip_rect *rect; | 183 | struct drm_clip_rect *rect; |
278 | int num_rects, plane, front, back; | 184 | int num_rects, pipe; |
279 | unsigned short top, bottom; | 185 | unsigned short top, bottom; |
280 | 186 | ||
281 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 187 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
@@ -283,50 +189,10 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
283 | if (!drw) | 189 | if (!drw) |
284 | continue; | 190 | continue; |
285 | 191 | ||
286 | plane = swap_hit->plane; | ||
287 | |||
288 | if (swap_hit->flip) { | ||
289 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
290 | continue; | ||
291 | } | ||
292 | |||
293 | if (init_drawrect) { | ||
294 | int width = sarea_priv->width; | ||
295 | int height = sarea_priv->height; | ||
296 | if (IS_I965G(dev)) { | ||
297 | BEGIN_LP_RING(4); | ||
298 | |||
299 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); | ||
300 | OUT_RING(0); | ||
301 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
302 | OUT_RING(0); | ||
303 | |||
304 | ADVANCE_LP_RING(); | ||
305 | } else { | ||
306 | BEGIN_LP_RING(6); | ||
307 | |||
308 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
309 | OUT_RING(0); | ||
310 | OUT_RING(0); | ||
311 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
312 | OUT_RING(0); | ||
313 | OUT_RING(0); | ||
314 | |||
315 | ADVANCE_LP_RING(); | ||
316 | } | ||
317 | |||
318 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | ||
319 | |||
320 | init_drawrect = 0; | ||
321 | } | ||
322 | |||
323 | rect = drw->rects; | 192 | rect = drw->rects; |
324 | top = upper[plane]; | 193 | pipe = swap_hit->pipe; |
325 | bottom = lower[plane]; | 194 | top = upper[pipe]; |
326 | 195 | bottom = lower[pipe]; | |
327 | front = (dev_priv->sarea_priv->pf_current_page >> | ||
328 | (2 * plane)) & 0x3; | ||
329 | back = (front + 1) % num_pages; | ||
330 | 196 | ||
331 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 197 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
332 | int y1 = max(rect->y1, top); | 198 | int y1 = max(rect->y1, top); |
@@ -341,17 +207,17 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
341 | OUT_RING(ropcpp | dst_pitch); | 207 | OUT_RING(ropcpp | dst_pitch); |
342 | OUT_RING((y1 << 16) | rect->x1); | 208 | OUT_RING((y1 << 16) | rect->x1); |
343 | OUT_RING((y2 << 16) | rect->x2); | 209 | OUT_RING((y2 << 16) | rect->x2); |
344 | OUT_RING(offsets[front]); | 210 | OUT_RING(sarea_priv->front_offset); |
345 | OUT_RING((y1 << 16) | rect->x1); | 211 | OUT_RING((y1 << 16) | rect->x1); |
346 | OUT_RING(src_pitch); | 212 | OUT_RING(src_pitch); |
347 | OUT_RING(offsets[back]); | 213 | OUT_RING(sarea_priv->back_offset); |
348 | 214 | ||
349 | ADVANCE_LP_RING(); | 215 | ADVANCE_LP_RING(); |
350 | } | 216 | } |
351 | } | 217 | } |
352 | } | 218 | } |
353 | 219 | ||
354 | spin_unlock(&dev->drw_lock); | 220 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
355 | 221 | ||
356 | list_for_each_safe(hit, tmp, &hits) { | 222 | list_for_each_safe(hit, tmp, &hits) { |
357 | drm_i915_vbl_swap_t *swap_hit = | 223 | drm_i915_vbl_swap_t *swap_hit = |
@@ -363,112 +229,67 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
363 | } | 229 | } |
364 | } | 230 | } |
365 | 231 | ||
366 | u32 i915_get_vblank_counter(struct drm_device *dev, int plane) | ||
367 | { | ||
368 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
369 | unsigned long high_frame; | ||
370 | unsigned long low_frame; | ||
371 | u32 high1, high2, low, count; | ||
372 | int pipe; | ||
373 | |||
374 | pipe = i915_get_pipe(dev, plane); | ||
375 | high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; | ||
376 | low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; | ||
377 | |||
378 | if (!i915_pipe_enabled(dev, pipe)) { | ||
379 | printk(KERN_ERR "trying to get vblank count for disabled " | ||
380 | "pipe %d\n", pipe); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * High & low register fields aren't synchronized, so make sure | ||
386 | * we get a low value that's stable across two reads of the high | ||
387 | * register. | ||
388 | */ | ||
389 | do { | ||
390 | high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
391 | PIPE_FRAME_HIGH_SHIFT); | ||
392 | low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
393 | PIPE_FRAME_LOW_SHIFT); | ||
394 | high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
395 | PIPE_FRAME_HIGH_SHIFT); | ||
396 | } while (high1 != high2); | ||
397 | |||
398 | count = (high1 << 8) | low; | ||
399 | |||
400 | /* count may be reset by other driver(e.g. 2D driver), | ||
401 | we have no way to know if it is wrapped or resetted | ||
402 | when count is zero. do a rough guess. | ||
403 | */ | ||
404 | if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) | ||
405 | dev->last_vblank[pipe] = 0; | ||
406 | |||
407 | return count; | ||
408 | } | ||
409 | |||
410 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 232 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
411 | { | 233 | { |
412 | struct drm_device *dev = (struct drm_device *) arg; | 234 | struct drm_device *dev = (struct drm_device *) arg; |
413 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 235 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
414 | u32 iir; | 236 | u16 temp; |
415 | u32 pipea_stats, pipeb_stats; | 237 | u32 pipea_stats, pipeb_stats; |
416 | int vblank = 0; | ||
417 | |||
418 | iir = I915_READ(I915REG_INT_IDENTITY_R); | ||
419 | if (iir == 0) { | ||
420 | DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", | ||
421 | iir, | ||
422 | I915_READ(I915REG_INT_MASK_R), | ||
423 | I915_READ(I915REG_INT_ENABLE_R), | ||
424 | I915_READ(I915REG_PIPEASTAT), | ||
425 | I915_READ(I915REG_PIPEBSTAT)); | ||
426 | return IRQ_NONE; | ||
427 | } | ||
428 | 238 | ||
429 | /* | 239 | pipea_stats = I915_READ(I915REG_PIPEASTAT); |
430 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise | 240 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); |
431 | * we may get extra interrupts. | ||
432 | */ | ||
433 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { | ||
434 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | ||
435 | if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
436 | I915_VBLANK_INTERRUPT_STATUS)) | ||
437 | { | ||
438 | vblank++; | ||
439 | drm_handle_vblank(dev, i915_get_plane(dev, 0)); | ||
440 | } | ||
441 | I915_WRITE(I915REG_PIPEASTAT, pipea_stats); | ||
442 | } | ||
443 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | ||
444 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | ||
445 | if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
446 | I915_VBLANK_INTERRUPT_STATUS)) | ||
447 | { | ||
448 | vblank++; | ||
449 | drm_handle_vblank(dev, i915_get_plane(dev, 1)); | ||
450 | } | ||
451 | I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); | ||
452 | } | ||
453 | 241 | ||
454 | if (dev_priv->sarea_priv) | 242 | temp = I915_READ16(I915REG_INT_IDENTITY_R); |
455 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | ||
456 | 243 | ||
457 | I915_WRITE(I915REG_INT_IDENTITY_R, iir); | 244 | temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); |
458 | (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ | ||
459 | 245 | ||
460 | if (iir & I915_USER_INTERRUPT) { | 246 | DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); |
247 | |||
248 | if (temp == 0) | ||
249 | return IRQ_NONE; | ||
250 | |||
251 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | ||
252 | (void) I915_READ16(I915REG_INT_IDENTITY_R); | ||
253 | DRM_READMEMORYBARRIER(); | ||
254 | |||
255 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | ||
256 | |||
257 | if (temp & USER_INT_FLAG) | ||
461 | DRM_WAKEUP(&dev_priv->irq_queue); | 258 | DRM_WAKEUP(&dev_priv->irq_queue); |
462 | } | 259 | |
463 | if (vblank) { | 260 | if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { |
261 | int vblank_pipe = dev_priv->vblank_pipe; | ||
262 | |||
263 | if ((vblank_pipe & | ||
264 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | ||
265 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
266 | if (temp & VSYNC_PIPEA_FLAG) | ||
267 | atomic_inc(&dev->vbl_received); | ||
268 | if (temp & VSYNC_PIPEB_FLAG) | ||
269 | atomic_inc(&dev->vbl_received2); | ||
270 | } else if (((temp & VSYNC_PIPEA_FLAG) && | ||
271 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
272 | ((temp & VSYNC_PIPEB_FLAG) && | ||
273 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
274 | atomic_inc(&dev->vbl_received); | ||
275 | |||
276 | DRM_WAKEUP(&dev->vbl_queue); | ||
277 | drm_vbl_send_signals(dev); | ||
278 | |||
464 | if (dev_priv->swaps_pending > 0) | 279 | if (dev_priv->swaps_pending > 0) |
465 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 280 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
281 | I915_WRITE(I915REG_PIPEASTAT, | ||
282 | pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
283 | I915_VBLANK_CLEAR); | ||
284 | I915_WRITE(I915REG_PIPEBSTAT, | ||
285 | pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
286 | I915_VBLANK_CLEAR); | ||
466 | } | 287 | } |
467 | 288 | ||
468 | return IRQ_HANDLED; | 289 | return IRQ_HANDLED; |
469 | } | 290 | } |
470 | 291 | ||
471 | static int i915_emit_irq(struct drm_device *dev) | 292 | static int i915_emit_irq(struct drm_device * dev) |
472 | { | 293 | { |
473 | drm_i915_private_t *dev_priv = dev->dev_private; | 294 | drm_i915_private_t *dev_priv = dev->dev_private; |
474 | RING_LOCALS; | 295 | RING_LOCALS; |
@@ -515,12 +336,42 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
515 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 336 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
516 | } | 337 | } |
517 | 338 | ||
518 | if (dev_priv->sarea_priv) | 339 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
519 | dev_priv->sarea_priv->last_dispatch = | ||
520 | READ_BREADCRUMB(dev_priv); | ||
521 | return ret; | 340 | return ret; |
522 | } | 341 | } |
523 | 342 | ||
343 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
344 | atomic_t *counter) | ||
345 | { | ||
346 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
347 | unsigned int cur_vblank; | ||
348 | int ret = 0; | ||
349 | |||
350 | if (!dev_priv) { | ||
351 | DRM_ERROR("called with no initialization\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
356 | (((cur_vblank = atomic_read(counter)) | ||
357 | - *sequence) <= (1<<23))); | ||
358 | |||
359 | *sequence = cur_vblank; | ||
360 | |||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | |||
365 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
366 | { | ||
367 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
368 | } | ||
369 | |||
370 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
371 | { | ||
372 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
373 | } | ||
374 | |||
524 | /* Needs the lock as it touches the ring. | 375 | /* Needs the lock as it touches the ring. |
525 | */ | 376 | */ |
526 | int i915_irq_emit(struct drm_device *dev, void *data, | 377 | int i915_irq_emit(struct drm_device *dev, void *data, |
@@ -563,96 +414,18 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
563 | return i915_wait_irq(dev, irqwait->irq_seq); | 414 | return i915_wait_irq(dev, irqwait->irq_seq); |
564 | } | 415 | } |
565 | 416 | ||
566 | int i915_enable_vblank(struct drm_device *dev, int plane) | ||
567 | { | ||
568 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
569 | int pipe = i915_get_pipe(dev, plane); | ||
570 | u32 pipestat_reg = 0; | ||
571 | u32 pipestat; | ||
572 | |||
573 | switch (pipe) { | ||
574 | case 0: | ||
575 | pipestat_reg = I915REG_PIPEASTAT; | ||
576 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
577 | break; | ||
578 | case 1: | ||
579 | pipestat_reg = I915REG_PIPEBSTAT; | ||
580 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
581 | break; | ||
582 | default: | ||
583 | DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", | ||
584 | pipe); | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | if (pipestat_reg) | ||
589 | { | ||
590 | pipestat = I915_READ (pipestat_reg); | ||
591 | /* | ||
592 | * Older chips didn't have the start vblank interrupt, | ||
593 | * but | ||
594 | */ | ||
595 | if (IS_I965G (dev)) | ||
596 | pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; | ||
597 | else | ||
598 | pipestat |= I915_VBLANK_INTERRUPT_ENABLE; | ||
599 | /* | ||
600 | * Clear any pending status | ||
601 | */ | ||
602 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
603 | I915_VBLANK_INTERRUPT_STATUS); | ||
604 | I915_WRITE(pipestat_reg, pipestat); | ||
605 | } | ||
606 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | void i915_disable_vblank(struct drm_device *dev, int plane) | ||
612 | { | ||
613 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
614 | int pipe = i915_get_pipe(dev, plane); | ||
615 | u32 pipestat_reg = 0; | ||
616 | u32 pipestat; | ||
617 | |||
618 | switch (pipe) { | ||
619 | case 0: | ||
620 | pipestat_reg = I915REG_PIPEASTAT; | ||
621 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
622 | break; | ||
623 | case 1: | ||
624 | pipestat_reg = I915REG_PIPEBSTAT; | ||
625 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
626 | break; | ||
627 | default: | ||
628 | DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", | ||
629 | pipe); | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
634 | if (pipestat_reg) | ||
635 | { | ||
636 | pipestat = I915_READ (pipestat_reg); | ||
637 | pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | | ||
638 | I915_VBLANK_INTERRUPT_ENABLE); | ||
639 | /* | ||
640 | * Clear any pending status | ||
641 | */ | ||
642 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
643 | I915_VBLANK_INTERRUPT_STATUS); | ||
644 | I915_WRITE(pipestat_reg, pipestat); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | static void i915_enable_interrupt (struct drm_device *dev) | 417 | static void i915_enable_interrupt (struct drm_device *dev) |
649 | { | 418 | { |
650 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 419 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
420 | u16 flag; | ||
651 | 421 | ||
652 | dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; | 422 | flag = 0; |
423 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | ||
424 | flag |= VSYNC_PIPEA_FLAG; | ||
425 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | ||
426 | flag |= VSYNC_PIPEB_FLAG; | ||
653 | 427 | ||
654 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | 428 | I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); |
655 | dev_priv->irq_enabled = 1; | ||
656 | } | 429 | } |
657 | 430 | ||
658 | /* Set the vblank monitor pipe | 431 | /* Set the vblank monitor pipe |
@@ -675,6 +448,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, | |||
675 | 448 | ||
676 | dev_priv->vblank_pipe = pipe->pipe; | 449 | dev_priv->vblank_pipe = pipe->pipe; |
677 | 450 | ||
451 | i915_enable_interrupt (dev); | ||
452 | |||
678 | return 0; | 453 | return 0; |
679 | } | 454 | } |
680 | 455 | ||
@@ -692,9 +467,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
692 | 467 | ||
693 | flag = I915_READ(I915REG_INT_ENABLE_R); | 468 | flag = I915_READ(I915REG_INT_ENABLE_R); |
694 | pipe->pipe = 0; | 469 | pipe->pipe = 0; |
695 | if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) | 470 | if (flag & VSYNC_PIPEA_FLAG) |
696 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | 471 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; |
697 | if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) | 472 | if (flag & VSYNC_PIPEB_FLAG) |
698 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | 473 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; |
699 | 474 | ||
700 | return 0; | 475 | return 0; |
@@ -709,30 +484,27 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
709 | drm_i915_private_t *dev_priv = dev->dev_private; | 484 | drm_i915_private_t *dev_priv = dev->dev_private; |
710 | drm_i915_vblank_swap_t *swap = data; | 485 | drm_i915_vblank_swap_t *swap = data; |
711 | drm_i915_vbl_swap_t *vbl_swap; | 486 | drm_i915_vbl_swap_t *vbl_swap; |
712 | unsigned int pipe, seqtype, curseq, plane; | 487 | unsigned int pipe, seqtype, curseq; |
713 | unsigned long irqflags; | 488 | unsigned long irqflags; |
714 | struct list_head *list; | 489 | struct list_head *list; |
715 | int ret; | ||
716 | 490 | ||
717 | if (!dev_priv) { | 491 | if (!dev_priv) { |
718 | DRM_ERROR("%s called with no initialization\n", __func__); | 492 | DRM_ERROR("%s called with no initialization\n", __func__); |
719 | return -EINVAL; | 493 | return -EINVAL; |
720 | } | 494 | } |
721 | 495 | ||
722 | if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { | 496 | if (dev_priv->sarea_priv->rotation) { |
723 | DRM_DEBUG("Rotation not supported\n"); | 497 | DRM_DEBUG("Rotation not supported\n"); |
724 | return -EINVAL; | 498 | return -EINVAL; |
725 | } | 499 | } |
726 | 500 | ||
727 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | | 501 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | |
728 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | | 502 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { |
729 | _DRM_VBLANK_FLIP)) { | ||
730 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); | 503 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); |
731 | return -EINVAL; | 504 | return -EINVAL; |
732 | } | 505 | } |
733 | 506 | ||
734 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 507 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
735 | pipe = i915_get_pipe(dev, plane); | ||
736 | 508 | ||
737 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 509 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
738 | 510 | ||
@@ -743,11 +515,6 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
743 | 515 | ||
744 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 516 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
745 | 517 | ||
746 | /* It makes no sense to schedule a swap for a drawable that doesn't have | ||
747 | * valid information at this point. E.g. this could mean that the X | ||
748 | * server is too old to push drawable information to the DRM, in which | ||
749 | * case all such swaps would become ineffective. | ||
750 | */ | ||
751 | if (!drm_get_drawable_info(dev, swap->drawable)) { | 518 | if (!drm_get_drawable_info(dev, swap->drawable)) { |
752 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 519 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
753 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); | 520 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); |
@@ -756,8 +523,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
756 | 523 | ||
757 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 524 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
758 | 525 | ||
759 | drm_update_vblank_count(dev, pipe); | 526 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); |
760 | curseq = drm_vblank_count(dev, pipe); | ||
761 | 527 | ||
762 | if (seqtype == _DRM_VBLANK_RELATIVE) | 528 | if (seqtype == _DRM_VBLANK_RELATIVE) |
763 | swap->sequence += curseq; | 529 | swap->sequence += curseq; |
@@ -771,43 +537,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
771 | } | 537 | } |
772 | } | 538 | } |
773 | 539 | ||
774 | if (swap->seqtype & _DRM_VBLANK_FLIP) { | ||
775 | swap->sequence--; | ||
776 | |||
777 | if ((curseq - swap->sequence) <= (1<<23)) { | ||
778 | struct drm_drawable_info *drw; | ||
779 | |||
780 | LOCK_TEST_WITH_RETURN(dev, file_priv); | ||
781 | |||
782 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
783 | |||
784 | drw = drm_get_drawable_info(dev, swap->drawable); | ||
785 | |||
786 | if (!drw) { | ||
787 | spin_unlock_irqrestore(&dev->drw_lock, | ||
788 | irqflags); | ||
789 | DRM_DEBUG("Invalid drawable ID %d\n", | ||
790 | swap->drawable); | ||
791 | return -EINVAL; | ||
792 | } | ||
793 | |||
794 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
795 | |||
796 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 540 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
803 | 541 | ||
804 | list_for_each(list, &dev_priv->vbl_swaps.head) { | 542 | list_for_each(list, &dev_priv->vbl_swaps.head) { |
805 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 543 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
806 | 544 | ||
807 | if (vbl_swap->drw_id == swap->drawable && | 545 | if (vbl_swap->drw_id == swap->drawable && |
808 | vbl_swap->plane == plane && | 546 | vbl_swap->pipe == pipe && |
809 | vbl_swap->sequence == swap->sequence) { | 547 | vbl_swap->sequence == swap->sequence) { |
810 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
811 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 548 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
812 | DRM_DEBUG("Already scheduled\n"); | 549 | DRM_DEBUG("Already scheduled\n"); |
813 | return 0; | 550 | return 0; |
@@ -830,19 +567,9 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
830 | 567 | ||
831 | DRM_DEBUG("\n"); | 568 | DRM_DEBUG("\n"); |
832 | 569 | ||
833 | ret = drm_vblank_get(dev, pipe); | ||
834 | if (ret) { | ||
835 | drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); | ||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | vbl_swap->drw_id = swap->drawable; | 570 | vbl_swap->drw_id = swap->drawable; |
840 | vbl_swap->plane = plane; | 571 | vbl_swap->pipe = pipe; |
841 | vbl_swap->sequence = swap->sequence; | 572 | vbl_swap->sequence = swap->sequence; |
842 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
843 | |||
844 | if (vbl_swap->flip) | ||
845 | swap->sequence++; | ||
846 | 573 | ||
847 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 574 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
848 | 575 | ||
@@ -860,57 +587,37 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
860 | { | 587 | { |
861 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 588 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
862 | 589 | ||
863 | I915_WRITE16(I915REG_HWSTAM, 0xeffe); | 590 | I915_WRITE16(I915REG_HWSTAM, 0xfffe); |
864 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); | 591 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); |
865 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 592 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
866 | } | 593 | } |
867 | 594 | ||
868 | int i915_driver_irq_postinstall(struct drm_device * dev) | 595 | void i915_driver_irq_postinstall(struct drm_device * dev) |
869 | { | 596 | { |
870 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 597 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
871 | int ret, num_pipes = 2; | ||
872 | 598 | ||
873 | spin_lock_init(&dev_priv->swaps_lock); | 599 | spin_lock_init(&dev_priv->swaps_lock); |
874 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 600 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
875 | dev_priv->swaps_pending = 0; | 601 | dev_priv->swaps_pending = 0; |
876 | 602 | ||
877 | dev_priv->user_irq_refcount = 0; | 603 | if (!dev_priv->vblank_pipe) |
878 | dev_priv->irq_enable_reg = 0; | 604 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; |
879 | |||
880 | ret = drm_vblank_init(dev, num_pipes); | ||
881 | if (ret) | ||
882 | return ret; | ||
883 | |||
884 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
885 | |||
886 | i915_enable_interrupt(dev); | 605 | i915_enable_interrupt(dev); |
887 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 606 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); |
888 | |||
889 | /* | ||
890 | * Initialize the hardware status page IRQ location. | ||
891 | */ | ||
892 | |||
893 | I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); | ||
894 | return 0; | ||
895 | } | 607 | } |
896 | 608 | ||
897 | void i915_driver_irq_uninstall(struct drm_device * dev) | 609 | void i915_driver_irq_uninstall(struct drm_device * dev) |
898 | { | 610 | { |
899 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 611 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
900 | u32 temp; | 612 | u16 temp; |
901 | 613 | ||
902 | if (!dev_priv) | 614 | if (!dev_priv) |
903 | return; | 615 | return; |
904 | 616 | ||
905 | dev_priv->irq_enabled = 0; | 617 | I915_WRITE16(I915REG_HWSTAM, 0xffff); |
906 | I915_WRITE(I915REG_HWSTAM, 0xffffffff); | 618 | I915_WRITE16(I915REG_INT_MASK_R, 0xffff); |
907 | I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); | 619 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
908 | I915_WRITE(I915REG_INT_ENABLE_R, 0x0); | 620 | |
909 | 621 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | |
910 | temp = I915_READ(I915REG_PIPEASTAT); | 622 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); |
911 | I915_WRITE(I915REG_PIPEASTAT, temp); | ||
912 | temp = I915_READ(I915REG_PIPEBSTAT); | ||
913 | I915_WRITE(I915REG_PIPEBSTAT, temp); | ||
914 | temp = I915_READ(I915REG_INT_IDENTITY_R); | ||
915 | I915_WRITE(I915REG_INT_IDENTITY_R, temp); | ||
916 | } | 623 | } |