drm/nouveau: fence: separate fence alloc and emit
The new (VM_BIND) UAPI exports DMA fences through DRM syncobjs. Hence, in order to emit fences within DMA fence signalling critical sections (e.g. as typically done in the DRM GPU schedulers run_job() callback) we need to separate fence allocation and fence emitting. Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230804182406.5222-8-dakr@redhat.com
This commit is contained in:
parent
fbc0ced450
commit
7f2a0b50b2
7 changed files with 59 additions and 41 deletions
|
@ -1122,11 +1122,18 @@ nv04_page_flip_emit(struct nouveau_channel *chan,
|
||||||
PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000);
|
PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000);
|
||||||
PUSH_KICK(push);
|
PUSH_KICK(push);
|
||||||
|
|
||||||
ret = nouveau_fence_new(chan, false, pfence);
|
ret = nouveau_fence_new(pfence);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
ret = nouveau_fence_emit(*pfence, chan);
|
||||||
|
if (ret)
|
||||||
|
goto fail_fence_unref;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_fence_unref:
|
||||||
|
nouveau_fence_unref(pfence);
|
||||||
fail:
|
fail:
|
||||||
spin_lock_irqsave(&dev->event_lock, flags);
|
spin_lock_irqsave(&dev->event_lock, flags);
|
||||||
list_del(&s->head);
|
list_del(&s->head);
|
||||||
|
|
|
@ -823,29 +823,39 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
|
||||||
mutex_lock(&cli->mutex);
|
mutex_lock(&cli->mutex);
|
||||||
else
|
else
|
||||||
mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
|
mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
|
||||||
|
|
||||||
ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible);
|
ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible);
|
||||||
if (ret == 0) {
|
if (ret)
|
||||||
ret = drm->ttm.move(chan, bo, bo->resource, new_reg);
|
goto out_unlock;
|
||||||
if (ret == 0) {
|
|
||||||
ret = nouveau_fence_new(chan, false, &fence);
|
ret = drm->ttm.move(chan, bo, bo->resource, new_reg);
|
||||||
if (ret == 0) {
|
if (ret)
|
||||||
/* TODO: figure out a better solution here
|
goto out_unlock;
|
||||||
*
|
|
||||||
* wait on the fence here explicitly as going through
|
ret = nouveau_fence_new(&fence);
|
||||||
* ttm_bo_move_accel_cleanup somehow doesn't seem to do it.
|
if (ret)
|
||||||
*
|
goto out_unlock;
|
||||||
* Without this the operation can timeout and we'll fallback to a
|
|
||||||
* software copy, which might take several minutes to finish.
|
ret = nouveau_fence_emit(fence, chan);
|
||||||
*/
|
if (ret) {
|
||||||
nouveau_fence_wait(fence, false, false);
|
nouveau_fence_unref(&fence);
|
||||||
ret = ttm_bo_move_accel_cleanup(bo,
|
goto out_unlock;
|
||||||
&fence->base,
|
|
||||||
evict, false,
|
|
||||||
new_reg);
|
|
||||||
nouveau_fence_unref(&fence);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: figure out a better solution here
|
||||||
|
*
|
||||||
|
* wait on the fence here explicitly as going through
|
||||||
|
* ttm_bo_move_accel_cleanup somehow doesn't seem to do it.
|
||||||
|
*
|
||||||
|
* Without this the operation can timeout and we'll fallback to a
|
||||||
|
* software copy, which might take several minutes to finish.
|
||||||
|
*/
|
||||||
|
nouveau_fence_wait(fence, false, false);
|
||||||
|
ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false,
|
||||||
|
new_reg);
|
||||||
|
nouveau_fence_unref(&fence);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
mutex_unlock(&cli->mutex);
|
mutex_unlock(&cli->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,9 +62,11 @@ nouveau_channel_idle(struct nouveau_channel *chan)
|
||||||
struct nouveau_fence *fence = NULL;
|
struct nouveau_fence *fence = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nouveau_fence_new(chan, false, &fence);
|
ret = nouveau_fence_new(&fence);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = nouveau_fence_wait(fence, false, false);
|
ret = nouveau_fence_emit(fence, chan);
|
||||||
|
if (!ret)
|
||||||
|
ret = nouveau_fence_wait(fence, false, false);
|
||||||
nouveau_fence_unref(&fence);
|
nouveau_fence_unref(&fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,8 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
nouveau_fence_new(dmem->migrate.chan, false, &fence);
|
if (!nouveau_fence_new(&fence))
|
||||||
|
nouveau_fence_emit(fence, dmem->migrate.chan);
|
||||||
migrate_vma_pages(&args);
|
migrate_vma_pages(&args);
|
||||||
nouveau_dmem_fence_done(&fence);
|
nouveau_dmem_fence_done(&fence);
|
||||||
dma_unmap_page(drm->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
|
dma_unmap_page(drm->dev->dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||||
|
@ -402,7 +403,8 @@ nouveau_dmem_evict_chunk(struct nouveau_dmem_chunk *chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nouveau_fence_new(chunk->drm->dmem->migrate.chan, false, &fence);
|
if (!nouveau_fence_new(&fence))
|
||||||
|
nouveau_fence_emit(fence, chunk->drm->dmem->migrate.chan);
|
||||||
migrate_device_pages(src_pfns, dst_pfns, npages);
|
migrate_device_pages(src_pfns, dst_pfns, npages);
|
||||||
nouveau_dmem_fence_done(&fence);
|
nouveau_dmem_fence_done(&fence);
|
||||||
migrate_device_finalize(src_pfns, dst_pfns, npages);
|
migrate_device_finalize(src_pfns, dst_pfns, npages);
|
||||||
|
@ -675,7 +677,8 @@ static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
|
||||||
addr += PAGE_SIZE;
|
addr += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nouveau_fence_new(drm->dmem->migrate.chan, false, &fence);
|
if (!nouveau_fence_new(&fence))
|
||||||
|
nouveau_fence_emit(fence, chunk->drm->dmem->migrate.chan);
|
||||||
migrate_vma_pages(args);
|
migrate_vma_pages(args);
|
||||||
nouveau_dmem_fence_done(&fence);
|
nouveau_dmem_fence_done(&fence);
|
||||||
nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);
|
nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);
|
||||||
|
|
|
@ -210,6 +210,9 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
|
||||||
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
|
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (unlikely(!chan->fence))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
fence->channel = chan;
|
fence->channel = chan;
|
||||||
fence->timeout = jiffies + (15 * HZ);
|
fence->timeout = jiffies + (15 * HZ);
|
||||||
|
|
||||||
|
@ -396,25 +399,16 @@ nouveau_fence_unref(struct nouveau_fence **pfence)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nouveau_fence_new(struct nouveau_channel *chan, bool sysmem,
|
nouveau_fence_new(struct nouveau_fence **pfence)
|
||||||
struct nouveau_fence **pfence)
|
|
||||||
{
|
{
|
||||||
struct nouveau_fence *fence;
|
struct nouveau_fence *fence;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (unlikely(!chan->fence))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
||||||
if (!fence)
|
if (!fence)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = nouveau_fence_emit(fence, chan);
|
|
||||||
if (ret)
|
|
||||||
nouveau_fence_unref(&fence);
|
|
||||||
|
|
||||||
*pfence = fence;
|
*pfence = fence;
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *nouveau_fence_get_get_driver_name(struct dma_fence *fence)
|
static const char *nouveau_fence_get_get_driver_name(struct dma_fence *fence)
|
||||||
|
|
|
@ -17,8 +17,7 @@ struct nouveau_fence {
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
int nouveau_fence_new(struct nouveau_channel *, bool sysmem,
|
int nouveau_fence_new(struct nouveau_fence **);
|
||||||
struct nouveau_fence **);
|
|
||||||
void nouveau_fence_unref(struct nouveau_fence **);
|
void nouveau_fence_unref(struct nouveau_fence **);
|
||||||
|
|
||||||
int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
|
int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
|
||||||
|
|
|
@ -873,8 +873,11 @@ revalidate:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nouveau_fence_new(chan, false, &fence);
|
ret = nouveau_fence_new(&fence);
|
||||||
|
if (!ret)
|
||||||
|
ret = nouveau_fence_emit(fence, chan);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
nouveau_fence_unref(&fence);
|
||||||
NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret);
|
NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret);
|
||||||
WIND_RING(chan);
|
WIND_RING(chan);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Loading…
Add table
Reference in a new issue