radeon_fence.c revision 60063497a95e716c9a689af3be2687d261f115b4
1771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse/* 2771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Copyright 2009 Jerome Glisse. 3771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * All Rights Reserved. 4771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * 5771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Permission is hereby granted, free of charge, to any person obtaining a 6771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * copy of this software and associated documentation files (the 7771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * "Software"), to deal in the Software without restriction, including 8771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * without limitation the rights to use, copy, modify, merge, publish, 9771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * distribute, sub license, and/or sell copies of the Software, and to 10771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * permit persons to whom the Software is furnished to do so, subject to 11771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * the following conditions: 12771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * 13771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * USE OR OTHER DEALINGS IN THE SOFTWARE. 20771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * 21771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * The above copyright notice and this permission notice (including the 22771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * next paragraph) shall be included in all copies or substantial portions 23771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * of the Software. 24771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * 25771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse */ 26771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse/* 27771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Authors: 28771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Jerome Glisse <glisse@freedesktop.org> 29771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Dave Airlie 30771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse */ 31771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include <linux/seq_file.h> 3260063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 33771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include <linux/wait.h> 34771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include <linux/list.h> 35771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include <linux/kref.h> 365a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 37771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include "drmP.h" 38771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include "drm.h" 39771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include "radeon_reg.h" 40771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#include "radeon.h" 4199ee7fac189893c90145a22b86bbcfdc98f69a9cDave Airlie#include "radeon_trace.h" 42771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 43b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucherstatic void radeon_fence_write(struct radeon_device *rdev, u32 seq) 44b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher{ 45b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher if (rdev->wb.enabled) { 46b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher u32 scratch_index; 47b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher if (rdev->wb.use_event) 48b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; 49b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher else 50b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; 51b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher rdev->wb.wb[scratch_index/4] = cpu_to_le32(seq);; 52b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher } else 53b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher WREG32(rdev->fence_drv.scratch_reg, seq); 54b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher} 55b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher 56b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucherstatic u32 radeon_fence_read(struct radeon_device *rdev) 57b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher{ 58b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher u32 seq; 59b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher 60b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher if (rdev->wb.enabled) { 61b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher u32 scratch_index; 62b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher if (rdev->wb.use_event) 63b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; 64b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher else 65b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; 66b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]); 67b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher } else 68b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher seq = RREG32(rdev->fence_drv.scratch_reg); 69b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher return seq; 70b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher} 71b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher 72771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) 73771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 74771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 75771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 76771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 77771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (fence->emited) { 78771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 79771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 80771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 81771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence->seq = atomic_add_return(1, &rdev->fence_drv.seq); 82b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher if (!rdev->cp.ready) 83771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse /* FIXME: cp is not running assume everythings is done right 84771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * away 85771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse */ 86b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher radeon_fence_write(rdev, fence->seq); 87b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher else 88771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_ring_emit(rdev, fence); 893ce0a23d2d253185df24e22e3d5f89800bb3dd1cJerome Glisse 9099ee7fac189893c90145a22b86bbcfdc98f69a9cDave Airlie trace_radeon_fence_emit(rdev->ddev, fence->seq); 91771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence->emited = true; 923409fc1b22e2717237f9f23112645f5d190cff4dNicolas Kaiser list_move_tail(&fence->list, &rdev->fence_drv.emited); 93771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 94771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 95771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 96771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 97771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissestatic bool radeon_fence_poll_locked(struct radeon_device *rdev) 98771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 99771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *fence; 100771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct list_head *i, *n; 101771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse uint32_t seq; 102771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse bool wake = false; 103225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse unsigned long cjiffies; 104771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 105b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher seq = radeon_fence_read(rdev); 106225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse if (seq != rdev->fence_drv.last_seq) { 107225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_seq = seq; 108225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_jiffies = jiffies; 109225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; 110225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } else { 111225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse cjiffies = jiffies; 112225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) { 113225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse cjiffies -= rdev->fence_drv.last_jiffies; 114225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse if (time_after(rdev->fence_drv.last_timeout, cjiffies)) { 115225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* update the timeout */ 116225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_timeout -= cjiffies; 117225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } else { 118225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* the 500ms timeout is elapsed we should test 119225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse * for GPU lockup 120225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse */ 121225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_timeout = 1; 122225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } 123225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } else { 124225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* wrap around update last jiffies, we will just wait 125225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse * a little longer 126225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse */ 127225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_jiffies = cjiffies; 128225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } 129225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse return false; 130225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse } 131771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse n = NULL; 132771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse list_for_each(i, &rdev->fence_drv.emited) { 133771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = list_entry(i, struct radeon_fence, list); 134771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (fence->seq == seq) { 135771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse n = i; 136771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse break; 137771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 138771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 139771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse /* all fence previous to this one are considered as signaled */ 140771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (n) { 141771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse i = n; 142771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse do { 143771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse n = i->prev; 1443409fc1b22e2717237f9f23112645f5d190cff4dNicolas Kaiser list_move_tail(i, &rdev->fence_drv.signaled); 145771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = list_entry(i, struct radeon_fence, list); 146771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence->signaled = true; 147771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse i = n; 148771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } while (i != &rdev->fence_drv.emited); 149771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse wake = true; 150771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 151771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return wake; 152771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 153771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 154771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissestatic void radeon_fence_destroy(struct kref *kref) 155771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 156771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 157771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *fence; 158771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 159771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = container_of(kref, struct radeon_fence, kref); 160771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags); 161771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse list_del(&fence->list); 162771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence->emited = false; 163771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags); 164771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse kfree(fence); 165771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 166771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 167771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence) 168771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 169771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 170771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 171771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); 172771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if ((*fence) == NULL) { 173771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return -ENOMEM; 174771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 175771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse kref_init(&((*fence)->kref)); 176771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse (*fence)->rdev = rdev; 177771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse (*fence)->emited = false; 178771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse (*fence)->signaled = false; 179771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse (*fence)->seq = 0; 180771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse INIT_LIST_HEAD(&(*fence)->list); 181771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 182771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 183771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse list_add_tail(&(*fence)->list, &rdev->fence_drv.created); 184771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 185771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 186771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 187771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 188771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 189771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissebool radeon_fence_signaled(struct radeon_fence *fence) 190771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 191771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 192771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse bool signaled = false; 193771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 1943655d54af8dd85788c3e5088387469703a0f8f12Darren Jenkins if (!fence) 195771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return true; 1963655d54af8dd85788c3e5088387469703a0f8f12Darren Jenkins 1973655d54af8dd85788c3e5088387469703a0f8f12Darren Jenkins if (fence->rdev->gpu_lockup) 198771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return true; 1993655d54af8dd85788c3e5088387469703a0f8f12Darren Jenkins 200771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags); 201771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse signaled = fence->signaled; 202771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse /* if we are shuting down report all fence as signaled */ 203771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (fence->rdev->shutdown) { 204771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse signaled = true; 205771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 206771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (!fence->emited) { 207771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse WARN(1, "Querying an unemited fence : %p !\n", fence); 208771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse signaled = true; 209771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 210771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (!signaled) { 211771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_poll_locked(fence->rdev); 212771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse signaled = fence->signaled; 213771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 214771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags); 215771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return signaled; 216771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 217771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 2183ce0a23d2d253185df24e22e3d5f89800bb3dd1cJerome Glisseint radeon_fence_wait(struct radeon_fence *fence, bool intr) 219771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 220771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_device *rdev; 221225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse unsigned long irq_flags, timeout; 222225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse u32 seq; 223771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse int r; 224771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 225771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (fence == NULL) { 226771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse WARN(1, "Querying an invalid fence : %p !\n", fence); 227771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 228771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 229771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse rdev = fence->rdev; 230771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (radeon_fence_signaled(fence)) { 231771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 232771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 233225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse timeout = rdev->fence_drv.last_timeout; 234771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseretry: 235225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* save current sequence used to check for GPU lockup */ 236225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse seq = rdev->fence_drv.last_seq; 23799ee7fac189893c90145a22b86bbcfdc98f69a9cDave Airlie trace_radeon_fence_wait_begin(rdev->ddev, seq); 2383ce0a23d2d253185df24e22e3d5f89800bb3dd1cJerome Glisse if (intr) { 2391614f8b17b8cc3ad143541d41569623d30dbc9ecDave Airlie radeon_irq_kms_sw_irq_get(rdev); 240771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse r = wait_event_interruptible_timeout(rdev->fence_drv.queue, 241771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_signaled(fence), timeout); 2421614f8b17b8cc3ad143541d41569623d30dbc9ecDave Airlie radeon_irq_kms_sw_irq_put(rdev); 24390aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse if (unlikely(r < 0)) { 2445cc6fbab9da5680e7e5d2507d0f0c2c52ff18031Thomas Hellstrom return r; 24590aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse } 246771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } else { 2471614f8b17b8cc3ad143541d41569623d30dbc9ecDave Airlie radeon_irq_kms_sw_irq_get(rdev); 248771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse r = wait_event_timeout(rdev->fence_drv.queue, 249771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_signaled(fence), timeout); 2501614f8b17b8cc3ad143541d41569623d30dbc9ecDave Airlie radeon_irq_kms_sw_irq_put(rdev); 251771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 25299ee7fac189893c90145a22b86bbcfdc98f69a9cDave Airlie trace_radeon_fence_wait_end(rdev->ddev, seq); 253771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (unlikely(!radeon_fence_signaled(fence))) { 254225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* we were interrupted for some reason and fence isn't 255225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse * isn't signaled yet, resume wait 256225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse */ 257225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse if (r) { 258225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse timeout = r; 259225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse goto retry; 260771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 261225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* don't protect read access to rdev->fence_drv.last_seq 262225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse * if we experiencing a lockup the value doesn't change 263225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse */ 264225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { 265225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* good news we believe it's a lockup */ 266fce7d61be01ad7606056608be08fef15b70eeb84Joe Perches WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", 267fce7d61be01ad7606056608be08fef15b70eeb84Joe Perches fence->seq, seq); 268225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse /* FIXME: what should we do ? marking everyone 269225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse * as signaled for now 270225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse */ 27190aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse rdev->gpu_lockup = true; 27290aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse r = radeon_gpu_reset(rdev); 27390aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse if (r) 27490aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse return r; 275b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher radeon_fence_write(rdev, fence->seq); 27690aca4d2740255bd130ea71a91530b9920c70abeJerome Glisse rdev->gpu_lockup = false; 277771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 278225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse timeout = RADEON_FENCE_JIFFIES_TIMEOUT; 279225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 280225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; 281225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse rdev->fence_drv.last_jiffies = jiffies; 282225758d8ba4fdcc1e8c9cf617fd89529bd4a9596Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 283771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse goto retry; 284771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 285771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 286771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 287771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 288771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_fence_wait_next(struct radeon_device *rdev) 289771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 290771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 291771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *fence; 292771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse int r; 293771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 294771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (rdev->gpu_lockup) { 295771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 296771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 297771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 298771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (list_empty(&rdev->fence_drv.emited)) { 299771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 300771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 301771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 302771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = list_entry(rdev->fence_drv.emited.next, 303771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence, list); 304771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_ref(fence); 305771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 306771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse r = radeon_fence_wait(fence, false); 307771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_unref(&fence); 308771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return r; 309771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 310771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 311771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_fence_wait_last(struct radeon_device *rdev) 312771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 313771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 314771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *fence; 315771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse int r; 316771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 317771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (rdev->gpu_lockup) { 318771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 319771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 320771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 321771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (list_empty(&rdev->fence_drv.emited)) { 322771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 323771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 324771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 325771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = list_entry(rdev->fence_drv.emited.prev, 326771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence, list); 327771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_ref(fence); 328771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 329771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse r = radeon_fence_wait(fence, false); 330771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_fence_unref(&fence); 331771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return r; 332771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 333771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 334771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissestruct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) 335771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 336771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse kref_get(&fence->kref); 337771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return fence; 338771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 339771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 340771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissevoid radeon_fence_unref(struct radeon_fence **fence) 341771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 342771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *tmp = *fence; 343771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 344771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse *fence = NULL; 345771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (tmp) { 346cdb650a4b5eaf1c0aedbfd7dd6afd6d465c3b0a0Paul Bolle kref_put(&tmp->kref, radeon_fence_destroy); 347771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 348771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 349771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 350771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissevoid radeon_fence_process(struct radeon_device *rdev) 351771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 352771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 353771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse bool wake; 354771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 355771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 356771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse wake = radeon_fence_poll_locked(rdev); 357771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 358771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (wake) { 359771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse wake_up_all(&rdev->fence_drv.queue); 360771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 361771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 362771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 363771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_fence_driver_init(struct radeon_device *rdev) 364771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 365771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 366771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse int r; 367771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 368771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 369771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse r = radeon_scratch_get(rdev, &rdev->fence_drv.scratch_reg); 370771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (r) { 3710a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse dev_err(rdev->dev, "fence failed to get scratch register\n"); 372771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 373771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return r; 374771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 375b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher radeon_fence_write(rdev, 0); 376771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse atomic_set(&rdev->fence_drv.seq, 0); 377771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse INIT_LIST_HEAD(&rdev->fence_drv.created); 378771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse INIT_LIST_HEAD(&rdev->fence_drv.emited); 379771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse INIT_LIST_HEAD(&rdev->fence_drv.signaled); 380771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse init_waitqueue_head(&rdev->fence_drv.queue); 3810a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse rdev->fence_drv.initialized = true; 382771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 383771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (radeon_debugfs_fence_init(rdev)) { 3840a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse dev_err(rdev->dev, "fence debugfs file creation failed\n"); 385771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 386771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 387771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 388771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 389771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissevoid radeon_fence_driver_fini(struct radeon_device *rdev) 390771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 391771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse unsigned long irq_flags; 392771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 3930a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse if (!rdev->fence_drv.initialized) 3940a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse return; 395771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse wake_up_all(&rdev->fence_drv.queue); 396771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); 397771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse radeon_scratch_free(rdev, rdev->fence_drv.scratch_reg); 398771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); 3990a0c7596c643239e8d4c3eaaba43b74a96f2411eJerome Glisse rdev->fence_drv.initialized = false; 400771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 401771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 402771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 403771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse/* 404771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse * Fence debugfs 405771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse */ 406771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#if defined(CONFIG_DEBUG_FS) 407771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissestatic int radeon_debugfs_fence_info(struct seq_file *m, void *data) 408771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 409771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct drm_info_node *node = (struct drm_info_node *)m->private; 410771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct drm_device *dev = node->minor->dev; 411771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_device *rdev = dev->dev_private; 412771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence *fence; 413771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 414771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse seq_printf(m, "Last signaled fence 0x%08X\n", 415b81157d016a48b8025ccfcb286827679b35f16aaAlex Deucher radeon_fence_read(rdev)); 416771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse if (!list_empty(&rdev->fence_drv.emited)) { 417771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence = list_entry(rdev->fence_drv.emited.prev, 418771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse struct radeon_fence, list); 419771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse seq_printf(m, "Last emited fence %p with 0x%08X\n", 420771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse fence, fence->seq); 421771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse } 422771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 423771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 424771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 425771fe6b912fca54f03e8a72eb63058b582775362Jerome Glissestatic struct drm_info_list radeon_debugfs_fence_list[] = { 426771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse {"radeon_fence_info", &radeon_debugfs_fence_info, 0, NULL}, 427771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse}; 428771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#endif 429771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse 430771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisseint radeon_debugfs_fence_init(struct radeon_device *rdev) 431771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse{ 432771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#if defined(CONFIG_DEBUG_FS) 433771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 1); 434771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#else 435771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse return 0; 436771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse#endif 437771fe6b912fca54f03e8a72eb63058b582775362Jerome Glisse} 438