xref: /openbmc/linux/drivers/gpu/drm/i915/i915_irq.c (revision c0e09200dc0813972442e550a5905a132768e56c)
1*c0e09200SDave Airlie /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
2*c0e09200SDave Airlie  */
3*c0e09200SDave Airlie /*
4*c0e09200SDave Airlie  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
5*c0e09200SDave Airlie  * All Rights Reserved.
6*c0e09200SDave Airlie  *
7*c0e09200SDave Airlie  * Permission is hereby granted, free of charge, to any person obtaining a
8*c0e09200SDave Airlie  * copy of this software and associated documentation files (the
9*c0e09200SDave Airlie  * "Software"), to deal in the Software without restriction, including
10*c0e09200SDave Airlie  * without limitation the rights to use, copy, modify, merge, publish,
11*c0e09200SDave Airlie  * distribute, sub license, and/or sell copies of the Software, and to
12*c0e09200SDave Airlie  * permit persons to whom the Software is furnished to do so, subject to
13*c0e09200SDave Airlie  * the following conditions:
14*c0e09200SDave Airlie  *
15*c0e09200SDave Airlie  * The above copyright notice and this permission notice (including the
16*c0e09200SDave Airlie  * next paragraph) shall be included in all copies or substantial portions
17*c0e09200SDave Airlie  * of the Software.
18*c0e09200SDave Airlie  *
19*c0e09200SDave Airlie  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20*c0e09200SDave Airlie  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21*c0e09200SDave Airlie  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22*c0e09200SDave Airlie  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23*c0e09200SDave Airlie  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24*c0e09200SDave Airlie  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25*c0e09200SDave Airlie  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26*c0e09200SDave Airlie  *
27*c0e09200SDave Airlie  */
28*c0e09200SDave Airlie 
29*c0e09200SDave Airlie #include "drmP.h"
30*c0e09200SDave Airlie #include "drm.h"
31*c0e09200SDave Airlie #include "i915_drm.h"
32*c0e09200SDave Airlie #include "i915_drv.h"
33*c0e09200SDave Airlie 
34*c0e09200SDave Airlie #define USER_INT_FLAG (1<<1)
35*c0e09200SDave Airlie #define VSYNC_PIPEB_FLAG (1<<5)
36*c0e09200SDave Airlie #define VSYNC_PIPEA_FLAG (1<<7)
37*c0e09200SDave Airlie 
38*c0e09200SDave Airlie #define MAX_NOPID ((u32)~0)
39*c0e09200SDave Airlie 
40*c0e09200SDave Airlie /**
41*c0e09200SDave Airlie  * Emit blits for scheduled buffer swaps.
42*c0e09200SDave Airlie  *
43*c0e09200SDave Airlie  * This function will be called with the HW lock held.
44*c0e09200SDave Airlie  */
45*c0e09200SDave Airlie static void i915_vblank_tasklet(struct drm_device *dev)
46*c0e09200SDave Airlie {
47*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
48*c0e09200SDave Airlie 	unsigned long irqflags;
49*c0e09200SDave Airlie 	struct list_head *list, *tmp, hits, *hit;
50*c0e09200SDave Airlie 	int nhits, nrects, slice[2], upper[2], lower[2], i;
51*c0e09200SDave Airlie 	unsigned counter[2] = { atomic_read(&dev->vbl_received),
52*c0e09200SDave Airlie 				atomic_read(&dev->vbl_received2) };
53*c0e09200SDave Airlie 	struct drm_drawable_info *drw;
54*c0e09200SDave Airlie 	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
55*c0e09200SDave Airlie 	u32 cpp = dev_priv->cpp;
56*c0e09200SDave Airlie 	u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
57*c0e09200SDave Airlie 				XY_SRC_COPY_BLT_WRITE_ALPHA |
58*c0e09200SDave Airlie 				XY_SRC_COPY_BLT_WRITE_RGB)
59*c0e09200SDave Airlie 			     : XY_SRC_COPY_BLT_CMD;
60*c0e09200SDave Airlie 	u32 src_pitch = sarea_priv->pitch * cpp;
61*c0e09200SDave Airlie 	u32 dst_pitch = sarea_priv->pitch * cpp;
62*c0e09200SDave Airlie 	u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
63*c0e09200SDave Airlie 	RING_LOCALS;
64*c0e09200SDave Airlie 
65*c0e09200SDave Airlie 	if (IS_I965G(dev) && sarea_priv->front_tiled) {
66*c0e09200SDave Airlie 		cmd |= XY_SRC_COPY_BLT_DST_TILED;
67*c0e09200SDave Airlie 		dst_pitch >>= 2;
68*c0e09200SDave Airlie 	}
69*c0e09200SDave Airlie 	if (IS_I965G(dev) && sarea_priv->back_tiled) {
70*c0e09200SDave Airlie 		cmd |= XY_SRC_COPY_BLT_SRC_TILED;
71*c0e09200SDave Airlie 		src_pitch >>= 2;
72*c0e09200SDave Airlie 	}
73*c0e09200SDave Airlie 
74*c0e09200SDave Airlie 	DRM_DEBUG("\n");
75*c0e09200SDave Airlie 
76*c0e09200SDave Airlie 	INIT_LIST_HEAD(&hits);
77*c0e09200SDave Airlie 
78*c0e09200SDave Airlie 	nhits = nrects = 0;
79*c0e09200SDave Airlie 
80*c0e09200SDave Airlie 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
81*c0e09200SDave Airlie 
82*c0e09200SDave Airlie 	/* Find buffer swaps scheduled for this vertical blank */
83*c0e09200SDave Airlie 	list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
84*c0e09200SDave Airlie 		drm_i915_vbl_swap_t *vbl_swap =
85*c0e09200SDave Airlie 			list_entry(list, drm_i915_vbl_swap_t, head);
86*c0e09200SDave Airlie 
87*c0e09200SDave Airlie 		if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
88*c0e09200SDave Airlie 			continue;
89*c0e09200SDave Airlie 
90*c0e09200SDave Airlie 		list_del(list);
91*c0e09200SDave Airlie 		dev_priv->swaps_pending--;
92*c0e09200SDave Airlie 
93*c0e09200SDave Airlie 		spin_unlock(&dev_priv->swaps_lock);
94*c0e09200SDave Airlie 		spin_lock(&dev->drw_lock);
95*c0e09200SDave Airlie 
96*c0e09200SDave Airlie 		drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
97*c0e09200SDave Airlie 
98*c0e09200SDave Airlie 		if (!drw) {
99*c0e09200SDave Airlie 			spin_unlock(&dev->drw_lock);
100*c0e09200SDave Airlie 			drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
101*c0e09200SDave Airlie 			spin_lock(&dev_priv->swaps_lock);
102*c0e09200SDave Airlie 			continue;
103*c0e09200SDave Airlie 		}
104*c0e09200SDave Airlie 
105*c0e09200SDave Airlie 		list_for_each(hit, &hits) {
106*c0e09200SDave Airlie 			drm_i915_vbl_swap_t *swap_cmp =
107*c0e09200SDave Airlie 				list_entry(hit, drm_i915_vbl_swap_t, head);
108*c0e09200SDave Airlie 			struct drm_drawable_info *drw_cmp =
109*c0e09200SDave Airlie 				drm_get_drawable_info(dev, swap_cmp->drw_id);
110*c0e09200SDave Airlie 
111*c0e09200SDave Airlie 			if (drw_cmp &&
112*c0e09200SDave Airlie 			    drw_cmp->rects[0].y1 > drw->rects[0].y1) {
113*c0e09200SDave Airlie 				list_add_tail(list, hit);
114*c0e09200SDave Airlie 				break;
115*c0e09200SDave Airlie 			}
116*c0e09200SDave Airlie 		}
117*c0e09200SDave Airlie 
118*c0e09200SDave Airlie 		spin_unlock(&dev->drw_lock);
119*c0e09200SDave Airlie 
120*c0e09200SDave Airlie 		/* List of hits was empty, or we reached the end of it */
121*c0e09200SDave Airlie 		if (hit == &hits)
122*c0e09200SDave Airlie 			list_add_tail(list, hits.prev);
123*c0e09200SDave Airlie 
124*c0e09200SDave Airlie 		nhits++;
125*c0e09200SDave Airlie 
126*c0e09200SDave Airlie 		spin_lock(&dev_priv->swaps_lock);
127*c0e09200SDave Airlie 	}
128*c0e09200SDave Airlie 
129*c0e09200SDave Airlie 	if (nhits == 0) {
130*c0e09200SDave Airlie 		spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
131*c0e09200SDave Airlie 		return;
132*c0e09200SDave Airlie 	}
133*c0e09200SDave Airlie 
134*c0e09200SDave Airlie 	spin_unlock(&dev_priv->swaps_lock);
135*c0e09200SDave Airlie 
136*c0e09200SDave Airlie 	i915_kernel_lost_context(dev);
137*c0e09200SDave Airlie 
138*c0e09200SDave Airlie 	if (IS_I965G(dev)) {
139*c0e09200SDave Airlie 		BEGIN_LP_RING(4);
140*c0e09200SDave Airlie 
141*c0e09200SDave Airlie 		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
142*c0e09200SDave Airlie 		OUT_RING(0);
143*c0e09200SDave Airlie 		OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16));
144*c0e09200SDave Airlie 		OUT_RING(0);
145*c0e09200SDave Airlie 		ADVANCE_LP_RING();
146*c0e09200SDave Airlie 	} else {
147*c0e09200SDave Airlie 		BEGIN_LP_RING(6);
148*c0e09200SDave Airlie 
149*c0e09200SDave Airlie 		OUT_RING(GFX_OP_DRAWRECT_INFO);
150*c0e09200SDave Airlie 		OUT_RING(0);
151*c0e09200SDave Airlie 		OUT_RING(0);
152*c0e09200SDave Airlie 		OUT_RING(sarea_priv->width | sarea_priv->height << 16);
153*c0e09200SDave Airlie 		OUT_RING(sarea_priv->width | sarea_priv->height << 16);
154*c0e09200SDave Airlie 		OUT_RING(0);
155*c0e09200SDave Airlie 
156*c0e09200SDave Airlie 		ADVANCE_LP_RING();
157*c0e09200SDave Airlie 	}
158*c0e09200SDave Airlie 
159*c0e09200SDave Airlie 	sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
160*c0e09200SDave Airlie 
161*c0e09200SDave Airlie 	upper[0] = upper[1] = 0;
162*c0e09200SDave Airlie 	slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
163*c0e09200SDave Airlie 	slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
164*c0e09200SDave Airlie 	lower[0] = sarea_priv->pipeA_y + slice[0];
165*c0e09200SDave Airlie 	lower[1] = sarea_priv->pipeB_y + slice[0];
166*c0e09200SDave Airlie 
167*c0e09200SDave Airlie 	spin_lock(&dev->drw_lock);
168*c0e09200SDave Airlie 
169*c0e09200SDave Airlie 	/* Emit blits for buffer swaps, partitioning both outputs into as many
170*c0e09200SDave Airlie 	 * slices as there are buffer swaps scheduled in order to avoid tearing
171*c0e09200SDave Airlie 	 * (based on the assumption that a single buffer swap would always
172*c0e09200SDave Airlie 	 * complete before scanout starts).
173*c0e09200SDave Airlie 	 */
174*c0e09200SDave Airlie 	for (i = 0; i++ < nhits;
175*c0e09200SDave Airlie 	     upper[0] = lower[0], lower[0] += slice[0],
176*c0e09200SDave Airlie 	     upper[1] = lower[1], lower[1] += slice[1]) {
177*c0e09200SDave Airlie 		if (i == nhits)
178*c0e09200SDave Airlie 			lower[0] = lower[1] = sarea_priv->height;
179*c0e09200SDave Airlie 
180*c0e09200SDave Airlie 		list_for_each(hit, &hits) {
181*c0e09200SDave Airlie 			drm_i915_vbl_swap_t *swap_hit =
182*c0e09200SDave Airlie 				list_entry(hit, drm_i915_vbl_swap_t, head);
183*c0e09200SDave Airlie 			struct drm_clip_rect *rect;
184*c0e09200SDave Airlie 			int num_rects, pipe;
185*c0e09200SDave Airlie 			unsigned short top, bottom;
186*c0e09200SDave Airlie 
187*c0e09200SDave Airlie 			drw = drm_get_drawable_info(dev, swap_hit->drw_id);
188*c0e09200SDave Airlie 
189*c0e09200SDave Airlie 			if (!drw)
190*c0e09200SDave Airlie 				continue;
191*c0e09200SDave Airlie 
192*c0e09200SDave Airlie 			rect = drw->rects;
193*c0e09200SDave Airlie 			pipe = swap_hit->pipe;
194*c0e09200SDave Airlie 			top = upper[pipe];
195*c0e09200SDave Airlie 			bottom = lower[pipe];
196*c0e09200SDave Airlie 
197*c0e09200SDave Airlie 			for (num_rects = drw->num_rects; num_rects--; rect++) {
198*c0e09200SDave Airlie 				int y1 = max(rect->y1, top);
199*c0e09200SDave Airlie 				int y2 = min(rect->y2, bottom);
200*c0e09200SDave Airlie 
201*c0e09200SDave Airlie 				if (y1 >= y2)
202*c0e09200SDave Airlie 					continue;
203*c0e09200SDave Airlie 
204*c0e09200SDave Airlie 				BEGIN_LP_RING(8);
205*c0e09200SDave Airlie 
206*c0e09200SDave Airlie 				OUT_RING(cmd);
207*c0e09200SDave Airlie 				OUT_RING(ropcpp | dst_pitch);
208*c0e09200SDave Airlie 				OUT_RING((y1 << 16) | rect->x1);
209*c0e09200SDave Airlie 				OUT_RING((y2 << 16) | rect->x2);
210*c0e09200SDave Airlie 				OUT_RING(sarea_priv->front_offset);
211*c0e09200SDave Airlie 				OUT_RING((y1 << 16) | rect->x1);
212*c0e09200SDave Airlie 				OUT_RING(src_pitch);
213*c0e09200SDave Airlie 				OUT_RING(sarea_priv->back_offset);
214*c0e09200SDave Airlie 
215*c0e09200SDave Airlie 				ADVANCE_LP_RING();
216*c0e09200SDave Airlie 			}
217*c0e09200SDave Airlie 		}
218*c0e09200SDave Airlie 	}
219*c0e09200SDave Airlie 
220*c0e09200SDave Airlie 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
221*c0e09200SDave Airlie 
222*c0e09200SDave Airlie 	list_for_each_safe(hit, tmp, &hits) {
223*c0e09200SDave Airlie 		drm_i915_vbl_swap_t *swap_hit =
224*c0e09200SDave Airlie 			list_entry(hit, drm_i915_vbl_swap_t, head);
225*c0e09200SDave Airlie 
226*c0e09200SDave Airlie 		list_del(hit);
227*c0e09200SDave Airlie 
228*c0e09200SDave Airlie 		drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
229*c0e09200SDave Airlie 	}
230*c0e09200SDave Airlie }
231*c0e09200SDave Airlie 
232*c0e09200SDave Airlie irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
233*c0e09200SDave Airlie {
234*c0e09200SDave Airlie 	struct drm_device *dev = (struct drm_device *) arg;
235*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
236*c0e09200SDave Airlie 	u16 temp;
237*c0e09200SDave Airlie 	u32 pipea_stats, pipeb_stats;
238*c0e09200SDave Airlie 
239*c0e09200SDave Airlie 	pipea_stats = I915_READ(I915REG_PIPEASTAT);
240*c0e09200SDave Airlie 	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
241*c0e09200SDave Airlie 
242*c0e09200SDave Airlie 	temp = I915_READ16(I915REG_INT_IDENTITY_R);
243*c0e09200SDave Airlie 
244*c0e09200SDave Airlie 	temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
245*c0e09200SDave Airlie 
246*c0e09200SDave Airlie 	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
247*c0e09200SDave Airlie 
248*c0e09200SDave Airlie 	if (temp == 0)
249*c0e09200SDave Airlie 		return IRQ_NONE;
250*c0e09200SDave Airlie 
251*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
252*c0e09200SDave Airlie 	(void) I915_READ16(I915REG_INT_IDENTITY_R);
253*c0e09200SDave Airlie 	DRM_READMEMORYBARRIER();
254*c0e09200SDave Airlie 
255*c0e09200SDave Airlie 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
256*c0e09200SDave Airlie 
257*c0e09200SDave Airlie 	if (temp & USER_INT_FLAG)
258*c0e09200SDave Airlie 		DRM_WAKEUP(&dev_priv->irq_queue);
259*c0e09200SDave Airlie 
260*c0e09200SDave Airlie 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
261*c0e09200SDave Airlie 		int vblank_pipe = dev_priv->vblank_pipe;
262*c0e09200SDave Airlie 
263*c0e09200SDave Airlie 		if ((vblank_pipe &
264*c0e09200SDave Airlie 		     (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
265*c0e09200SDave Airlie 		    == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
266*c0e09200SDave Airlie 			if (temp & VSYNC_PIPEA_FLAG)
267*c0e09200SDave Airlie 				atomic_inc(&dev->vbl_received);
268*c0e09200SDave Airlie 			if (temp & VSYNC_PIPEB_FLAG)
269*c0e09200SDave Airlie 				atomic_inc(&dev->vbl_received2);
270*c0e09200SDave Airlie 		} else if (((temp & VSYNC_PIPEA_FLAG) &&
271*c0e09200SDave Airlie 			    (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
272*c0e09200SDave Airlie 			   ((temp & VSYNC_PIPEB_FLAG) &&
273*c0e09200SDave Airlie 			    (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
274*c0e09200SDave Airlie 			atomic_inc(&dev->vbl_received);
275*c0e09200SDave Airlie 
276*c0e09200SDave Airlie 		DRM_WAKEUP(&dev->vbl_queue);
277*c0e09200SDave Airlie 		drm_vbl_send_signals(dev);
278*c0e09200SDave Airlie 
279*c0e09200SDave Airlie 		if (dev_priv->swaps_pending > 0)
280*c0e09200SDave Airlie 			drm_locked_tasklet(dev, i915_vblank_tasklet);
281*c0e09200SDave Airlie 		I915_WRITE(I915REG_PIPEASTAT,
282*c0e09200SDave Airlie 			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
283*c0e09200SDave Airlie 			I915_VBLANK_CLEAR);
284*c0e09200SDave Airlie 		I915_WRITE(I915REG_PIPEBSTAT,
285*c0e09200SDave Airlie 			pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
286*c0e09200SDave Airlie 			I915_VBLANK_CLEAR);
287*c0e09200SDave Airlie 	}
288*c0e09200SDave Airlie 
289*c0e09200SDave Airlie 	return IRQ_HANDLED;
290*c0e09200SDave Airlie }
291*c0e09200SDave Airlie 
292*c0e09200SDave Airlie static int i915_emit_irq(struct drm_device * dev)
293*c0e09200SDave Airlie {
294*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
295*c0e09200SDave Airlie 	RING_LOCALS;
296*c0e09200SDave Airlie 
297*c0e09200SDave Airlie 	i915_kernel_lost_context(dev);
298*c0e09200SDave Airlie 
299*c0e09200SDave Airlie 	DRM_DEBUG("\n");
300*c0e09200SDave Airlie 
301*c0e09200SDave Airlie 	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
302*c0e09200SDave Airlie 
303*c0e09200SDave Airlie 	if (dev_priv->counter > 0x7FFFFFFFUL)
304*c0e09200SDave Airlie 		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
305*c0e09200SDave Airlie 
306*c0e09200SDave Airlie 	BEGIN_LP_RING(6);
307*c0e09200SDave Airlie 	OUT_RING(CMD_STORE_DWORD_IDX);
308*c0e09200SDave Airlie 	OUT_RING(20);
309*c0e09200SDave Airlie 	OUT_RING(dev_priv->counter);
310*c0e09200SDave Airlie 	OUT_RING(0);
311*c0e09200SDave Airlie 	OUT_RING(0);
312*c0e09200SDave Airlie 	OUT_RING(GFX_OP_USER_INTERRUPT);
313*c0e09200SDave Airlie 	ADVANCE_LP_RING();
314*c0e09200SDave Airlie 
315*c0e09200SDave Airlie 	return dev_priv->counter;
316*c0e09200SDave Airlie }
317*c0e09200SDave Airlie 
318*c0e09200SDave Airlie static int i915_wait_irq(struct drm_device * dev, int irq_nr)
319*c0e09200SDave Airlie {
320*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
321*c0e09200SDave Airlie 	int ret = 0;
322*c0e09200SDave Airlie 
323*c0e09200SDave Airlie 	DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
324*c0e09200SDave Airlie 		  READ_BREADCRUMB(dev_priv));
325*c0e09200SDave Airlie 
326*c0e09200SDave Airlie 	if (READ_BREADCRUMB(dev_priv) >= irq_nr)
327*c0e09200SDave Airlie 		return 0;
328*c0e09200SDave Airlie 
329*c0e09200SDave Airlie 	dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
330*c0e09200SDave Airlie 
331*c0e09200SDave Airlie 	DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
332*c0e09200SDave Airlie 		    READ_BREADCRUMB(dev_priv) >= irq_nr);
333*c0e09200SDave Airlie 
334*c0e09200SDave Airlie 	if (ret == -EBUSY) {
335*c0e09200SDave Airlie 		DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
336*c0e09200SDave Airlie 			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
337*c0e09200SDave Airlie 	}
338*c0e09200SDave Airlie 
339*c0e09200SDave Airlie 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
340*c0e09200SDave Airlie 	return ret;
341*c0e09200SDave Airlie }
342*c0e09200SDave Airlie 
343*c0e09200SDave Airlie static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
344*c0e09200SDave Airlie 				      atomic_t *counter)
345*c0e09200SDave Airlie {
346*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
347*c0e09200SDave Airlie 	unsigned int cur_vblank;
348*c0e09200SDave Airlie 	int ret = 0;
349*c0e09200SDave Airlie 
350*c0e09200SDave Airlie 	if (!dev_priv) {
351*c0e09200SDave Airlie 		DRM_ERROR("called with no initialization\n");
352*c0e09200SDave Airlie 		return -EINVAL;
353*c0e09200SDave Airlie 	}
354*c0e09200SDave Airlie 
355*c0e09200SDave Airlie 	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
356*c0e09200SDave Airlie 		    (((cur_vblank = atomic_read(counter))
357*c0e09200SDave Airlie 			- *sequence) <= (1<<23)));
358*c0e09200SDave Airlie 
359*c0e09200SDave Airlie 	*sequence = cur_vblank;
360*c0e09200SDave Airlie 
361*c0e09200SDave Airlie 	return ret;
362*c0e09200SDave Airlie }
363*c0e09200SDave Airlie 
364*c0e09200SDave Airlie 
365*c0e09200SDave Airlie int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
366*c0e09200SDave Airlie {
367*c0e09200SDave Airlie 	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
368*c0e09200SDave Airlie }
369*c0e09200SDave Airlie 
370*c0e09200SDave Airlie int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
371*c0e09200SDave Airlie {
372*c0e09200SDave Airlie 	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
373*c0e09200SDave Airlie }
374*c0e09200SDave Airlie 
375*c0e09200SDave Airlie /* Needs the lock as it touches the ring.
376*c0e09200SDave Airlie  */
377*c0e09200SDave Airlie int i915_irq_emit(struct drm_device *dev, void *data,
378*c0e09200SDave Airlie 			 struct drm_file *file_priv)
379*c0e09200SDave Airlie {
380*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
381*c0e09200SDave Airlie 	drm_i915_irq_emit_t *emit = data;
382*c0e09200SDave Airlie 	int result;
383*c0e09200SDave Airlie 
384*c0e09200SDave Airlie 	LOCK_TEST_WITH_RETURN(dev, file_priv);
385*c0e09200SDave Airlie 
386*c0e09200SDave Airlie 	if (!dev_priv) {
387*c0e09200SDave Airlie 		DRM_ERROR("called with no initialization\n");
388*c0e09200SDave Airlie 		return -EINVAL;
389*c0e09200SDave Airlie 	}
390*c0e09200SDave Airlie 
391*c0e09200SDave Airlie 	result = i915_emit_irq(dev);
392*c0e09200SDave Airlie 
393*c0e09200SDave Airlie 	if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
394*c0e09200SDave Airlie 		DRM_ERROR("copy_to_user\n");
395*c0e09200SDave Airlie 		return -EFAULT;
396*c0e09200SDave Airlie 	}
397*c0e09200SDave Airlie 
398*c0e09200SDave Airlie 	return 0;
399*c0e09200SDave Airlie }
400*c0e09200SDave Airlie 
401*c0e09200SDave Airlie /* Doesn't need the hardware lock.
402*c0e09200SDave Airlie  */
403*c0e09200SDave Airlie int i915_irq_wait(struct drm_device *dev, void *data,
404*c0e09200SDave Airlie 			 struct drm_file *file_priv)
405*c0e09200SDave Airlie {
406*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
407*c0e09200SDave Airlie 	drm_i915_irq_wait_t *irqwait = data;
408*c0e09200SDave Airlie 
409*c0e09200SDave Airlie 	if (!dev_priv) {
410*c0e09200SDave Airlie 		DRM_ERROR("called with no initialization\n");
411*c0e09200SDave Airlie 		return -EINVAL;
412*c0e09200SDave Airlie 	}
413*c0e09200SDave Airlie 
414*c0e09200SDave Airlie 	return i915_wait_irq(dev, irqwait->irq_seq);
415*c0e09200SDave Airlie }
416*c0e09200SDave Airlie 
417*c0e09200SDave Airlie static void i915_enable_interrupt (struct drm_device *dev)
418*c0e09200SDave Airlie {
419*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
420*c0e09200SDave Airlie 	u16 flag;
421*c0e09200SDave Airlie 
422*c0e09200SDave Airlie 	flag = 0;
423*c0e09200SDave Airlie 	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
424*c0e09200SDave Airlie 		flag |= VSYNC_PIPEA_FLAG;
425*c0e09200SDave Airlie 	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
426*c0e09200SDave Airlie 		flag |= VSYNC_PIPEB_FLAG;
427*c0e09200SDave Airlie 
428*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
429*c0e09200SDave Airlie }
430*c0e09200SDave Airlie 
431*c0e09200SDave Airlie /* Set the vblank monitor pipe
432*c0e09200SDave Airlie  */
433*c0e09200SDave Airlie int i915_vblank_pipe_set(struct drm_device *dev, void *data,
434*c0e09200SDave Airlie 			 struct drm_file *file_priv)
435*c0e09200SDave Airlie {
436*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
437*c0e09200SDave Airlie 	drm_i915_vblank_pipe_t *pipe = data;
438*c0e09200SDave Airlie 
439*c0e09200SDave Airlie 	if (!dev_priv) {
440*c0e09200SDave Airlie 		DRM_ERROR("called with no initialization\n");
441*c0e09200SDave Airlie 		return -EINVAL;
442*c0e09200SDave Airlie 	}
443*c0e09200SDave Airlie 
444*c0e09200SDave Airlie 	if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
445*c0e09200SDave Airlie 		DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
446*c0e09200SDave Airlie 		return -EINVAL;
447*c0e09200SDave Airlie 	}
448*c0e09200SDave Airlie 
449*c0e09200SDave Airlie 	dev_priv->vblank_pipe = pipe->pipe;
450*c0e09200SDave Airlie 
451*c0e09200SDave Airlie 	i915_enable_interrupt (dev);
452*c0e09200SDave Airlie 
453*c0e09200SDave Airlie 	return 0;
454*c0e09200SDave Airlie }
455*c0e09200SDave Airlie 
456*c0e09200SDave Airlie int i915_vblank_pipe_get(struct drm_device *dev, void *data,
457*c0e09200SDave Airlie 			 struct drm_file *file_priv)
458*c0e09200SDave Airlie {
459*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
460*c0e09200SDave Airlie 	drm_i915_vblank_pipe_t *pipe = data;
461*c0e09200SDave Airlie 	u16 flag;
462*c0e09200SDave Airlie 
463*c0e09200SDave Airlie 	if (!dev_priv) {
464*c0e09200SDave Airlie 		DRM_ERROR("called with no initialization\n");
465*c0e09200SDave Airlie 		return -EINVAL;
466*c0e09200SDave Airlie 	}
467*c0e09200SDave Airlie 
468*c0e09200SDave Airlie 	flag = I915_READ(I915REG_INT_ENABLE_R);
469*c0e09200SDave Airlie 	pipe->pipe = 0;
470*c0e09200SDave Airlie 	if (flag & VSYNC_PIPEA_FLAG)
471*c0e09200SDave Airlie 		pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
472*c0e09200SDave Airlie 	if (flag & VSYNC_PIPEB_FLAG)
473*c0e09200SDave Airlie 		pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
474*c0e09200SDave Airlie 
475*c0e09200SDave Airlie 	return 0;
476*c0e09200SDave Airlie }
477*c0e09200SDave Airlie 
478*c0e09200SDave Airlie /**
479*c0e09200SDave Airlie  * Schedule buffer swap at given vertical blank.
480*c0e09200SDave Airlie  */
481*c0e09200SDave Airlie int i915_vblank_swap(struct drm_device *dev, void *data,
482*c0e09200SDave Airlie 		     struct drm_file *file_priv)
483*c0e09200SDave Airlie {
484*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = dev->dev_private;
485*c0e09200SDave Airlie 	drm_i915_vblank_swap_t *swap = data;
486*c0e09200SDave Airlie 	drm_i915_vbl_swap_t *vbl_swap;
487*c0e09200SDave Airlie 	unsigned int pipe, seqtype, curseq;
488*c0e09200SDave Airlie 	unsigned long irqflags;
489*c0e09200SDave Airlie 	struct list_head *list;
490*c0e09200SDave Airlie 
491*c0e09200SDave Airlie 	if (!dev_priv) {
492*c0e09200SDave Airlie 		DRM_ERROR("%s called with no initialization\n", __func__);
493*c0e09200SDave Airlie 		return -EINVAL;
494*c0e09200SDave Airlie 	}
495*c0e09200SDave Airlie 
496*c0e09200SDave Airlie 	if (dev_priv->sarea_priv->rotation) {
497*c0e09200SDave Airlie 		DRM_DEBUG("Rotation not supported\n");
498*c0e09200SDave Airlie 		return -EINVAL;
499*c0e09200SDave Airlie 	}
500*c0e09200SDave Airlie 
501*c0e09200SDave Airlie 	if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
502*c0e09200SDave Airlie 			     _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
503*c0e09200SDave Airlie 		DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
504*c0e09200SDave Airlie 		return -EINVAL;
505*c0e09200SDave Airlie 	}
506*c0e09200SDave Airlie 
507*c0e09200SDave Airlie 	pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
508*c0e09200SDave Airlie 
509*c0e09200SDave Airlie 	seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
510*c0e09200SDave Airlie 
511*c0e09200SDave Airlie 	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
512*c0e09200SDave Airlie 		DRM_ERROR("Invalid pipe %d\n", pipe);
513*c0e09200SDave Airlie 		return -EINVAL;
514*c0e09200SDave Airlie 	}
515*c0e09200SDave Airlie 
516*c0e09200SDave Airlie 	spin_lock_irqsave(&dev->drw_lock, irqflags);
517*c0e09200SDave Airlie 
518*c0e09200SDave Airlie 	if (!drm_get_drawable_info(dev, swap->drawable)) {
519*c0e09200SDave Airlie 		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
520*c0e09200SDave Airlie 		DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
521*c0e09200SDave Airlie 		return -EINVAL;
522*c0e09200SDave Airlie 	}
523*c0e09200SDave Airlie 
524*c0e09200SDave Airlie 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
525*c0e09200SDave Airlie 
526*c0e09200SDave Airlie 	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
527*c0e09200SDave Airlie 
528*c0e09200SDave Airlie 	if (seqtype == _DRM_VBLANK_RELATIVE)
529*c0e09200SDave Airlie 		swap->sequence += curseq;
530*c0e09200SDave Airlie 
531*c0e09200SDave Airlie 	if ((curseq - swap->sequence) <= (1<<23)) {
532*c0e09200SDave Airlie 		if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
533*c0e09200SDave Airlie 			swap->sequence = curseq + 1;
534*c0e09200SDave Airlie 		} else {
535*c0e09200SDave Airlie 			DRM_DEBUG("Missed target sequence\n");
536*c0e09200SDave Airlie 			return -EINVAL;
537*c0e09200SDave Airlie 		}
538*c0e09200SDave Airlie 	}
539*c0e09200SDave Airlie 
540*c0e09200SDave Airlie 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
541*c0e09200SDave Airlie 
542*c0e09200SDave Airlie 	list_for_each(list, &dev_priv->vbl_swaps.head) {
543*c0e09200SDave Airlie 		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
544*c0e09200SDave Airlie 
545*c0e09200SDave Airlie 		if (vbl_swap->drw_id == swap->drawable &&
546*c0e09200SDave Airlie 		    vbl_swap->pipe == pipe &&
547*c0e09200SDave Airlie 		    vbl_swap->sequence == swap->sequence) {
548*c0e09200SDave Airlie 			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
549*c0e09200SDave Airlie 			DRM_DEBUG("Already scheduled\n");
550*c0e09200SDave Airlie 			return 0;
551*c0e09200SDave Airlie 		}
552*c0e09200SDave Airlie 	}
553*c0e09200SDave Airlie 
554*c0e09200SDave Airlie 	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
555*c0e09200SDave Airlie 
556*c0e09200SDave Airlie 	if (dev_priv->swaps_pending >= 100) {
557*c0e09200SDave Airlie 		DRM_DEBUG("Too many swaps queued\n");
558*c0e09200SDave Airlie 		return -EBUSY;
559*c0e09200SDave Airlie 	}
560*c0e09200SDave Airlie 
561*c0e09200SDave Airlie 	vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
562*c0e09200SDave Airlie 
563*c0e09200SDave Airlie 	if (!vbl_swap) {
564*c0e09200SDave Airlie 		DRM_ERROR("Failed to allocate memory to queue swap\n");
565*c0e09200SDave Airlie 		return -ENOMEM;
566*c0e09200SDave Airlie 	}
567*c0e09200SDave Airlie 
568*c0e09200SDave Airlie 	DRM_DEBUG("\n");
569*c0e09200SDave Airlie 
570*c0e09200SDave Airlie 	vbl_swap->drw_id = swap->drawable;
571*c0e09200SDave Airlie 	vbl_swap->pipe = pipe;
572*c0e09200SDave Airlie 	vbl_swap->sequence = swap->sequence;
573*c0e09200SDave Airlie 
574*c0e09200SDave Airlie 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
575*c0e09200SDave Airlie 
576*c0e09200SDave Airlie 	list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
577*c0e09200SDave Airlie 	dev_priv->swaps_pending++;
578*c0e09200SDave Airlie 
579*c0e09200SDave Airlie 	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
580*c0e09200SDave Airlie 
581*c0e09200SDave Airlie 	return 0;
582*c0e09200SDave Airlie }
583*c0e09200SDave Airlie 
584*c0e09200SDave Airlie /* drm_dma.h hooks
585*c0e09200SDave Airlie */
586*c0e09200SDave Airlie void i915_driver_irq_preinstall(struct drm_device * dev)
587*c0e09200SDave Airlie {
588*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
589*c0e09200SDave Airlie 
590*c0e09200SDave Airlie 	I915_WRITE16(I915REG_HWSTAM, 0xfffe);
591*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_MASK_R, 0x0);
592*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
593*c0e09200SDave Airlie }
594*c0e09200SDave Airlie 
595*c0e09200SDave Airlie void i915_driver_irq_postinstall(struct drm_device * dev)
596*c0e09200SDave Airlie {
597*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
598*c0e09200SDave Airlie 
599*c0e09200SDave Airlie 	spin_lock_init(&dev_priv->swaps_lock);
600*c0e09200SDave Airlie 	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
601*c0e09200SDave Airlie 	dev_priv->swaps_pending = 0;
602*c0e09200SDave Airlie 
603*c0e09200SDave Airlie 	if (!dev_priv->vblank_pipe)
604*c0e09200SDave Airlie 		dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
605*c0e09200SDave Airlie 	i915_enable_interrupt(dev);
606*c0e09200SDave Airlie 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
607*c0e09200SDave Airlie }
608*c0e09200SDave Airlie 
609*c0e09200SDave Airlie void i915_driver_irq_uninstall(struct drm_device * dev)
610*c0e09200SDave Airlie {
611*c0e09200SDave Airlie 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
612*c0e09200SDave Airlie 	u16 temp;
613*c0e09200SDave Airlie 
614*c0e09200SDave Airlie 	if (!dev_priv)
615*c0e09200SDave Airlie 		return;
616*c0e09200SDave Airlie 
617*c0e09200SDave Airlie 	I915_WRITE16(I915REG_HWSTAM, 0xffff);
618*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
619*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
620*c0e09200SDave Airlie 
621*c0e09200SDave Airlie 	temp = I915_READ16(I915REG_INT_IDENTITY_R);
622*c0e09200SDave Airlie 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
623*c0e09200SDave Airlie }
624