Commit 978474dc authored by Danilo Krummrich's avatar Danilo Krummrich
Browse files

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: 7f2a0b50 ("drm/nouveau: fence: separate fence alloc and emit")
Signed-off-by: default avatarDanilo Krummrich <dakr@redhat.com>
Reviewed-by: default avatarDave Airlie <airlied@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230829223847.4406-1-dakr@redhat.com
parent 4b2fd81f
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -1122,18 +1122,11 @@ nv04_page_flip_emit(struct nouveau_channel *chan,
	PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000);
	PUSH_KICK(push);

	ret = nouveau_fence_new(pfence);
	ret = nouveau_fence_new(pfence, chan);
	if (ret)
		goto fail;

	ret = nouveau_fence_emit(*pfence, chan);
	if (ret)
		goto fail_fence_unref;

	return 0;

fail_fence_unref:
	nouveau_fence_unref(pfence);
fail:
	spin_lock_irqsave(&dev->event_lock, flags);
	list_del(&s->head);
+1 −7
Original line number Diff line number Diff line
@@ -875,16 +875,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
	if (ret)
		goto out_unlock;

	ret = nouveau_fence_new(&fence);
	ret = nouveau_fence_new(&fence, chan);
	if (ret)
		goto out_unlock;

	ret = nouveau_fence_emit(fence, chan);
	if (ret) {
		nouveau_fence_unref(&fence);
		goto out_unlock;
	}

	/* TODO: figure out a better solution here
	 *
	 * wait on the fence here explicitly as going through
+2 −4
Original line number Diff line number Diff line
@@ -70,10 +70,8 @@ nouveau_channel_idle(struct nouveau_channel *chan)
		struct nouveau_fence *fence = NULL;
		int ret;

		ret = nouveau_fence_new(&fence);
		ret = nouveau_fence_new(&fence, chan);
		if (!ret) {
			ret = nouveau_fence_emit(fence, chan);
			if (!ret)
			ret = nouveau_fence_wait(fence, false, false);
			nouveau_fence_unref(&fence);
		}
+3 −6
Original line number Diff line number Diff line
@@ -209,8 +209,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
		goto done;
	}

	if (!nouveau_fence_new(&fence))
		nouveau_fence_emit(fence, dmem->migrate.chan);
	nouveau_fence_new(&fence, dmem->migrate.chan);
	migrate_vma_pages(&args);
	nouveau_dmem_fence_done(&fence);
	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)
		}
	}

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

	if (!nouveau_fence_new(&fence))
		nouveau_fence_emit(fence, drm->dmem->migrate.chan);
	nouveau_fence_new(&fence, drm->dmem->migrate.chan);
	migrate_vma_pages(args);
	nouveau_dmem_fence_done(&fence);
	nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);
+8 −3
Original line number Diff line number Diff line
@@ -96,7 +96,8 @@ nouveau_exec_job_submit(struct nouveau_job *job)
	unsigned long index;
	int ret;

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

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

	ret = nouveau_fence_emit(fence, chan);
	ret = nouveau_fence_emit(fence);
	if (ret) {
		nouveau_fence_unref(&exec_job->fence);
		NV_PRINTK(err, job->cli, "error fencing pushbuf: %d\n", ret);
		WIND_RING(chan);
		return ERR_PTR(ret);
	}

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

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

	nouveau_job_free(job);

	nouveau_fence_unref(&exec_job->fence);
	kfree(exec_job->fence);
	kfree(exec_job->push.s);
	kfree(exec_job);
}
Loading