diff options
Diffstat (limited to 'drivers/char/drm/i915_irq.c')
-rw-r--r-- | drivers/char/drm/i915_irq.c | 605 |
1 files changed, 459 insertions, 146 deletions
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 92653b38e64c..023ce66ef3ab 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c | |||
@@ -38,6 +38,109 @@ | |||
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 | /** | ||
41 | * Emit blits for scheduled buffer swaps. | 144 | * Emit blits for scheduled buffer swaps. |
42 | * | 145 | * |
43 | * This function will be called with the HW lock held. | 146 | * This function will be called with the HW lock held. |
@@ -45,40 +148,59 @@ | |||
45 | static void i915_vblank_tasklet(struct drm_device *dev) | 148 | static void i915_vblank_tasklet(struct drm_device *dev) |
46 | { | 149 | { |
47 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 150 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
48 | unsigned long irqflags; | ||
49 | struct list_head *list, *tmp, hits, *hit; | 151 | struct list_head *list, *tmp, hits, *hit; |
50 | int nhits, nrects, slice[2], upper[2], lower[2], i; | 152 | int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; |
51 | unsigned counter[2] = { atomic_read(&dev->vbl_received), | 153 | unsigned counter[2]; |
52 | atomic_read(&dev->vbl_received2) }; | ||
53 | struct drm_drawable_info *drw; | 154 | struct drm_drawable_info *drw; |
54 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 155 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
55 | u32 cpp = dev_priv->cpp; | 156 | u32 cpp = dev_priv->cpp, offsets[3]; |
56 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | | 157 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | |
57 | XY_SRC_COPY_BLT_WRITE_ALPHA | | 158 | XY_SRC_COPY_BLT_WRITE_ALPHA | |
58 | XY_SRC_COPY_BLT_WRITE_RGB) | 159 | XY_SRC_COPY_BLT_WRITE_RGB) |
59 | : XY_SRC_COPY_BLT_CMD; | 160 | : XY_SRC_COPY_BLT_CMD; |
60 | u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | | 161 | u32 src_pitch = sarea_priv->pitch * cpp; |
61 | (cpp << 23) | (1 << 24); | 162 | 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 | RING_LOCALS; | 165 | RING_LOCALS; |
63 | 166 | ||
167 | if (sarea_priv->front_tiled) { | ||
168 | cmd |= XY_SRC_COPY_BLT_DST_TILED; | ||
169 | dst_pitch >>= 2; | ||
170 | } | ||
171 | if (sarea_priv->back_tiled) { | ||
172 | cmd |= XY_SRC_COPY_BLT_SRC_TILED; | ||
173 | src_pitch >>= 2; | ||
174 | } | ||
175 | |||
176 | counter[0] = drm_vblank_count(dev, 0); | ||
177 | counter[1] = drm_vblank_count(dev, 1); | ||
178 | |||
64 | DRM_DEBUG("\n"); | 179 | DRM_DEBUG("\n"); |
65 | 180 | ||
66 | INIT_LIST_HEAD(&hits); | 181 | INIT_LIST_HEAD(&hits); |
67 | 182 | ||
68 | nhits = nrects = 0; | 183 | nhits = nrects = 0; |
69 | 184 | ||
70 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 185 | /* No irqsave/restore necessary. This tasklet may be run in an |
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); | ||
71 | 191 | ||
72 | /* Find buffer swaps scheduled for this vertical blank */ | 192 | /* Find buffer swaps scheduled for this vertical blank */ |
73 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 193 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
74 | drm_i915_vbl_swap_t *vbl_swap = | 194 | drm_i915_vbl_swap_t *vbl_swap = |
75 | list_entry(list, drm_i915_vbl_swap_t, head); | 195 | list_entry(list, drm_i915_vbl_swap_t, head); |
196 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
76 | 197 | ||
77 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) | 198 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) |
78 | continue; | 199 | continue; |
79 | 200 | ||
80 | list_del(list); | 201 | list_del(list); |
81 | dev_priv->swaps_pending--; | 202 | dev_priv->swaps_pending--; |
203 | drm_vblank_put(dev, pipe); | ||
82 | 204 | ||
83 | spin_unlock(&dev_priv->swaps_lock); | 205 | spin_unlock(&dev_priv->swaps_lock); |
84 | spin_lock(&dev->drw_lock); | 206 | spin_lock(&dev->drw_lock); |
@@ -116,33 +238,23 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
116 | spin_lock(&dev_priv->swaps_lock); | 238 | spin_lock(&dev_priv->swaps_lock); |
117 | } | 239 | } |
118 | 240 | ||
119 | if (nhits == 0) { | ||
120 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | spin_unlock(&dev_priv->swaps_lock); | 241 | spin_unlock(&dev_priv->swaps_lock); |
125 | 242 | ||
126 | i915_kernel_lost_context(dev); | 243 | if (nhits == 0) |
127 | 244 | return; | |
128 | BEGIN_LP_RING(6); | ||
129 | |||
130 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
131 | OUT_RING(0); | ||
132 | OUT_RING(0); | ||
133 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
134 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
135 | OUT_RING(0); | ||
136 | |||
137 | ADVANCE_LP_RING(); | ||
138 | 245 | ||
139 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | 246 | i915_kernel_lost_context(dev); |
140 | 247 | ||
141 | upper[0] = upper[1] = 0; | 248 | upper[0] = upper[1] = 0; |
142 | slice[0] = max(sarea_priv->pipeA_h / nhits, 1); | 249 | slice[0] = max(sarea_priv->planeA_h / nhits, 1); |
143 | slice[1] = max(sarea_priv->pipeB_h / nhits, 1); | 250 | slice[1] = max(sarea_priv->planeB_h / nhits, 1); |
144 | lower[0] = sarea_priv->pipeA_y + slice[0]; | 251 | lower[0] = sarea_priv->planeA_y + slice[0]; |
145 | lower[1] = sarea_priv->pipeB_y + slice[0]; | 252 | lower[1] = sarea_priv->planeB_y + slice[0]; |
253 | |||
254 | offsets[0] = sarea_priv->front_offset; | ||
255 | offsets[1] = sarea_priv->back_offset; | ||
256 | offsets[2] = sarea_priv->third_offset; | ||
257 | num_pages = sarea_priv->third_handle ? 3 : 2; | ||
146 | 258 | ||
147 | spin_lock(&dev->drw_lock); | 259 | spin_lock(&dev->drw_lock); |
148 | 260 | ||
@@ -154,6 +266,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
154 | for (i = 0; i++ < nhits; | 266 | for (i = 0; i++ < nhits; |
155 | upper[0] = lower[0], lower[0] += slice[0], | 267 | upper[0] = lower[0], lower[0] += slice[0], |
156 | upper[1] = lower[1], lower[1] += slice[1]) { | 268 | upper[1] = lower[1], lower[1] += slice[1]) { |
269 | int init_drawrect = 1; | ||
270 | |||
157 | if (i == nhits) | 271 | if (i == nhits) |
158 | lower[0] = lower[1] = sarea_priv->height; | 272 | lower[0] = lower[1] = sarea_priv->height; |
159 | 273 | ||
@@ -161,7 +275,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
161 | drm_i915_vbl_swap_t *swap_hit = | 275 | drm_i915_vbl_swap_t *swap_hit = |
162 | list_entry(hit, drm_i915_vbl_swap_t, head); | 276 | list_entry(hit, drm_i915_vbl_swap_t, head); |
163 | struct drm_clip_rect *rect; | 277 | struct drm_clip_rect *rect; |
164 | int num_rects, pipe; | 278 | int num_rects, plane, front, back; |
165 | unsigned short top, bottom; | 279 | unsigned short top, bottom; |
166 | 280 | ||
167 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 281 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
@@ -169,10 +283,50 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
169 | if (!drw) | 283 | if (!drw) |
170 | continue; | 284 | continue; |
171 | 285 | ||
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 | |||
172 | rect = drw->rects; | 323 | rect = drw->rects; |
173 | pipe = swap_hit->pipe; | 324 | top = upper[plane]; |
174 | top = upper[pipe]; | 325 | bottom = lower[plane]; |
175 | bottom = lower[pipe]; | 326 | |
327 | front = (dev_priv->sarea_priv->pf_current_page >> | ||
328 | (2 * plane)) & 0x3; | ||
329 | back = (front + 1) % num_pages; | ||
176 | 330 | ||
177 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 331 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
178 | int y1 = max(rect->y1, top); | 332 | int y1 = max(rect->y1, top); |
@@ -184,20 +338,20 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
184 | BEGIN_LP_RING(8); | 338 | BEGIN_LP_RING(8); |
185 | 339 | ||
186 | OUT_RING(cmd); | 340 | OUT_RING(cmd); |
187 | OUT_RING(pitchropcpp); | 341 | OUT_RING(ropcpp | dst_pitch); |
188 | OUT_RING((y1 << 16) | rect->x1); | 342 | OUT_RING((y1 << 16) | rect->x1); |
189 | OUT_RING((y2 << 16) | rect->x2); | 343 | OUT_RING((y2 << 16) | rect->x2); |
190 | OUT_RING(sarea_priv->front_offset); | 344 | OUT_RING(offsets[front]); |
191 | OUT_RING((y1 << 16) | rect->x1); | 345 | OUT_RING((y1 << 16) | rect->x1); |
192 | OUT_RING(pitchropcpp & 0xffff); | 346 | OUT_RING(src_pitch); |
193 | OUT_RING(sarea_priv->back_offset); | 347 | OUT_RING(offsets[back]); |
194 | 348 | ||
195 | ADVANCE_LP_RING(); | 349 | ADVANCE_LP_RING(); |
196 | } | 350 | } |
197 | } | 351 | } |
198 | } | 352 | } |
199 | 353 | ||
200 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 354 | spin_unlock(&dev->drw_lock); |
201 | 355 | ||
202 | list_for_each_safe(hit, tmp, &hits) { | 356 | list_for_each_safe(hit, tmp, &hits) { |
203 | drm_i915_vbl_swap_t *swap_hit = | 357 | drm_i915_vbl_swap_t *swap_hit = |
@@ -209,67 +363,112 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
209 | } | 363 | } |
210 | } | 364 | } |
211 | 365 | ||
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 | |||
212 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 410 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
213 | { | 411 | { |
214 | struct drm_device *dev = (struct drm_device *) arg; | 412 | struct drm_device *dev = (struct drm_device *) arg; |
215 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 413 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
216 | u16 temp; | 414 | u32 iir; |
217 | u32 pipea_stats, pipeb_stats; | 415 | u32 pipea_stats, pipeb_stats; |
218 | 416 | int vblank = 0; | |
219 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | 417 | |
220 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | 418 | iir = I915_READ(I915REG_INT_IDENTITY_R); |
221 | 419 | if (iir == 0) { | |
222 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 420 | DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", |
223 | 421 | iir, | |
224 | temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); | 422 | I915_READ(I915REG_INT_MASK_R), |
225 | 423 | I915_READ(I915REG_INT_ENABLE_R), | |
226 | DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); | 424 | I915_READ(I915REG_PIPEASTAT), |
227 | 425 | I915_READ(I915REG_PIPEBSTAT)); | |
228 | if (temp == 0) | ||
229 | return IRQ_NONE; | 426 | return IRQ_NONE; |
427 | } | ||
230 | 428 | ||
231 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 429 | /* |
232 | (void) I915_READ16(I915REG_INT_IDENTITY_R); | 430 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise |
233 | DRM_READMEMORYBARRIER(); | 431 | * we may get extra interrupts. |
234 | 432 | */ | |
235 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 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 | } | ||
236 | 453 | ||
237 | if (temp & USER_INT_FLAG) | 454 | if (dev_priv->sarea_priv) |
238 | DRM_WAKEUP(&dev_priv->irq_queue); | 455 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
239 | 456 | ||
240 | if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { | 457 | I915_WRITE(I915REG_INT_IDENTITY_R, iir); |
241 | int vblank_pipe = dev_priv->vblank_pipe; | 458 | (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ |
242 | |||
243 | if ((vblank_pipe & | ||
244 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | ||
245 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
246 | if (temp & VSYNC_PIPEA_FLAG) | ||
247 | atomic_inc(&dev->vbl_received); | ||
248 | if (temp & VSYNC_PIPEB_FLAG) | ||
249 | atomic_inc(&dev->vbl_received2); | ||
250 | } else if (((temp & VSYNC_PIPEA_FLAG) && | ||
251 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
252 | ((temp & VSYNC_PIPEB_FLAG) && | ||
253 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
254 | atomic_inc(&dev->vbl_received); | ||
255 | |||
256 | DRM_WAKEUP(&dev->vbl_queue); | ||
257 | drm_vbl_send_signals(dev); | ||
258 | 459 | ||
460 | if (iir & I915_USER_INTERRUPT) { | ||
461 | DRM_WAKEUP(&dev_priv->irq_queue); | ||
462 | } | ||
463 | if (vblank) { | ||
259 | if (dev_priv->swaps_pending > 0) | 464 | if (dev_priv->swaps_pending > 0) |
260 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 465 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
261 | I915_WRITE(I915REG_PIPEASTAT, | ||
262 | pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
263 | I915_VBLANK_CLEAR); | ||
264 | I915_WRITE(I915REG_PIPEBSTAT, | ||
265 | pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
266 | I915_VBLANK_CLEAR); | ||
267 | } | 466 | } |
268 | 467 | ||
269 | return IRQ_HANDLED; | 468 | return IRQ_HANDLED; |
270 | } | 469 | } |
271 | 470 | ||
272 | static int i915_emit_irq(struct drm_device * dev) | 471 | static int i915_emit_irq(struct drm_device *dev) |
273 | { | 472 | { |
274 | drm_i915_private_t *dev_priv = dev->dev_private; | 473 | drm_i915_private_t *dev_priv = dev->dev_private; |
275 | RING_LOCALS; | 474 | RING_LOCALS; |
@@ -316,42 +515,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
316 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 515 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
317 | } | 516 | } |
318 | 517 | ||
319 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 518 | if (dev_priv->sarea_priv) |
320 | return ret; | 519 | dev_priv->sarea_priv->last_dispatch = |
321 | } | 520 | READ_BREADCRUMB(dev_priv); |
322 | |||
323 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
324 | atomic_t *counter) | ||
325 | { | ||
326 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
327 | unsigned int cur_vblank; | ||
328 | int ret = 0; | ||
329 | |||
330 | if (!dev_priv) { | ||
331 | DRM_ERROR("called with no initialization\n"); | ||
332 | return -EINVAL; | ||
333 | } | ||
334 | |||
335 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
336 | (((cur_vblank = atomic_read(counter)) | ||
337 | - *sequence) <= (1<<23))); | ||
338 | |||
339 | *sequence = cur_vblank; | ||
340 | |||
341 | return ret; | 521 | return ret; |
342 | } | 522 | } |
343 | 523 | ||
344 | |||
345 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
346 | { | ||
347 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
348 | } | ||
349 | |||
350 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
351 | { | ||
352 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
353 | } | ||
354 | |||
355 | /* Needs the lock as it touches the ring. | 524 | /* Needs the lock as it touches the ring. |
356 | */ | 525 | */ |
357 | int i915_irq_emit(struct drm_device *dev, void *data, | 526 | int i915_irq_emit(struct drm_device *dev, void *data, |
@@ -394,18 +563,96 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
394 | return i915_wait_irq(dev, irqwait->irq_seq); | 563 | return i915_wait_irq(dev, irqwait->irq_seq); |
395 | } | 564 | } |
396 | 565 | ||
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 | |||
397 | static void i915_enable_interrupt (struct drm_device *dev) | 648 | static void i915_enable_interrupt (struct drm_device *dev) |
398 | { | 649 | { |
399 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 650 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
400 | u16 flag; | ||
401 | 651 | ||
402 | flag = 0; | 652 | dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; |
403 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | ||
404 | flag |= VSYNC_PIPEA_FLAG; | ||
405 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | ||
406 | flag |= VSYNC_PIPEB_FLAG; | ||
407 | 653 | ||
408 | I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); | 654 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); |
655 | dev_priv->irq_enabled = 1; | ||
409 | } | 656 | } |
410 | 657 | ||
411 | /* Set the vblank monitor pipe | 658 | /* Set the vblank monitor pipe |
@@ -428,8 +675,6 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, | |||
428 | 675 | ||
429 | dev_priv->vblank_pipe = pipe->pipe; | 676 | dev_priv->vblank_pipe = pipe->pipe; |
430 | 677 | ||
431 | i915_enable_interrupt (dev); | ||
432 | |||
433 | return 0; | 678 | return 0; |
434 | } | 679 | } |
435 | 680 | ||
@@ -447,9 +692,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
447 | 692 | ||
448 | flag = I915_READ(I915REG_INT_ENABLE_R); | 693 | flag = I915_READ(I915REG_INT_ENABLE_R); |
449 | pipe->pipe = 0; | 694 | pipe->pipe = 0; |
450 | if (flag & VSYNC_PIPEA_FLAG) | 695 | if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) |
451 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | 696 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; |
452 | if (flag & VSYNC_PIPEB_FLAG) | 697 | if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) |
453 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | 698 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; |
454 | 699 | ||
455 | return 0; | 700 | return 0; |
@@ -464,27 +709,30 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
464 | drm_i915_private_t *dev_priv = dev->dev_private; | 709 | drm_i915_private_t *dev_priv = dev->dev_private; |
465 | drm_i915_vblank_swap_t *swap = data; | 710 | drm_i915_vblank_swap_t *swap = data; |
466 | drm_i915_vbl_swap_t *vbl_swap; | 711 | drm_i915_vbl_swap_t *vbl_swap; |
467 | unsigned int pipe, seqtype, curseq; | 712 | unsigned int pipe, seqtype, curseq, plane; |
468 | unsigned long irqflags; | 713 | unsigned long irqflags; |
469 | struct list_head *list; | 714 | struct list_head *list; |
715 | int ret; | ||
470 | 716 | ||
471 | if (!dev_priv) { | 717 | if (!dev_priv) { |
472 | DRM_ERROR("%s called with no initialization\n", __func__); | 718 | DRM_ERROR("%s called with no initialization\n", __func__); |
473 | return -EINVAL; | 719 | return -EINVAL; |
474 | } | 720 | } |
475 | 721 | ||
476 | if (dev_priv->sarea_priv->rotation) { | 722 | if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { |
477 | DRM_DEBUG("Rotation not supported\n"); | 723 | DRM_DEBUG("Rotation not supported\n"); |
478 | return -EINVAL; | 724 | return -EINVAL; |
479 | } | 725 | } |
480 | 726 | ||
481 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | | 727 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | |
482 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { | 728 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | |
729 | _DRM_VBLANK_FLIP)) { | ||
483 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); | 730 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); |
484 | return -EINVAL; | 731 | return -EINVAL; |
485 | } | 732 | } |
486 | 733 | ||
487 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 734 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
735 | pipe = i915_get_pipe(dev, plane); | ||
488 | 736 | ||
489 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 737 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
490 | 738 | ||
@@ -495,6 +743,11 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
495 | 743 | ||
496 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 744 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
497 | 745 | ||
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 | */ | ||
498 | if (!drm_get_drawable_info(dev, swap->drawable)) { | 751 | if (!drm_get_drawable_info(dev, swap->drawable)) { |
499 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 752 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
500 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); | 753 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); |
@@ -503,7 +756,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
503 | 756 | ||
504 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 757 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
505 | 758 | ||
506 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); | 759 | drm_update_vblank_count(dev, pipe); |
760 | curseq = drm_vblank_count(dev, pipe); | ||
507 | 761 | ||
508 | if (seqtype == _DRM_VBLANK_RELATIVE) | 762 | if (seqtype == _DRM_VBLANK_RELATIVE) |
509 | swap->sequence += curseq; | 763 | swap->sequence += curseq; |
@@ -517,14 +771,43 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
517 | } | 771 | } |
518 | } | 772 | } |
519 | 773 | ||
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 | |||
520 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 802 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
521 | 803 | ||
522 | list_for_each(list, &dev_priv->vbl_swaps.head) { | 804 | list_for_each(list, &dev_priv->vbl_swaps.head) { |
523 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 805 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
524 | 806 | ||
525 | if (vbl_swap->drw_id == swap->drawable && | 807 | if (vbl_swap->drw_id == swap->drawable && |
526 | vbl_swap->pipe == pipe && | 808 | vbl_swap->plane == plane && |
527 | vbl_swap->sequence == swap->sequence) { | 809 | vbl_swap->sequence == swap->sequence) { |
810 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
528 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 811 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
529 | DRM_DEBUG("Already scheduled\n"); | 812 | DRM_DEBUG("Already scheduled\n"); |
530 | return 0; | 813 | return 0; |
@@ -547,9 +830,19 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
547 | 830 | ||
548 | DRM_DEBUG("\n"); | 831 | DRM_DEBUG("\n"); |
549 | 832 | ||
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 | |||
550 | vbl_swap->drw_id = swap->drawable; | 839 | vbl_swap->drw_id = swap->drawable; |
551 | vbl_swap->pipe = pipe; | 840 | vbl_swap->plane = plane; |
552 | vbl_swap->sequence = swap->sequence; | 841 | vbl_swap->sequence = swap->sequence; |
842 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
843 | |||
844 | if (vbl_swap->flip) | ||
845 | swap->sequence++; | ||
553 | 846 | ||
554 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 847 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
555 | 848 | ||
@@ -567,37 +860,57 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
567 | { | 860 | { |
568 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 861 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
569 | 862 | ||
570 | I915_WRITE16(I915REG_HWSTAM, 0xfffe); | 863 | I915_WRITE16(I915REG_HWSTAM, 0xeffe); |
571 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); | 864 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); |
572 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 865 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
573 | } | 866 | } |
574 | 867 | ||
575 | void i915_driver_irq_postinstall(struct drm_device * dev) | 868 | int i915_driver_irq_postinstall(struct drm_device * dev) |
576 | { | 869 | { |
577 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 870 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
871 | int ret, num_pipes = 2; | ||
578 | 872 | ||
579 | spin_lock_init(&dev_priv->swaps_lock); | 873 | spin_lock_init(&dev_priv->swaps_lock); |
580 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 874 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
581 | dev_priv->swaps_pending = 0; | 875 | dev_priv->swaps_pending = 0; |
582 | 876 | ||
583 | if (!dev_priv->vblank_pipe) | 877 | dev_priv->user_irq_refcount = 0; |
584 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; | 878 | dev_priv->irq_enable_reg = 0; |
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 | |||
585 | i915_enable_interrupt(dev); | 886 | i915_enable_interrupt(dev); |
586 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 887 | 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; | ||
587 | } | 895 | } |
588 | 896 | ||
589 | void i915_driver_irq_uninstall(struct drm_device * dev) | 897 | void i915_driver_irq_uninstall(struct drm_device * dev) |
590 | { | 898 | { |
591 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 899 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
592 | u16 temp; | 900 | u32 temp; |
593 | 901 | ||
594 | if (!dev_priv) | 902 | if (!dev_priv) |
595 | return; | 903 | return; |
596 | 904 | ||
597 | I915_WRITE16(I915REG_HWSTAM, 0xffff); | 905 | dev_priv->irq_enabled = 0; |
598 | I915_WRITE16(I915REG_INT_MASK_R, 0xffff); | 906 | I915_WRITE(I915REG_HWSTAM, 0xffffffff); |
599 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 907 | I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); |
600 | 908 | I915_WRITE(I915REG_INT_ENABLE_R, 0x0); | |
601 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 909 | |
602 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 910 | temp = I915_READ(I915REG_PIPEASTAT); |
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); | ||
603 | } | 916 | } |