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