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 struct fence_work { 39 struct work_struct base; 40 struct list_head head; 41 void (*func)(void *); 42 void *data; 43 }; 44 45 static void 46 nouveau_fence_signal(struct nouveau_fence *fence) 47 { 48 struct fence_work *work, *temp; 49 50 list_for_each_entry_safe(work, temp, &fence->work, head) { 51 schedule_work(&work->base); 52 list_del(&work->head); 53 } 54 55 fence->channel = NULL; 56 list_del(&fence->head); 57 } 58 59 void 60 nouveau_fence_context_del(struct nouveau_fence_chan *fctx) 61 { 62 struct nouveau_fence *fence, *fnext; 63 spin_lock(&fctx->lock); 64 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 65 nouveau_fence_signal(fence); 66 } 67 spin_unlock(&fctx->lock); 68 } 69 70 void 71 nouveau_fence_context_new(struct nouveau_fence_chan *fctx) 72 { 73 INIT_LIST_HEAD(&fctx->flip); 74 INIT_LIST_HEAD(&fctx->pending); 75 spin_lock_init(&fctx->lock); 76 } 77 78 static void 79 nouveau_fence_work_handler(struct work_struct *kwork) 80 { 81 struct fence_work *work = container_of(kwork, typeof(*work), base); 82 work->func(work->data); 83 kfree(work); 84 } 85 86 void 87 nouveau_fence_work(struct nouveau_fence *fence, 88 void (*func)(void *), void *data) 89 { 90 struct nouveau_channel *chan = fence->channel; 91 struct nouveau_fence_chan *fctx; 92 struct fence_work *work = NULL; 93 94 if (nouveau_fence_done(fence)) { 95 func(data); 96 return; 97 } 98 99 fctx = chan->fence; 100 work = kmalloc(sizeof(*work), GFP_KERNEL); 101 if (!work) { 102 WARN_ON(nouveau_fence_wait(fence, false, false)); 103 func(data); 104 return; 105 } 106 107 spin_lock(&fctx->lock); 108 if (!fence->channel) { 109 spin_unlock(&fctx->lock); 110 kfree(work); 111 func(data); 112 return; 113 } 114 115 INIT_WORK(&work->base, nouveau_fence_work_handler); 116 work->func = func; 117 work->data = data; 118 list_add(&work->head, &fence->work); 119 spin_unlock(&fctx->lock); 120 } 121 122 static void 123 nouveau_fence_update(struct nouveau_channel *chan) 124 { 125 struct nouveau_fence_chan *fctx = chan->fence; 126 struct nouveau_fence *fence, *fnext; 127 128 spin_lock(&fctx->lock); 129 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { 130 if (fctx->read(chan) < fence->sequence) 131 break; 132 133 nouveau_fence_signal(fence); 134 nouveau_fence_unref(&fence); 135 } 136 spin_unlock(&fctx->lock); 137 } 138 139 int 140 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) 141 { 142 struct nouveau_fence_chan *fctx = chan->fence; 143 int ret; 144 145 fence->channel = chan; 146 fence->timeout = jiffies + (15 * HZ); 147 fence->sequence = ++fctx->sequence; 148 149 ret = fctx->emit(fence); 150 if (!ret) { 151 kref_get(&fence->kref); 152 spin_lock(&fctx->lock); 153 list_add_tail(&fence->head, &fctx->pending); 154 spin_unlock(&fctx->lock); 155 } 156 157 return ret; 158 } 159 160 bool 161 nouveau_fence_done(struct nouveau_fence *fence) 162 { 163 if (fence->channel) 164 nouveau_fence_update(fence->channel); 165 return !fence->channel; 166 } 167 168 static int 169 nouveau_fence_wait_uevent_handler(void *data, int index) 170 { 171 struct nouveau_fence_priv *priv = data; 172 wake_up_all(&priv->waiting); 173 return NVKM_EVENT_KEEP; 174 } 175 176 static int 177 nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) 178 179 { 180 struct nouveau_channel *chan = fence->channel; 181 struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); 182 struct nouveau_fence_priv *priv = chan->drm->fence; 183 struct nouveau_eventh *handler; 184 int ret = 0; 185 186 ret = nouveau_event_new(pfifo->uevent, 0, 187 nouveau_fence_wait_uevent_handler, 188 priv, &handler); 189 if (ret) 190 return ret; 191 192 nouveau_event_get(handler); 193 194 if (fence->timeout) { 195 unsigned long timeout = fence->timeout - jiffies; 196 197 if (time_before(jiffies, fence->timeout)) { 198 if (intr) { 199 ret = wait_event_interruptible_timeout( 200 priv->waiting, 201 nouveau_fence_done(fence), 202 timeout); 203 } else { 204 ret = wait_event_timeout(priv->waiting, 205 nouveau_fence_done(fence), 206 timeout); 207 } 208 } 209 210 if (ret >= 0) { 211 fence->timeout = jiffies + ret; 212 if (time_after_eq(jiffies, fence->timeout)) 213 ret = -EBUSY; 214 } 215 } else { 216 if (intr) { 217 ret = wait_event_interruptible(priv->waiting, 218 nouveau_fence_done(fence)); 219 } else { 220 wait_event(priv->waiting, nouveau_fence_done(fence)); 221 } 222 } 223 224 nouveau_event_ref(NULL, &handler); 225 if (unlikely(ret < 0)) 226 return ret; 227 228 return 0; 229 } 230 231 int 232 nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) 233 { 234 struct nouveau_channel *chan = fence->channel; 235 struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL; 236 unsigned long sleep_time = NSEC_PER_MSEC / 1000; 237 ktime_t t; 238 int ret = 0; 239 240 while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) { 241 ret = nouveau_fence_wait_uevent(fence, intr); 242 if (ret < 0) 243 return ret; 244 } 245 246 while (!nouveau_fence_done(fence)) { 247 if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { 248 ret = -EBUSY; 249 break; 250 } 251 252 __set_current_state(intr ? TASK_INTERRUPTIBLE : 253 TASK_UNINTERRUPTIBLE); 254 if (lazy) { 255 t = ktime_set(0, sleep_time); 256 schedule_hrtimeout(&t, HRTIMER_MODE_REL); 257 sleep_time *= 2; 258 if (sleep_time > NSEC_PER_MSEC) 259 sleep_time = NSEC_PER_MSEC; 260 } 261 262 if (intr && signal_pending(current)) { 263 ret = -ERESTARTSYS; 264 break; 265 } 266 } 267 268 __set_current_state(TASK_RUNNING); 269 return ret; 270 } 271 272 int 273 nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) 274 { 275 struct nouveau_fence_chan *fctx = chan->fence; 276 struct nouveau_channel *prev; 277 int ret = 0; 278 279 prev = fence ? fence->channel : NULL; 280 if (prev) { 281 if (unlikely(prev != chan && !nouveau_fence_done(fence))) { 282 ret = fctx->sync(fence, prev, chan); 283 if (unlikely(ret)) 284 ret = nouveau_fence_wait(fence, true, false); 285 } 286 } 287 288 return ret; 289 } 290 291 static void 292 nouveau_fence_del(struct kref *kref) 293 { 294 struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref); 295 kfree(fence); 296 } 297 298 void 299 nouveau_fence_unref(struct nouveau_fence **pfence) 300 { 301 if (*pfence) 302 kref_put(&(*pfence)->kref, nouveau_fence_del); 303 *pfence = NULL; 304 } 305 306 struct nouveau_fence * 307 nouveau_fence_ref(struct nouveau_fence *fence) 308 { 309 if (fence) 310 kref_get(&fence->kref); 311 return fence; 312 } 313 314 int 315 nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, 316 struct nouveau_fence **pfence) 317 { 318 struct nouveau_fence *fence; 319 int ret = 0; 320 321 if (unlikely(!chan->fence)) 322 return -ENODEV; 323 324 fence = kzalloc(sizeof(*fence), GFP_KERNEL); 325 if (!fence) 326 return -ENOMEM; 327 328 INIT_LIST_HEAD(&fence->work); 329 fence->sysmem = sysmem; 330 kref_init(&fence->kref); 331 332 ret = nouveau_fence_emit(fence, chan); 333 if (ret) 334 nouveau_fence_unref(&fence); 335 336 *pfence = fence; 337 return ret; 338 } 339