1 /* 2 * Copyright (C) 2007 Ben Skeggs. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27 #include <drm/drmP.h> 28 29 #include <linux/ktime.h> 30 #include <linux/hrtimer.h> 31 32 #include "nouveau_drm.h" 33 #include "nouveau_dma.h" 34 #include "nouveau_fence.h" 35 36 void 37 nouveau_fence_context_del(struct nouveau_fence_chan *fctx) 38 { 39 struct nouveau_fence *fence, *fnext; 40 spin_lock(&fctx->lock); 41 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 42 if (fence->work) 43 fence->work(fence->priv, false); 44 fence->channel = NULL; 45 list_del(&fence->head); 46 nouveau_fence_unref(&fence); 47 } 48 spin_unlock(&fctx->lock); 49 } 50 51 void 52 nouveau_fence_context_new(struct nouveau_fence_chan *fctx) 53 { 54 INIT_LIST_HEAD(&fctx->flip); 55 INIT_LIST_HEAD(&fctx->pending); 56 spin_lock_init(&fctx->lock); 57 } 58 59 static void 60 nouveau_fence_update(struct nouveau_channel *chan) 61 { 62 struct nouveau_fence_priv *priv = chan->drm->fence; 63 struct nouveau_fence_chan *fctx = chan->fence; 64 struct nouveau_fence *fence, *fnext; 65 66 spin_lock(&fctx->lock); 67 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 68 if (priv->read(chan) < fence->sequence) 69 break; 70 71 if (fence->work) 72 fence->work(fence->priv, true); 73 fence->channel = NULL; 74 list_del(&fence->head); 75 nouveau_fence_unref(&fence); 76 } 77 spin_unlock(&fctx->lock); 78 } 79 80 int 81 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) 82 { 83 struct nouveau_fence_priv *priv = chan->drm->fence; 84 struct nouveau_fence_chan *fctx = chan->fence; 85 int ret; 86 87 fence->channel = chan; 88 fence->timeout = jiffies + (3 * DRM_HZ); 89 fence->sequence = ++fctx->sequence; 90 91 ret = priv->emit(fence); 92 if (!ret) { 93 kref_get(&fence->kref); 94 spin_lock(&fctx->lock); 95 list_add_tail(&fence->head, &fctx->pending); 96 spin_unlock(&fctx->lock); 97 } 98 99 return ret; 100 } 101 102 bool 103 nouveau_fence_done(struct nouveau_fence *fence) 104 { 105 if (fence->channel) 106 nouveau_fence_update(fence->channel); 107 return !fence->channel; 108 } 109 110 int 111 nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) 112 { 113 unsigned long sleep_time = NSEC_PER_MSEC / 1000; 114 ktime_t t; 115 int ret = 0; 116 117 while (!nouveau_fence_done(fence)) { 118 if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { 119 ret = -EBUSY; 120 break; 121 } 122 123 __set_current_state(intr ? TASK_INTERRUPTIBLE : 124 TASK_UNINTERRUPTIBLE); 125 if (lazy) { 126 t = ktime_set(0, sleep_time); 127 schedule_hrtimeout(&t, HRTIMER_MODE_REL); 128 sleep_time *= 2; 129 if (sleep_time > NSEC_PER_MSEC) 130 sleep_time = NSEC_PER_MSEC; 131 } 132 133 if (intr && signal_pending(current)) { 134 ret = -ERESTARTSYS; 135 break; 136 } 137 } 138 139 __set_current_state(TASK_RUNNING); 140 return ret; 141 } 142 143 int 144 nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) 145 { 146 struct nouveau_fence_priv *priv = chan->drm->fence; 147 struct nouveau_channel *prev; 148 int ret = 0; 149 150 prev = fence ? fence->channel : NULL; 151 if (prev) { 152 if (unlikely(prev != chan && !nouveau_fence_done(fence))) { 153 ret = priv->sync(fence, prev, chan); 154 if (unlikely(ret)) 155 ret = nouveau_fence_wait(fence, true, false); 156 } 157 } 158 159 return ret; 160 } 161 162 static void 163 nouveau_fence_del(struct kref *kref) 164 { 165 struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref); 166 kfree(fence); 167 } 168 169 void 170 nouveau_fence_unref(struct nouveau_fence **pfence) 171 { 172 if (*pfence) 173 kref_put(&(*pfence)->kref, nouveau_fence_del); 174 *pfence = NULL; 175 } 176 177 struct nouveau_fence * 178 nouveau_fence_ref(struct nouveau_fence *fence) 179 { 180 kref_get(&fence->kref); 181 return fence; 182 } 183 184 int 185 nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence) 186 { 187 struct nouveau_fence *fence; 188 int ret = 0; 189 190 if (unlikely(!chan->fence)) 191 return -ENODEV; 192 193 fence = kzalloc(sizeof(*fence), GFP_KERNEL); 194 if (!fence) 195 return -ENOMEM; 196 kref_init(&fence->kref); 197 198 if (chan) { 199 ret = nouveau_fence_emit(fence, chan); 200 if (ret) 201 nouveau_fence_unref(&fence); 202 } 203 204 *pfence = fence; 205 return ret; 206 } 207