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(fence: &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 | |
20 | f->ops->work(f); |
21 | |
22 | fence_complete(f); |
23 | dma_fence_put(fence: &f->dma); |
24 | } |
25 | |
26 | static int |
27 | fence_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) |
28 | { |
29 | struct dma_fence_work *f = container_of(fence, typeof(*f), chain); |
30 | |
31 | switch (state) { |
32 | case FENCE_COMPLETE: |
33 | if (fence->error) |
34 | dma_fence_set_error(fence: &f->dma, error: fence->error); |
35 | |
36 | if (!f->dma.error) { |
37 | dma_fence_get(fence: &f->dma); |
38 | if (test_bit(DMA_FENCE_WORK_IMM, &f->dma.flags)) |
39 | fence_work(work: &f->work); |
40 | else |
41 | queue_work(wq: system_unbound_wq, work: &f->work); |
42 | } else { |
43 | fence_complete(f); |
44 | } |
45 | break; |
46 | |
47 | case FENCE_FREE: |
48 | dma_fence_put(fence: &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(fence: &f->chain); |
72 | |
73 | BUILD_BUG_ON(offsetof(typeof(*f), dma)); |
74 | dma_fence_free(fence: &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(fence: &f->dma, ops: &fence_ops, lock: &f->lock, context: 0, seqno: 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(fence: &f->chain, dma: signal, cb: &f->cb); |
99 | } |
100 | |