1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
27 **************************************************************************/
29 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
38 * Initiate a sync flush if it's not already pending.
41 static void i915_initiate_rwflush(struct drm_i915_private *dev_priv,
42 struct drm_fence_class_manager *fc)
44 if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) &&
45 !dev_priv->flush_pending) {
46 dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv);
47 dev_priv->flush_flags = fc->pending_flush;
48 dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0);
49 I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
50 dev_priv->flush_pending = 1;
51 fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW;
55 static void i915_fence_flush(struct drm_device *dev,
58 struct drm_i915_private *dev_priv =
59 (struct drm_i915_private *) dev->dev_private;
60 struct drm_fence_manager *fm = &dev->fm;
61 struct drm_fence_class_manager *fc = &fm->fence_class[0];
62 unsigned long irq_flags;
64 if (unlikely(!dev_priv))
67 write_lock_irqsave(&fm->lock, irq_flags);
68 i915_initiate_rwflush(dev_priv, fc);
69 write_unlock_irqrestore(&fm->lock, irq_flags);
72 static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class,
73 uint32_t waiting_types)
75 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
76 struct drm_fence_manager *fm = &dev->fm;
77 struct drm_fence_class_manager *fc = &fm->fence_class[0];
78 uint32_t flush_flags = 0;
79 uint32_t flush_sequence = 0;
83 if (unlikely(!dev_priv))
87 * First, report any executed sync flush:
90 if (dev_priv->flush_pending) {
91 i_status = READ_HWSP(dev_priv, 0);
92 if ((i_status & (1 << 12)) !=
93 (dev_priv->saved_flush_status & (1 << 12))) {
94 flush_flags = dev_priv->flush_flags;
95 flush_sequence = dev_priv->flush_sequence;
96 dev_priv->flush_pending = 0;
97 drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0);
102 * Report A new breadcrumb, and adjust IRQs.
105 if (waiting_types & DRM_FENCE_TYPE_EXE) {
106 sequence = READ_BREADCRUMB(dev_priv);
108 if (sequence != dev_priv->reported_sequence ||
109 !dev_priv->reported_sequence_valid) {
110 drm_fence_handler(dev, 0, sequence,
111 DRM_FENCE_TYPE_EXE, 0);
112 dev_priv->reported_sequence = sequence;
113 dev_priv->reported_sequence_valid = 1;
116 if (dev_priv->fence_irq_on && !(waiting_types & DRM_FENCE_TYPE_EXE)) {
117 i915_user_irq_off(dev_priv);
118 dev_priv->fence_irq_on = 0;
119 } else if (!dev_priv->fence_irq_on && (waiting_types & DRM_FENCE_TYPE_EXE)) {
120 i915_user_irq_on(dev_priv);
121 dev_priv->fence_irq_on = 1;
126 * There may be new RW flushes pending. Start them.
129 i915_initiate_rwflush(dev_priv, fc);
132 * And possibly, but unlikely, they finish immediately.
135 if (dev_priv->flush_pending) {
136 i_status = READ_HWSP(dev_priv, 0);
137 if (unlikely((i_status & (1 << 12)) !=
138 (dev_priv->saved_flush_status & (1 << 12)))) {
139 flush_flags = dev_priv->flush_flags;
140 flush_sequence = dev_priv->flush_sequence;
141 dev_priv->flush_pending = 0;
142 drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0);
147 static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class,
148 uint32_t flags, uint32_t *sequence,
149 uint32_t *native_type)
151 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
152 if (unlikely(!dev_priv))
156 *sequence = (uint32_t) dev_priv->counter;
157 *native_type = DRM_FENCE_TYPE_EXE;
158 if (flags & DRM_I915_FENCE_FLAG_FLUSHED)
159 *native_type |= DRM_I915_FENCE_TYPE_RW;
164 void i915_fence_handler(struct drm_device *dev)
166 struct drm_fence_manager *fm = &dev->fm;
167 struct drm_fence_class_manager *fc = &fm->fence_class[0];
169 write_lock(&fm->lock);
170 i915_fence_poll(dev, 0, fc->waiting_types);
171 write_unlock(&fm->lock);
175 * We need a separate wait function since we need to poll for
179 static int i915_fence_wait(struct drm_fence_object *fence,
180 int lazy, int interruptible, uint32_t mask)
182 struct drm_device *dev = fence->dev;
183 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
184 struct drm_fence_manager *fm = &dev->fm;
185 struct drm_fence_class_manager *fc = &fm->fence_class[0];
187 unsigned long _end = jiffies + 3 * DRM_HZ;
189 drm_fence_object_flush(fence, mask);
190 if (likely(interruptible))
191 ret = wait_event_interruptible_timeout
192 (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
195 ret = wait_event_timeout
196 (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
199 if (unlikely(ret == -ERESTARTSYS))
202 if (unlikely(ret == 0))
205 if (likely(mask == DRM_FENCE_TYPE_EXE ||
206 drm_fence_object_signaled(fence, mask)))
210 * Remove this code snippet when fixed. HWSTAM doesn't let
211 * flush info through...
214 if (unlikely(dev_priv && !dev_priv->irq_enabled)) {
215 unsigned long irq_flags;
217 DRM_ERROR("X server disabled IRQs before releasing frame buffer.\n");
219 dev_priv->flush_pending = 0;
220 write_lock_irqsave(&fm->lock, irq_flags);
221 drm_fence_handler(dev, fence->fence_class,
222 fence->sequence, fence->type, 0);
223 write_unlock_irqrestore(&fm->lock, irq_flags);
227 * Poll for sync flush completion.
230 return drm_fence_wait_polling(fence, lazy, interruptible, mask, _end);
233 static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence)
235 uint32_t flush_flags = fence->waiting_types &
236 ~(DRM_FENCE_TYPE_EXE | fence->signaled_types);
238 if (likely(flush_flags == 0 ||
239 ((flush_flags & ~fence->native_types) == 0) ||
240 (fence->signaled_types != DRM_FENCE_TYPE_EXE)))
243 struct drm_device *dev = fence->dev;
244 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
245 struct drm_fence_driver *driver = dev->driver->fence_driver;
247 if (unlikely(!dev_priv))
250 if (dev_priv->flush_pending) {
251 uint32_t diff = (dev_priv->flush_sequence - fence->sequence) &
252 driver->sequence_mask;
254 if (diff < driver->wrap_diff)
262 * In the very unlikely event that "poll" is not really called very often
263 * we need the following function to handle sequence wraparounds.
266 void i915_invalidate_reported_sequence(struct drm_device *dev)
268 struct drm_i915_private *dev_priv = (struct drm_i915_private *)
270 struct drm_fence_manager *fm = &dev->fm;
271 unsigned long irq_flags;
273 if (unlikely(!dev_priv))
276 write_lock_irqsave(&fm->lock, irq_flags);
277 dev_priv->reported_sequence_valid = 0;
278 write_unlock_irqrestore(&fm->lock, irq_flags);
282 struct drm_fence_driver i915_fence_driver = {
284 .wrap_diff = (1U << (BREADCRUMB_BITS - 1)),
285 .flush_diff = (1U << (BREADCRUMB_BITS - 2)),
286 .sequence_mask = BREADCRUMB_MASK,
288 .emit = i915_fence_emit_sequence,
289 .flush = i915_fence_flush,
290 .poll = i915_fence_poll,
291 .needed_flush = i915_fence_needed_flush,
292 .wait = i915_fence_wait,