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 if (test_bit(DMA_FENCE_WORK_IMM, &f->dma.flags)) 42 fence_work(&f->work); 43 else 44 queue_work(system_unbound_wq, &f->work); 45 } else { 46 fence_complete(f); 47 } 48 break; 49 50 case FENCE_FREE: 51 dma_fence_put(&f->dma); 52 break; 53 } 54 55 return NOTIFY_DONE; 56 } 57 58 static const char *get_driver_name(struct dma_fence *fence) 59 { 60 return "dma-fence"; 61 } 62 63 static const char *get_timeline_name(struct dma_fence *fence) 64 { 65 struct dma_fence_work *f = container_of(fence, typeof(*f), dma); 66 67 return f->ops->name ?: "work"; 68 } 69 70 static void fence_release(struct dma_fence *fence) 71 { 72 struct dma_fence_work *f = container_of(fence, typeof(*f), dma); 73 74 i915_sw_fence_fini(&f->chain); 75 76 BUILD_BUG_ON(offsetof(typeof(*f), dma)); 77 dma_fence_free(&f->dma); 78 } 79 80 static const struct dma_fence_ops fence_ops = { 81 .get_driver_name = get_driver_name, 82 .get_timeline_name = get_timeline_name, 83 .release = fence_release, 84 }; 85 86 void dma_fence_work_init(struct dma_fence_work *f, 87 const struct dma_fence_work_ops *ops) 88 { 89 f->ops = ops; 90 spin_lock_init(&f->lock); 91 dma_fence_init(&f->dma, &fence_ops, &f->lock, 0, 0); 92 i915_sw_fence_init(&f->chain, fence_notify); 93 INIT_WORK(&f->work, fence_work); 94 } 95 96 int dma_fence_work_chain(struct dma_fence_work *f, struct dma_fence *signal) 97 { 98 if (!signal) 99 return 0; 100 101 return __i915_sw_fence_await_dma_fence(&f->chain, signal, &f->cb); 102 } 103