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 inline 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(INSTPM, (1 << 5) | (1 << 21));
50 dev_priv->flush_pending = 1;
51 fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW;
55 static inline void i915_report_rwflush(struct drm_device *dev,
56 struct drm_i915_private *dev_priv)
58 if (unlikely(dev_priv->flush_pending)) {
62 uint32_t flush_sequence;
64 i_status = READ_HWSP(dev_priv, 0);
65 if ((i_status & (1 << 12)) !=
66 (dev_priv->saved_flush_status & (1 << 12))) {
67 flush_flags = dev_priv->flush_flags;
68 flush_sequence = dev_priv->flush_sequence;
69 dev_priv->flush_pending = 0;
70 drm_fence_handler(dev, 0, flush_sequence,
76 static void i915_fence_flush(struct drm_device *dev,
79 struct drm_i915_private *dev_priv =
80 (struct drm_i915_private *) dev->dev_private;
81 struct drm_fence_manager *fm = &dev->fm;
82 struct drm_fence_class_manager *fc = &fm->fence_class[0];
83 unsigned long irq_flags;
85 if (unlikely(!dev_priv))
88 write_lock_irqsave(&fm->lock, irq_flags);
89 i915_initiate_rwflush(dev_priv, fc);
90 write_unlock_irqrestore(&fm->lock, irq_flags);
94 static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class,
95 uint32_t waiting_types)
97 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
98 struct drm_fence_manager *fm = &dev->fm;
99 struct drm_fence_class_manager *fc = &fm->fence_class[0];
102 if (unlikely(!dev_priv))
106 * First, report any executed sync flush:
109 i915_report_rwflush(dev, dev_priv);
112 * Report A new breadcrumb, and adjust IRQs.
115 if (waiting_types & DRM_FENCE_TYPE_EXE) {
117 sequence = READ_BREADCRUMB(dev_priv);
118 drm_fence_handler(dev, 0, sequence,
119 DRM_FENCE_TYPE_EXE, 0);
121 if (dev_priv->fence_irq_on &&
122 !(fc->waiting_types & DRM_FENCE_TYPE_EXE)) {
123 i915_user_irq_off(dev);
124 dev_priv->fence_irq_on = 0;
125 } else if (!dev_priv->fence_irq_on &&
126 (fc->waiting_types & DRM_FENCE_TYPE_EXE)) {
127 i915_user_irq_on(dev);
128 dev_priv->fence_irq_on = 1;
133 * There may be new RW flushes pending. Start them.
136 i915_initiate_rwflush(dev_priv, fc);
139 * And possibly, but unlikely, they finish immediately.
142 i915_report_rwflush(dev, dev_priv);
146 static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class,
147 uint32_t flags, uint32_t *sequence,
148 uint32_t *native_type)
150 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
151 if (unlikely(!dev_priv))
155 *sequence = (uint32_t) dev_priv->counter;
156 *native_type = DRM_FENCE_TYPE_EXE;
157 if (flags & DRM_I915_FENCE_FLAG_FLUSHED)
158 *native_type |= DRM_I915_FENCE_TYPE_RW;
163 void i915_fence_handler(struct drm_device *dev)
165 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
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 if (likely(dev_priv->fence_irq_on))
171 i915_fence_poll(dev, 0, fc->waiting_types);
172 write_unlock(&fm->lock);
176 * We need a separate wait function since we need to poll for
180 static int i915_fence_wait(struct drm_fence_object *fence,
181 int lazy, int interruptible, uint32_t mask)
183 struct drm_device *dev = fence->dev;
184 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
185 struct drm_fence_manager *fm = &dev->fm;
186 struct drm_fence_class_manager *fc = &fm->fence_class[0];
188 unsigned long _end = jiffies + 3 * DRM_HZ;
190 drm_fence_object_flush(fence, mask);
191 if (likely(interruptible))
192 ret = wait_event_interruptible_timeout
193 (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
196 ret = wait_event_timeout
197 (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
200 if (unlikely(ret == -ERESTARTSYS))
203 if (unlikely(ret == 0))
206 if (likely(mask == DRM_FENCE_TYPE_EXE ||
207 drm_fence_object_signaled(fence, mask)))
211 * Remove this code snippet when fixed. HWSTAM doesn't let
212 * flush info through...
215 if (unlikely(dev_priv && !dev_priv->irq_enabled)) {
216 unsigned long irq_flags;
218 DRM_ERROR("X server disabled IRQs before releasing frame buffer.\n");
220 dev_priv->flush_pending = 0;
221 write_lock_irqsave(&fm->lock, irq_flags);
222 drm_fence_handler(dev, fence->fence_class,
223 fence->sequence, fence->type, 0);
224 write_unlock_irqrestore(&fm->lock, irq_flags);
228 * Poll for sync flush completion.
231 return drm_fence_wait_polling(fence, lazy, interruptible, mask, _end);
234 static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence)
236 uint32_t flush_flags = fence->waiting_types &
237 ~(DRM_FENCE_TYPE_EXE | fence->signaled_types);
239 if (likely(flush_flags == 0 ||
240 ((flush_flags & ~fence->native_types) == 0) ||
241 (fence->signaled_types != DRM_FENCE_TYPE_EXE)))
244 struct drm_device *dev = fence->dev;
245 struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
246 struct drm_fence_driver *driver = dev->driver->fence_driver;
248 if (unlikely(!dev_priv))
251 if (dev_priv->flush_pending) {
252 uint32_t diff = (dev_priv->flush_sequence - fence->sequence) &
253 driver->sequence_mask;
255 if (diff < driver->wrap_diff)
262 struct drm_fence_driver i915_fence_driver = {
264 .wrap_diff = (1U << (BREADCRUMB_BITS - 1)),
265 .flush_diff = (1U << (BREADCRUMB_BITS - 2)),
266 .sequence_mask = BREADCRUMB_MASK,
268 .emit = i915_fence_emit_sequence,
269 .flush = i915_fence_flush,
270 .poll = i915_fence_poll,
271 .needed_flush = i915_fence_needed_flush,
272 .wait = i915_fence_wait,