radeon_ms: fix fence
[platform/upstream/libdrm.git] / shared-core / radeon_ms_fence.c
1 /*
2  * Copyright 2007 Dave Airlie.
3  * Copyright 2007 Jérôme Glisse
4  * All Rights Reserved.
5  *
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:
12  *
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
15  * Software.
16  *
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.
24  *
25  * Authors:
26  *    Dave Airlie
27  *    Jerome Glisse <glisse@freedesktop.org>
28  */
29 #include "radeon_ms.h"
30 #include "amd_legacy_fence.h"
31
32 #define R3XX_FENCE_SEQUENCE_RW_FLUSH    0x80000000u
33
34 static inline int r3xx_fence_emit_sequence(struct drm_device *dev,
35                                            struct drm_radeon_private *dev_priv,
36                                            uint32_t sequence)
37 {
38         struct legacy_fence *r3xx_fence = dev_priv->fence;
39         uint32_t cmd[2];
40         int i, r;
41
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
46                  * have 3D idle  */
47                 dev_priv->flush_cache(dev);
48         }
49         cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0);
50         cmd[1] = sequence;
51         for (i = 0; i < dev_priv->usec_timeout; i++) {
52                 r = radeon_ms_ring_emit(dev, cmd, 2);
53                 if (!r) {
54                         dev_priv->irq_emit(dev);
55                         return 0;
56                 }
57         }
58         return -EBUSY;
59 }
60
61 static inline uint32_t r3xx_fence_sequence(struct legacy_fence *r3xx_fence)
62 {
63         r3xx_fence->sequence += 1;
64         if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) {
65                 r3xx_fence->sequence = 1;
66         }
67         return r3xx_fence->sequence;
68 }
69
70 static inline void r3xx_fence_report(struct drm_device *dev,
71                                      struct drm_radeon_private *dev_priv,
72                                      struct legacy_fence *r3xx_fence)
73 {
74         uint32_t fence_types = DRM_FENCE_TYPE_EXE;
75         uint32_t sequence;
76
77         if (dev_priv == NULL) {
78                 return;
79         }
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;
86                 }
87         }
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;
92         }
93 }
94
95 static void r3xx_fence_flush(struct drm_device *dev, uint32_t class)
96 {
97         struct drm_radeon_private *dev_priv = dev->dev_private;
98         struct legacy_fence *r3xx_fence = dev_priv->fence;
99         uint32_t sequence;
100
101         sequence = r3xx_fence_sequence(r3xx_fence);
102         sequence |= R3XX_FENCE_SEQUENCE_RW_FLUSH;
103         r3xx_fence_emit_sequence(dev, dev_priv, sequence);
104 }
105
106 static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class,
107                             uint32_t waiting_types)
108 {
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;
113
114         if (unlikely(!dev_priv)) {
115                 return;
116         }
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;
122         }
123         r3xx_fence_report(dev, dev_priv, r3xx_fence);
124         return;
125 }
126
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)
130 {
131         struct drm_radeon_private *dev_priv = dev->dev_private;
132         struct legacy_fence *r3xx_fence = dev_priv->fence;
133         uint32_t tmp;
134
135         if (!dev_priv || dev_priv->cp_ready != 1) {
136                 return -EINVAL;
137         }
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;
143         }
144         return r3xx_fence_emit_sequence(dev, dev_priv, tmp);
145 }
146
147 static int r3xx_fence_has_irq(struct drm_device *dev,
148                               uint32_t class, uint32_t type)
149 {
150         const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE |
151                                        DRM_RADEON_FENCE_TYPE_RW;
152         /*
153          * We have an irq for EXE & RW fence.
154          */
155         if (class == 0 && (type & type_irq_mask)) {
156                 return 1;
157         }
158         return 0;
159 }
160
161 static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence)
162 {
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;
168         
169         flush_types = fence->waiting_types &    
170                       ~(DRM_FENCE_TYPE_EXE | fence->signaled_types);
171
172         if (flush_types == 0 || ((flush_types & ~fence->native_types) == 0)) {
173                 return 0;
174         }
175         if (unlikely(dev_priv == NULL)) {
176                 return 0;
177         }
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) {
182                         return 0;
183                 }
184         }
185         return flush_types;
186 }
187
188 static int r3xx_fence_wait(struct drm_fence_object *fence,
189                            int lazy, int interruptible, uint32_t mask)
190 {
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];
194         int r;
195
196         drm_fence_object_flush(fence, mask);
197         if (likely(interruptible)) {
198                 r = wait_event_interruptible_timeout(
199                         fc->fence_queue,
200                         drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), 
201                         3 * DRM_HZ);
202         } else {
203                 r = wait_event_timeout(
204                         fc->fence_queue,
205                         drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), 
206                         3 * DRM_HZ);
207         }
208         if (unlikely(r == -ERESTARTSYS)) {
209                 return -EAGAIN;
210         }
211         if (unlikely(r == 0)) {
212                 return -EBUSY;
213         }
214
215         if (likely(mask == DRM_FENCE_TYPE_EXE || 
216                    drm_fence_object_signaled(fence, mask))) {
217                 return 0;
218         }
219
220         /*
221          * Poll for sync flush completion.
222          */
223         return drm_fence_wait_polling(fence, lazy, interruptible,
224                                       mask, 3 * DRM_HZ);
225 }
226
227 struct drm_fence_driver r3xx_fence_driver = {
228         .num_classes = 1,
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,
238 };
239
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)
243 {
244         *class = 0;
245         if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) {
246                 *type = DRM_FENCE_TYPE_EXE | DRM_RADEON_FENCE_TYPE_RW;
247         } else {
248                 *type = DRM_FENCE_TYPE_EXE;
249         }
250         return 0;
251 }
252
253 /* this are used by the irq code */
254 void r3xx_fence_handler(struct drm_device * dev)
255 {
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];
259
260         if (unlikely(dev_priv == NULL)) {
261                 return;
262         }
263
264         write_lock(&fm->lock);
265         r3xx_fence_poll(dev, 0, fc->waiting_types);
266         write_unlock(&fm->lock);
267 }