diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_fence.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 6c946837a0aa..1680d9187bab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -35,15 +35,34 @@ | |||
35 | 35 | ||
36 | #include <engine/fifo.h> | 36 | #include <engine/fifo.h> |
37 | 37 | ||
38 | struct fence_work { | ||
39 | struct work_struct base; | ||
40 | struct list_head head; | ||
41 | void (*func)(void *); | ||
42 | void *data; | ||
43 | }; | ||
44 | |||
45 | static void | ||
46 | nouveau_fence_signal(struct nouveau_fence *fence) | ||
47 | { | ||
48 | struct fence_work *work, *temp; | ||
49 | |||
50 | list_for_each_entry_safe(work, temp, &fence->work, head) { | ||
51 | schedule_work(&work->base); | ||
52 | list_del(&work->head); | ||
53 | } | ||
54 | |||
55 | fence->channel = NULL; | ||
56 | list_del(&fence->head); | ||
57 | } | ||
58 | |||
38 | void | 59 | void |
39 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) | 60 | nouveau_fence_context_del(struct nouveau_fence_chan *fctx) |
40 | { | 61 | { |
41 | struct nouveau_fence *fence, *fnext; | 62 | struct nouveau_fence *fence, *fnext; |
42 | spin_lock(&fctx->lock); | 63 | spin_lock(&fctx->lock); |
43 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { | 64 | list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { |
44 | fence->channel = NULL; | 65 | nouveau_fence_signal(fence); |
45 | list_del(&fence->head); | ||
46 | nouveau_fence_unref(&fence); | ||
47 | } | 66 | } |
48 | spin_unlock(&fctx->lock); | 67 | spin_unlock(&fctx->lock); |
49 | } | 68 | } |
@@ -57,6 +76,50 @@ nouveau_fence_context_new(struct nouveau_fence_chan *fctx) | |||
57 | } | 76 | } |
58 | 77 | ||
59 | static void | 78 | static void |
79 | nouveau_fence_work_handler(struct work_struct *kwork) | ||
80 | { | ||
81 | struct fence_work *work = container_of(kwork, typeof(*work), base); | ||
82 | work->func(work->data); | ||
83 | kfree(work); | ||
84 | } | ||
85 | |||
86 | void | ||
87 | nouveau_fence_work(struct nouveau_fence *fence, | ||
88 | void (*func)(void *), void *data) | ||
89 | { | ||
90 | struct nouveau_channel *chan = fence->channel; | ||
91 | struct nouveau_fence_chan *fctx; | ||
92 | struct fence_work *work = NULL; | ||
93 | |||
94 | if (nouveau_fence_done(fence)) { | ||
95 | func(data); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | fctx = chan->fence; | ||
100 | work = kmalloc(sizeof(*work), GFP_KERNEL); | ||
101 | if (!work) { | ||
102 | WARN_ON(nouveau_fence_wait(fence, false, false)); | ||
103 | func(data); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | spin_lock(&fctx->lock); | ||
108 | if (!fence->channel) { | ||
109 | spin_unlock(&fctx->lock); | ||
110 | kfree(work); | ||
111 | func(data); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | INIT_WORK(&work->base, nouveau_fence_work_handler); | ||
116 | work->func = func; | ||
117 | work->data = data; | ||
118 | list_add(&work->head, &fence->work); | ||
119 | spin_unlock(&fctx->lock); | ||
120 | } | ||
121 | |||
122 | static void | ||
60 | nouveau_fence_update(struct nouveau_channel *chan) | 123 | nouveau_fence_update(struct nouveau_channel *chan) |
61 | { | 124 | { |
62 | struct nouveau_fence_chan *fctx = chan->fence; | 125 | struct nouveau_fence_chan *fctx = chan->fence; |
@@ -67,8 +130,7 @@ nouveau_fence_update(struct nouveau_channel *chan) | |||
67 | if (fctx->read(chan) < fence->sequence) | 130 | if (fctx->read(chan) < fence->sequence) |
68 | break; | 131 | break; |
69 | 132 | ||
70 | fence->channel = NULL; | 133 | nouveau_fence_signal(fence); |
71 | list_del(&fence->head); | ||
72 | nouveau_fence_unref(&fence); | 134 | nouveau_fence_unref(&fence); |
73 | } | 135 | } |
74 | spin_unlock(&fctx->lock); | 136 | spin_unlock(&fctx->lock); |
@@ -265,6 +327,7 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, | |||
265 | if (!fence) | 327 | if (!fence) |
266 | return -ENOMEM; | 328 | return -ENOMEM; |
267 | 329 | ||
330 | INIT_LIST_HEAD(&fence->work); | ||
268 | fence->sysmem = sysmem; | 331 | fence->sysmem = sysmem; |
269 | kref_init(&fence->kref); | 332 | kref_init(&fence->kref); |
270 | 333 | ||