Skip to content

Commit 978474d

Browse files
committed
drm/nouveau: fence: fix undefined fence state after emit
nouveau_fence_emit() can fail before and after initializing the dma-fence and hence before and after initializing the dma-fence' kref. In order to avoid nouveau_fence_emit() potentially failing before dma-fence initialization pass the channel to nouveau_fence_new() already and perform the required check before even allocating the fence. While at it, restore the original behavior of nouveau_fence_new() and add nouveau_fence_create() for separate (pre-)allocation instead. Always splitting up allocation end emit wasn't a good idea in the first place. Hence, limit it to the places where we actually need to pre-allocate. Fixes: 7f2a0b5 ("drm/nouveau: fence: separate fence alloc and emit") Signed-off-by: Danilo Krummrich <[email protected]> Reviewed-by: Dave Airlie <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 4b2fd81 commit 978474d

File tree

8 files changed

+45
-40
lines changed

8 files changed

+45
-40
lines changed

drivers/gpu/drm/nouveau/dispnv04/crtc.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,18 +1122,11 @@ nv04_page_flip_emit(struct nouveau_channel *chan,
11221122
PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000);
11231123
PUSH_KICK(push);
11241124

1125-
ret = nouveau_fence_new(pfence);
1125+
ret = nouveau_fence_new(pfence, chan);
11261126
if (ret)
11271127
goto fail;
11281128

1129-
ret = nouveau_fence_emit(*pfence, chan);
1130-
if (ret)
1131-
goto fail_fence_unref;
1132-
11331129
return 0;
1134-
1135-
fail_fence_unref:
1136-
nouveau_fence_unref(pfence);
11371130
fail:
11381131
spin_lock_irqsave(&dev->event_lock, flags);
11391132
list_del(&s->head);

drivers/gpu/drm/nouveau/nouveau_bo.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -875,16 +875,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
875875
if (ret)
876876
goto out_unlock;
877877

878-
ret = nouveau_fence_new(&fence);
878+
ret = nouveau_fence_new(&fence, chan);
879879
if (ret)
880880
goto out_unlock;
881881

882-
ret = nouveau_fence_emit(fence, chan);
883-
if (ret) {
884-
nouveau_fence_unref(&fence);
885-
goto out_unlock;
886-
}
887-
888882
/* TODO: figure out a better solution here
889883
*
890884
* wait on the fence here explicitly as going through

drivers/gpu/drm/nouveau/nouveau_chan.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,9 @@ nouveau_channel_idle(struct nouveau_channel *chan)
7070
struct nouveau_fence *fence = NULL;
7171
int ret;
7272

73-
ret = nouveau_fence_new(&fence);
73+
ret = nouveau_fence_new(&fence, chan);
7474
if (!ret) {
75-
ret = nouveau_fence_emit(fence, chan);
76-
if (!ret)
77-
ret = nouveau_fence_wait(fence, false, false);
75+
ret = nouveau_fence_wait(fence, false, false);
7876
nouveau_fence_unref(&fence);
7977
}
8078

drivers/gpu/drm/nouveau/nouveau_dmem.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
209209
goto done;
210210
}
211211

212-
if (!nouveau_fence_new(&fence))
213-
nouveau_fence_emit(fence, dmem->migrate.chan);
212+
nouveau_fence_new(&fence, dmem->migrate.chan);
214213
migrate_vma_pages(&args);
215214
nouveau_dmem_fence_done(&fence);
216215
dma_unmap_page(drm->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
@@ -403,8 +402,7 @@ nouveau_dmem_evict_chunk(struct nouveau_dmem_chunk *chunk)
403402
}
404403
}
405404

406-
if (!nouveau_fence_new(&fence))
407-
nouveau_fence_emit(fence, chunk->drm->dmem->migrate.chan);
405+
nouveau_fence_new(&fence, chunk->drm->dmem->migrate.chan);
408406
migrate_device_pages(src_pfns, dst_pfns, npages);
409407
nouveau_dmem_fence_done(&fence);
410408
migrate_device_finalize(src_pfns, dst_pfns, npages);
@@ -677,8 +675,7 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
677675
addr += PAGE_SIZE;
678676
}
679677

680-
if (!nouveau_fence_new(&fence))
681-
nouveau_fence_emit(fence, drm->dmem->migrate.chan);
678+
nouveau_fence_new(&fence, drm->dmem->migrate.chan);
682679
migrate_vma_pages(args);
683680
nouveau_dmem_fence_done(&fence);
684681
nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);

drivers/gpu/drm/nouveau/nouveau_exec.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ nouveau_exec_job_submit(struct nouveau_job *job)
9696
unsigned long index;
9797
int ret;
9898

99-
ret = nouveau_fence_new(&exec_job->fence);
99+
/* Create a new fence, but do not emit yet. */
100+
ret = nouveau_fence_create(&exec_job->fence, exec_job->chan);
100101
if (ret)
101102
return ret;
102103

@@ -170,13 +171,17 @@ nouveau_exec_job_run(struct nouveau_job *job)
170171
nv50_dma_push(chan, p->va, p->va_len, no_prefetch);
171172
}
172173

173-
ret = nouveau_fence_emit(fence, chan);
174+
ret = nouveau_fence_emit(fence);
174175
if (ret) {
176+
nouveau_fence_unref(&exec_job->fence);
175177
NV_PRINTK(err, job->cli, "error fencing pushbuf: %d\n", ret);
176178
WIND_RING(chan);
177179
return ERR_PTR(ret);
178180
}
179181

182+
/* The fence was emitted successfully, set the job's fence pointer to
183+
* NULL in order to avoid freeing it up when the job is cleaned up.
184+
*/
180185
exec_job->fence = NULL;
181186

182187
return &fence->base;
@@ -189,7 +194,7 @@ nouveau_exec_job_free(struct nouveau_job *job)
189194

190195
nouveau_job_free(job);
191196

192-
nouveau_fence_unref(&exec_job->fence);
197+
kfree(exec_job->fence);
193198
kfree(exec_job->push.s);
194199
kfree(exec_job);
195200
}

drivers/gpu/drm/nouveau/nouveau_fence.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,13 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
205205
}
206206

207207
int
208-
nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
208+
nouveau_fence_emit(struct nouveau_fence *fence)
209209
{
210+
struct nouveau_channel *chan = fence->channel;
210211
struct nouveau_fence_chan *fctx = chan->fence;
211212
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
212213
int ret;
213214

214-
if (unlikely(!chan->fence))
215-
return -ENODEV;
216-
217-
fence->channel = chan;
218215
fence->timeout = jiffies + (15 * HZ);
219216

220217
if (priv->uevent)
@@ -406,18 +403,41 @@ nouveau_fence_unref(struct nouveau_fence **pfence)
406403
}
407404

408405
int
409-
nouveau_fence_new(struct nouveau_fence **pfence)
406+
nouveau_fence_create(struct nouveau_fence **pfence,
407+
struct nouveau_channel *chan)
410408
{
411409
struct nouveau_fence *fence;
412410

411+
if (unlikely(!chan->fence))
412+
return -ENODEV;
413+
413414
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
414415
if (!fence)
415416
return -ENOMEM;
416417

418+
fence->channel = chan;
419+
417420
*pfence = fence;
418421
return 0;
419422
}
420423

424+
int
425+
nouveau_fence_new(struct nouveau_fence **pfence,
426+
struct nouveau_channel *chan)
427+
{
428+
int ret = 0;
429+
430+
ret = nouveau_fence_create(pfence, chan);
431+
if (ret)
432+
return ret;
433+
434+
ret = nouveau_fence_emit(*pfence);
435+
if (ret)
436+
nouveau_fence_unref(pfence);
437+
438+
return ret;
439+
}
440+
421441
static const char *nouveau_fence_get_get_driver_name(struct dma_fence *fence)
422442
{
423443
return "nouveau";

drivers/gpu/drm/nouveau/nouveau_fence.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ struct nouveau_fence {
1717
unsigned long timeout;
1818
};
1919

20-
int nouveau_fence_new(struct nouveau_fence **);
20+
int nouveau_fence_create(struct nouveau_fence **, struct nouveau_channel *);
21+
int nouveau_fence_new(struct nouveau_fence **, struct nouveau_channel *);
2122
void nouveau_fence_unref(struct nouveau_fence **);
2223

23-
int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
24+
int nouveau_fence_emit(struct nouveau_fence *);
2425
bool nouveau_fence_done(struct nouveau_fence *);
2526
int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
2627
int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr);

drivers/gpu/drm/nouveau/nouveau_gem.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -914,11 +914,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
914914
}
915915
}
916916

917-
ret = nouveau_fence_new(&fence);
918-
if (!ret)
919-
ret = nouveau_fence_emit(fence, chan);
917+
ret = nouveau_fence_new(&fence, chan);
920918
if (ret) {
921-
nouveau_fence_unref(&fence);
922919
NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret);
923920
WIND_RING(chan);
924921
goto out;

0 commit comments

Comments
 (0)