aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_fence.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2010-03-09 09:45:10 -0500
committerDave Airlie <airlied@redhat.com>2010-04-05 20:42:45 -0400
commit225758d8ba4fdcc1e8c9cf617fd89529bd4a9596 (patch)
treea9ac2f23435d4a6db5aa33774ba94d9f0aeb5c4c /drivers/gpu/drm/radeon/radeon_fence.c
parent95beb690170e6ce918fe53c73a0fcc7cf64d704a (diff)
drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4
This patch cleanup the fence code, it drops the timeout field of fence as the time to complete each IB is unpredictable and shouldn't be bound. The fence cleanup lead to GPU lockup detection improvement, this patch introduce a callback, allowing to do asic specific test for lockup detection. In this patch the CP is use as a first indicator of GPU lockup. If CP doesn't make progress during 1second we assume we are facing a GPU lockup. To avoid overhead of testing GPU lockup frequently due to fence taking time to be signaled we query the lockup callback every 500msec. There is plenty code comment explaining the design & choise inside the code. This have been tested mostly on R3XX/R5XX hw, in normal running destkop (compiz firefox, quake3 running) the lockup callback wasn't call once (1 hour session). Also tested with forcing GPU lockup and lockup was reported after the 1s CP activity timeout. V2 switch to 500ms timeout so GPU lockup get call at least 2 times in less than 2sec. V3 store last jiffies in fence struct so on ERESTART, EBUSY we keep track of how long we already wait for a given fence V4 make sure we got up to date cp read pointer so we don't have false positive Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_fence.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c102
1 files changed, 55 insertions, 47 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 8495d4e32e18..393154268dea 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -57,7 +57,6 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
57 radeon_fence_ring_emit(rdev, fence); 57 radeon_fence_ring_emit(rdev, fence);
58 58
59 fence->emited = true; 59 fence->emited = true;
60 fence->timeout = jiffies + ((2000 * HZ) / 1000);
61 list_del(&fence->list); 60 list_del(&fence->list);
62 list_add_tail(&fence->list, &rdev->fence_drv.emited); 61 list_add_tail(&fence->list, &rdev->fence_drv.emited);
63 write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 62 write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
@@ -70,15 +69,34 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev)
70 struct list_head *i, *n; 69 struct list_head *i, *n;
71 uint32_t seq; 70 uint32_t seq;
72 bool wake = false; 71 bool wake = false;
72 unsigned long cjiffies;
73 73
74 if (rdev == NULL) {
75 return true;
76 }
77 if (rdev->shutdown) {
78 return true;
79 }
80 seq = RREG32(rdev->fence_drv.scratch_reg); 74 seq = RREG32(rdev->fence_drv.scratch_reg);
81 rdev->fence_drv.last_seq = seq; 75 if (seq != rdev->fence_drv.last_seq) {
76 rdev->fence_drv.last_seq = seq;
77 rdev->fence_drv.last_jiffies = jiffies;
78 rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
79 } else {
80 cjiffies = jiffies;
81 if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) {
82 cjiffies -= rdev->fence_drv.last_jiffies;
83 if (time_after(rdev->fence_drv.last_timeout, cjiffies)) {
84 /* update the timeout */
85 rdev->fence_drv.last_timeout -= cjiffies;
86 } else {
87 /* the 500ms timeout is elapsed we should test
88 * for GPU lockup
89 */
90 rdev->fence_drv.last_timeout = 1;
91 }
92 } else {
93 /* wrap around update last jiffies, we will just wait
94 * a little longer
95 */
96 rdev->fence_drv.last_jiffies = cjiffies;
97 }
98 return false;
99 }
82 n = NULL; 100 n = NULL;
83 list_for_each(i, &rdev->fence_drv.emited) { 101 list_for_each(i, &rdev->fence_drv.emited) {
84 fence = list_entry(i, struct radeon_fence, list); 102 fence = list_entry(i, struct radeon_fence, list);
@@ -170,9 +188,8 @@ bool radeon_fence_signaled(struct radeon_fence *fence)
170int radeon_fence_wait(struct radeon_fence *fence, bool intr) 188int radeon_fence_wait(struct radeon_fence *fence, bool intr)
171{ 189{
172 struct radeon_device *rdev; 190 struct radeon_device *rdev;
173 unsigned long cur_jiffies; 191 unsigned long irq_flags, timeout;
174 unsigned long timeout; 192 u32 seq;
175 bool expired = false;
176 int r; 193 int r;
177 194
178 if (fence == NULL) { 195 if (fence == NULL) {
@@ -183,14 +200,10 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
183 if (radeon_fence_signaled(fence)) { 200 if (radeon_fence_signaled(fence)) {
184 return 0; 201 return 0;
185 } 202 }
186 203 timeout = rdev->fence_drv.last_timeout;
187retry: 204retry:
188 cur_jiffies = jiffies; 205 /* save current sequence used to check for GPU lockup */
189 timeout = HZ / 100; 206 seq = rdev->fence_drv.last_seq;
190 if (time_after(fence->timeout, cur_jiffies)) {
191 timeout = fence->timeout - cur_jiffies;
192 }
193
194 if (intr) { 207 if (intr) {
195 radeon_irq_kms_sw_irq_get(rdev); 208 radeon_irq_kms_sw_irq_get(rdev);
196 r = wait_event_interruptible_timeout(rdev->fence_drv.queue, 209 r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
@@ -205,38 +218,34 @@ retry:
205 radeon_irq_kms_sw_irq_put(rdev); 218 radeon_irq_kms_sw_irq_put(rdev);
206 } 219 }
207 if (unlikely(!radeon_fence_signaled(fence))) { 220 if (unlikely(!radeon_fence_signaled(fence))) {
208 if (unlikely(r == 0)) { 221 /* we were interrupted for some reason and fence isn't
209 expired = true; 222 * isn't signaled yet, resume wait
223 */
224 if (r) {
225 timeout = r;
226 goto retry;
210 } 227 }
211 if (unlikely(expired)) { 228 /* don't protect read access to rdev->fence_drv.last_seq
212 timeout = 1; 229 * if we experiencing a lockup the value doesn't change
213 if (time_after(cur_jiffies, fence->timeout)) { 230 */
214 timeout = cur_jiffies - fence->timeout; 231 if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
215 } 232 /* good news we believe it's a lockup */
216 timeout = jiffies_to_msecs(timeout); 233 dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq);
217 if (timeout > 500) { 234 r = radeon_gpu_reset(rdev);
218 DRM_ERROR("fence(%p:0x%08X) %lums timeout " 235 if (r)
219 "going to reset GPU\n", 236 return r;
220 fence, fence->seq, timeout); 237 /* FIXME: what should we do ? marking everyone
221 radeon_gpu_reset(rdev); 238 * as signaled for now
222 WREG32(rdev->fence_drv.scratch_reg, fence->seq); 239 */
223 } 240 WREG32(rdev->fence_drv.scratch_reg, fence->seq);
224 } 241 }
242 timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
243 write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
244 rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
245 rdev->fence_drv.last_jiffies = jiffies;
246 write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
225 goto retry; 247 goto retry;
226 } 248 }
227 if (unlikely(expired)) {
228 rdev->fence_drv.count_timeout++;
229 cur_jiffies = jiffies;
230 timeout = 1;
231 if (time_after(cur_jiffies, fence->timeout)) {
232 timeout = cur_jiffies - fence->timeout;
233 }
234 timeout = jiffies_to_msecs(timeout);
235 DRM_ERROR("fence(%p:0x%08X) %lums timeout\n",
236 fence, fence->seq, timeout);
237 DRM_ERROR("last signaled fence(0x%08X)\n",
238 rdev->fence_drv.last_seq);
239 }
240 return 0; 249 return 0;
241} 250}
242 251
@@ -332,7 +341,6 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
332 INIT_LIST_HEAD(&rdev->fence_drv.created); 341 INIT_LIST_HEAD(&rdev->fence_drv.created);
333 INIT_LIST_HEAD(&rdev->fence_drv.emited); 342 INIT_LIST_HEAD(&rdev->fence_drv.emited);
334 INIT_LIST_HEAD(&rdev->fence_drv.signaled); 343 INIT_LIST_HEAD(&rdev->fence_drv.signaled);
335 rdev->fence_drv.count_timeout = 0;
336 init_waitqueue_head(&rdev->fence_drv.queue); 344 init_waitqueue_head(&rdev->fence_drv.queue);
337 rdev->fence_drv.initialized = true; 345 rdev->fence_drv.initialized = true;
338 write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 346 write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);