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 #include <engine/fifo.h> 37 38 void 39 nouveau_fence_context_del(struct nouveau_fence_chan *fctx) 40 { 41 struct nouveau_fence *fence, *fnext; 42 spin_lock(&fctx->lock); 43 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 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_chan *fctx = chan->fence; 63 struct nouveau_fence *fence, *fnext; 64 65 spin_lock(&fctx->lock); 66 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 67 if (fctx->read(chan) < fence->sequence) 68 break; 69 70 fence->channel = NULL; 71 list_del(&fence->head); 72 nouveau_fence_unref(&fence); 73 } 74 spin_unlock(&fctx->lock); 75 } 76 77 int 78 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) 79 { 80 struct nouveau_fence_chan *fctx = chan->fence; 81 int ret; 82 83 fence->channel = chan; 84 fence->timeout = jiffies + (3 * DRM_HZ); 85 fence->sequence = ++fctx->sequence; 86 87 ret = fctx->emit(fence); 88 if (!ret) { 89 kref_get(&fence->kref); 90 spin_lock(&fctx->lock); 91 list_add_tail(&fence->head, &fctx->pending); 92 spin_unlock(&fctx->lock); 93 } 94 95 return ret; 96 } 97 98 bool 99 nouveau_fence_done(struct nouveau_fence *fence) 100 { 101 if (fence->channel) 102 nouveau_fence_update(fence->channel); 103 return !fence->channel; 104 } 105 106 struct nouveau_fence_uevent { 107 struct nouveau_eventh handler; 108 struct nouveau_fence_priv *priv; 109 }; 110 111 static int 112 nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index) 113 { 114 struct nouveau_fence_uevent *uevent = 115 container_of(event, struct nouveau_fence_uevent, handler); 116 wake_up_all(&uevent->priv->waiting); 117 return NVKM_EVENT_KEEP; 118 } 119 120 static int 121 nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) 122 123 { 124 struct nouveau_channel *chan = fence->channel; 125 struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); 126 struct nouveau_fence_priv *priv = chan->drm->fence; 127 struct nouveau_fence_uevent uevent = { 128 .handler.func = nouveau_fence_wait_uevent_handler, 129 .priv = priv, 130 }; 131 int ret = 0; 132 133 nouveau_event_get(pfifo->uevent, 0, &uevent.handler); 134 135 if (fence->timeout) { 136 unsigned long timeout = fence->timeout - jiffies; 137 138 if (time_before(jiffies, fence->timeout)) { 139 if (intr) { 140 ret = wait_event_interruptible_timeout( 141 priv->waiting, 142 nouveau_fence_done(fence), 143 timeout); 144 } else { 145 ret = wait_event_timeout(priv->waiting, 146 nouveau_fence_done(fence), 147 timeout); 148 } 149 } 150 151 if (ret >= 0) { 152 fence->timeout = jiffies + ret; 153 if (time_after_eq(jiffies, fence->timeout)) 154 ret = -EBUSY; 155 } 156 } else { 157 if (intr) { 158 ret = wait_event_interruptible(priv->waiting, 159 nouveau_fence_done(fence)); 160 } else { 161 wait_event(priv->waiting, nouveau_fence_done(fence)); 162 } 163 } 164 165 nouveau_event_put(pfifo->uevent, 0, &uevent.handler); 166 if (unlikely(ret < 0)) 167 return ret; 168 169 return 0; 170 } 171 172 int 173 nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) 174 { 175 struct nouveau_channel *chan = fence->channel; 176 struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL; 177 unsigned long sleep_time = NSEC_PER_MSEC / 1000; 178 ktime_t t; 179 int ret = 0; 180 181 while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) { 182 ret = nouveau_fence_wait_uevent(fence, intr); 183 if (ret < 0) 184 return ret; 185 } 186 187 while (!nouveau_fence_done(fence)) { 188 if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { 189 ret = -EBUSY; 190 break; 191 } 192 193 __set_current_state(intr ? TASK_INTERRUPTIBLE : 194 TASK_UNINTERRUPTIBLE); 195 if (lazy) { 196 t = ktime_set(0, sleep_time); 197 schedule_hrtimeout(&t, HRTIMER_MODE_REL); 198 sleep_time *= 2; 199 if (sleep_time > NSEC_PER_MSEC) 200 sleep_time = NSEC_PER_MSEC; 201 } 202 203 if (intr && signal_pending(current)) { 204 ret = -ERESTARTSYS; 205 break; 206 } 207 } 208 209 __set_current_state(TASK_RUNNING); 210 return ret; 211 } 212 213 int 214 nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) 215 { 216 struct nouveau_fence_chan *fctx = chan->fence; 217 struct nouveau_channel *prev; 218 int ret = 0; 219 220 prev = fence ? fence->channel : NULL; 221 if (prev) { 222 if (unlikely(prev != chan && !nouveau_fence_done(fence))) { 223 ret = fctx->sync(fence, prev, chan); 224 if (unlikely(ret)) 225 ret = nouveau_fence_wait(fence, true, false); 226 } 227 } 228 229 return ret; 230 } 231 232 static void 233 nouveau_fence_del(struct kref *kref) 234 { 235 struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref); 236 kfree(fence); 237 } 238 239 void 240 nouveau_fence_unref(struct nouveau_fence **pfence) 241 { 242 if (*pfence) 243 kref_put(&(*pfence)->kref, nouveau_fence_del); 244 *pfence = NULL; 245 } 246 247 struct nouveau_fence * 248 nouveau_fence_ref(struct nouveau_fence *fence) 249 { 250 kref_get(&fence->kref); 251 return fence; 252 } 253 254 int 255 nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, 256 struct nouveau_fence **pfence) 257 { 258 struct nouveau_fence *fence; 259 int ret = 0; 260 261 if (unlikely(!chan->fence)) 262 return -ENODEV; 263 264 fence = kzalloc(sizeof(*fence), GFP_KERNEL); 265 if (!fence) 266 return -ENOMEM; 267 268 fence->sysmem = sysmem; 269 kref_init(&fence->kref); 270 271 ret = nouveau_fence_emit(fence, chan); 272 if (ret) 273 nouveau_fence_unref(&fence); 274 275 *pfence = fence; 276 return ret; 277 } 278