1 // SPDX-License-Identifier: MIT 2 3 /* 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include "i915_sw_fence_work.h" 8 9 static void fence_complete(struct dma_fence_work *f) 10 { 11 if (f->ops->release) 12 f->ops->release(f); 13 dma_fence_signal(&f->dma); 14 } 15 16 static void fence_work(struct work_struct *work) 17 { 18 struct dma_fence_work *f = container_of(work, typeof(*f), work); 19 int err; 20 21 err = f->ops->work(f); 22 if (err) 23 dma_fence_set_error(&f->dma, err); 24 25 fence_complete(f); 26 dma_fence_put(&f->dma); 27 } 28 29 static int __i915_sw_fence_call 30 fence_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) 31 { 32 struct dma_fence_work *f = container_of(fence, typeof(*f), chain); 33 34 switch (state) { 35 case FENCE_COMPLETE: 36 if (fence->error) 37 dma_fence_set_error(&f->dma, fence->error); 38 39 if (!f->dma.error) { 40 dma_fence_get(&f->dma); 41 queue_work(system_unbound_wq, &f->work); 42 } else { 43 fence_complete(f); 44 } 45 break; 46 47 case FENCE_FREE: 48 dma_fence_put(&f->dma); 49 break; 50 } 51 52 return NOTIFY_DONE; 53 } 54 55 static const char *get_driver_name(struct dma_fence *fence) 56 { 57 return "dma-fence"; 58 } 59 60 static const char *get_timeline_name(struct dma_fence *fence) 61 { 62 struct dma_fence_work *f = container_of(fence, typeof(*f), dma); 63 64 return f->ops->name ?: "work"; 65 } 66 67 static void fence_release(struct dma_fence *fence) 68 { 69 struct dma_fence_work *f = container_of(fence, typeof(*f), dma); 70 71 i915_sw_fence_fini(&f->chain); 72 73 BUILD_BUG_ON(offsetof(typeof(*f), dma)); 74 dma_fence_free(&f->dma); 75 } 76 77 static const struct dma_fence_ops fence_ops = { 78 .get_driver_name = get_driver_name, 79 .get_timeline_name = get_timeline_name, 80 .release = fence_release, 81 }; 82 83 void dma_fence_work_init(struct dma_fence_work *f, 84 const struct dma_fence_work_ops *ops) 85 { 86 f->ops = ops; 87 spin_lock_init(&f->lock); 88 dma_fence_init(&f->dma, &fence_ops, &f->lock, 0, 0); 89 i915_sw_fence_init(&f->chain, fence_notify); 90 INIT_WORK(&f->work, fence_work); 91 } 92 93 int dma_fence_work_chain(struct dma_fence_work *f, struct dma_fence *signal) 94 { 95 if (!signal) 96 return 0; 97 98 return __i915_sw_fence_await_dma_fence(&f->chain, signal, &f->cb); 99 } 100