2 * Copyright 2007 Dave Airlie.
3 * Copyright 2007 Jérôme Glisse
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 * Jerome Glisse <glisse@freedesktop.org>
29 #include "radeon_ms.h"
30 #include "amd_legacy_fence.h"
32 #define R3XX_FENCE_SEQUENCE_RW_FLUSH 0x80000000u
34 static inline int r3xx_fence_emit_sequence(struct drm_device *dev,
35 struct drm_radeon_private *dev_priv,
38 struct legacy_fence *r3xx_fence = dev_priv->fence;
42 if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) {
43 r3xx_fence->sequence_last_flush =
44 sequence & ~R3XX_FENCE_SEQUENCE_RW_FLUSH;
45 /* Ask flush for VERTEX & FRAGPROG pipeline
47 dev_priv->flush_cache(dev);
49 cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0);
51 for (i = 0; i < dev_priv->usec_timeout; i++) {
52 r = radeon_ms_ring_emit(dev, cmd, 2);
54 dev_priv->irq_emit(dev);
61 static inline uint32_t r3xx_fence_sequence(struct legacy_fence *r3xx_fence)
63 r3xx_fence->sequence += 1;
64 if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) {
65 r3xx_fence->sequence = 1;
67 return r3xx_fence->sequence;
70 static inline void r3xx_fence_report(struct drm_device *dev,
71 struct drm_radeon_private *dev_priv,
72 struct legacy_fence *r3xx_fence)
74 uint32_t fence_types = DRM_FENCE_TYPE_EXE;
77 if (dev_priv == NULL) {
80 sequence = mmio_read(dev_priv, dev_priv->fence_reg);
81 if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) {
82 sequence &= ~R3XX_FENCE_SEQUENCE_RW_FLUSH;
83 fence_types |= DRM_RADEON_FENCE_TYPE_RW;
84 if (sequence == r3xx_fence->sequence_last_flush) {
85 r3xx_fence->sequence_last_flush = 0;
88 /* avoid to report already reported sequence */
89 if (sequence != r3xx_fence->sequence_last_reported) {
90 drm_fence_handler(dev, 0, sequence, fence_types, 0);
91 r3xx_fence->sequence_last_reported = sequence;
95 static void r3xx_fence_flush(struct drm_device *dev, uint32_t class)
97 struct drm_radeon_private *dev_priv = dev->dev_private;
98 struct legacy_fence *r3xx_fence = dev_priv->fence;
101 sequence = r3xx_fence_sequence(r3xx_fence);
102 sequence |= R3XX_FENCE_SEQUENCE_RW_FLUSH;
103 r3xx_fence_emit_sequence(dev, dev_priv, sequence);
106 static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class,
107 uint32_t waiting_types)
109 struct drm_radeon_private *dev_priv = dev->dev_private;
110 struct drm_fence_manager *fm = &dev->fm;
111 struct drm_fence_class_manager *fc = &fm->fence_class[fence_class];
112 struct legacy_fence *r3xx_fence = dev_priv->fence;
114 if (unlikely(!dev_priv)) {
117 /* if there is a RW flush pending then submit new sequence
118 * preceded by flush cmds */
119 if (fc->pending_flush & DRM_RADEON_FENCE_TYPE_RW) {
120 r3xx_fence_flush(dev, 0);
121 fc->pending_flush &= ~DRM_RADEON_FENCE_TYPE_RW;
123 r3xx_fence_report(dev, dev_priv, r3xx_fence);
127 static int r3xx_fence_emit(struct drm_device *dev, uint32_t class,
128 uint32_t flags, uint32_t *sequence,
129 uint32_t *native_type)
131 struct drm_radeon_private *dev_priv = dev->dev_private;
132 struct legacy_fence *r3xx_fence = dev_priv->fence;
135 if (!dev_priv || dev_priv->cp_ready != 1) {
138 *sequence = tmp = r3xx_fence_sequence(r3xx_fence);
139 *native_type = DRM_FENCE_TYPE_EXE;
140 if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) {
141 *native_type |= DRM_RADEON_FENCE_TYPE_RW;
142 tmp |= R3XX_FENCE_SEQUENCE_RW_FLUSH;
144 return r3xx_fence_emit_sequence(dev, dev_priv, tmp);
147 static int r3xx_fence_has_irq(struct drm_device *dev,
148 uint32_t class, uint32_t type)
150 const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE |
151 DRM_RADEON_FENCE_TYPE_RW;
153 * We have an irq for EXE & RW fence.
155 if (class == 0 && (type & type_irq_mask)) {
161 static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence)
163 struct drm_device *dev = fence->dev;
164 struct drm_radeon_private *dev_priv = dev->dev_private;
165 struct legacy_fence *r3xx_fence = dev_priv->fence;
166 struct drm_fence_driver *driver = dev->driver->fence_driver;
167 uint32_t flush_types, diff;
169 flush_types = fence->waiting_types &
170 ~(DRM_FENCE_TYPE_EXE | fence->signaled_types);
172 if (flush_types == 0 || ((flush_types & ~fence->native_types) == 0)) {
175 if (unlikely(dev_priv == NULL)) {
178 if (r3xx_fence->sequence_last_flush) {
179 diff = (r3xx_fence->sequence_last_flush - fence->sequence) &
180 driver->sequence_mask;
181 if (diff < driver->wrap_diff) {
188 static int r3xx_fence_wait(struct drm_fence_object *fence,
189 int lazy, int interruptible, uint32_t mask)
191 struct drm_device *dev = fence->dev;
192 struct drm_fence_manager *fm = &dev->fm;
193 struct drm_fence_class_manager *fc = &fm->fence_class[0];
196 drm_fence_object_flush(fence, mask);
197 if (likely(interruptible)) {
198 r = wait_event_interruptible_timeout(
200 drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
203 r = wait_event_timeout(
205 drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE),
208 if (unlikely(r == -ERESTARTSYS)) {
211 if (unlikely(r == 0)) {
215 if (likely(mask == DRM_FENCE_TYPE_EXE ||
216 drm_fence_object_signaled(fence, mask))) {
221 * Poll for sync flush completion.
223 return drm_fence_wait_polling(fence, lazy, interruptible,
227 struct drm_fence_driver r3xx_fence_driver = {
229 .wrap_diff = (1 << 29),
230 .flush_diff = (1 << 28),
231 .sequence_mask = 0x7fffffffU,
232 .has_irq = r3xx_fence_has_irq,
233 .emit = r3xx_fence_emit,
234 .flush = r3xx_fence_flush,
235 .poll = r3xx_fence_poll,
236 .needed_flush = r3xx_fence_needed_flush,
237 .wait = r3xx_fence_wait,
240 /* this are used by the buffer object code */
241 int r3xx_fence_types(struct drm_buffer_object *bo,
242 uint32_t *class, uint32_t *type)
245 if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) {
246 *type = DRM_FENCE_TYPE_EXE | DRM_RADEON_FENCE_TYPE_RW;
248 *type = DRM_FENCE_TYPE_EXE;
253 /* this are used by the irq code */
254 void r3xx_fence_handler(struct drm_device * dev)
256 struct drm_radeon_private *dev_priv = dev->dev_private;
257 struct drm_fence_manager *fm = &dev->fm;
258 struct drm_fence_class_manager *fc = &fm->fence_class[0];
260 if (unlikely(dev_priv == NULL)) {
264 write_lock(&fm->lock);
265 r3xx_fence_poll(dev, 0, fc->waiting_types);
266 write_unlock(&fm->lock);