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