Commit 862450a8 authored by Ben Skeggs's avatar Ben Skeggs Committed by Dave Airlie
Browse files

drm/nouveau/gf100-: track chan progress with non-WFI semaphore release



From VOLTA_CHANNEL_GPFIFO_A onwards, HW no longer updates the GET/GP_GET
pointers in USERD following channel progress, but instead updates on a
timer for compatibility, and SW is expected to implement its own method
of tracking channel progress (typically via non-WFI semaphore release).

Nouveau has been making use of the compatibility mode up until now,
however, from BLACKWELL_CHANNEL_GPFIFO_A HW no longer supports USERD
writeback at all.

Allocate a per-channel buffer in system memory, and append a non-WFI
semaphore release to the end of each push buffer segment to simulate
the pointers previously read from USERD.

This change is implemented for Fermi (which is the first to support non-
WFI semaphore release) onwards, as readback from system memory is likely
faster than BAR1 reads.

Signed-off-by: default avatarBen Skeggs <bskeggs@nvidia.com>
Reviewed-by: default avatarDave Airlie <airlied@redhat.com>
Reviewed-by: default avatarTimur Tabi <ttabi@nvidia.com>
Tested-by: default avatarTimur Tabi <ttabi@nvidia.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent d1fb887a
Loading
Loading
Loading
Loading
+25 −5
Original line number Diff line number Diff line
@@ -17,7 +17,13 @@ struct nvif_chan {
			void (*push)(struct nvif_chan *, bool main, u64 addr, u32 size,
				     bool no_prefetch);
			void (*kick)(struct nvif_chan *);
			int (*post)(struct nvif_chan *, u32 gpptr, u32 pbptr);
			u32 post_size;
		} gpfifo;

		struct {
			int (*release)(struct nvif_chan *, u64 addr, u32 data);
		} sem;
	} *func;

	struct {
@@ -31,6 +37,11 @@ struct nvif_chan {
		int free;
	} gpfifo;

	struct {
		struct nvif_map map;
		u64 addr;
	} sema;

	struct nvif_push push;

	struct nvif_user *usermode;
@@ -43,14 +54,23 @@ void nvif_chan_gpfifo_ctor(const struct nvif_chan_func *, void *userd, void *gpf
			   void *push, u64 push_addr, u32 push_size, struct nvif_chan *);
int nvif_chan_gpfifo_wait(struct nvif_chan *, u32 gpfifo_nr, u32 push_nr);
void nvif_chan_gpfifo_push(struct nvif_chan *, u64 addr, u32 size, bool no_prefetch);
int nvif_chan_gpfifo_post(struct nvif_chan *);

int nvif_chan506f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
		       void *push, u64 push_addr, u32 push_size);
u32 nvif_chan506f_read_get(struct nvif_chan *);
u32 nvif_chan506f_gpfifo_read_get(struct nvif_chan *);
void nvif_chan506f_gpfifo_push(struct nvif_chan *, bool main, u64 addr, u32 size, bool no_prefetch);
void nvif_chan506f_gpfifo_kick(struct nvif_chan *);

int nvif_chan906f_ctor_(const struct nvif_chan_func *, void *userd, void *gpfifo, u32 gpfifo_size,
			void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr,
			struct nvif_chan *);
u32 nvif_chan906f_read_get(struct nvif_chan *);
u32 nvif_chan906f_gpfifo_read_get(struct nvif_chan *);
int nvif_chan906f_gpfifo_post(struct nvif_chan *, u32 gpptr, u32 pbptr);

int nvif_chan506f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
		       void *push, u64 push_addr, u32 push_size);
int nvif_chan906f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
		       void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr);
int nvif_chanc36f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
		       void *push, u64 push_addr, u32 push_size,
		       void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr,
		       struct nvif_user *usermode, u32 doorbell_token);
#endif
+22 −0
Original line number Diff line number Diff line
@@ -456,6 +456,28 @@ nouveau_bo_new_map(struct nouveau_cli *cli, u32 domain, u32 size, struct nouveau
	return 0;
}

int
nouveau_bo_new_map_gpu(struct nouveau_cli *cli, u32 domain, u32 size,
		       struct nouveau_bo **pnvbo, struct nouveau_vma **pvma)
{
	struct nouveau_vmm *vmm = nouveau_cli_vmm(cli);
	struct nouveau_bo *nvbo;
	int ret;

	ret = nouveau_bo_new_map(cli, domain, size, &nvbo);
	if (ret)
		return ret;

	ret = nouveau_vma_new(nvbo, vmm, pvma);
	if (ret) {
		nouveau_bo_unpin_del(&nvbo);
		return ret;
	}

	*pnvbo = nvbo;
	return 0;
}

static void
set_placement_range(struct nouveau_bo *nvbo, uint32_t domain)
{
+2 −0
Original line number Diff line number Diff line
@@ -92,6 +92,8 @@ void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo);

int nouveau_bo_new_pin(struct nouveau_cli *, u32 domain, u32 size, struct nouveau_bo **);
int nouveau_bo_new_map(struct nouveau_cli *, u32 domain, u32 size, struct nouveau_bo **);
int nouveau_bo_new_map_gpu(struct nouveau_cli *, u32 domain, u32 size,
			   struct nouveau_bo **, struct nouveau_vma **);
void nouveau_bo_unpin_del(struct nouveau_bo **);

/* TODO: submit equivalent to TTM generic API upstream? */
+16 −3
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ nouveau_channel_del(struct nouveau_channel **pchan)
		nvif_event_dtor(&chan->kill);
		nvif_object_dtor(&chan->user);
		nvif_mem_dtor(&chan->mem_userd);
		nouveau_vma_del(&chan->sema.vma);
		nouveau_bo_unpin_del(&chan->sema.bo);
		nvif_object_dtor(&chan->push.ctxdma);
		nouveau_vma_del(&chan->push.vma);
		nouveau_bo_unpin_del(&chan->push.buffer);
@@ -189,8 +191,10 @@ nouveau_channel_prep(struct nouveau_cli *cli,

		chan->push.addr = chan->push.vma->addr;

		if (device->info.family >= NV_DEVICE_INFO_V0_FERMI)
			return 0;
		if (device->info.family >= NV_DEVICE_INFO_V0_FERMI) {
			return nouveau_bo_new_map_gpu(cli, NOUVEAU_GEM_DOMAIN_GART, PAGE_SIZE,
						      &chan->sema.bo, &chan->sema.vma);
		}

		args.target = NV_DMA_V0_TARGET_VM;
		args.access = NV_DMA_V0_ACCESS_VM;
@@ -429,16 +433,25 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
		chan->user_get = 0x44;
		chan->dma.max = (0x10000 / 4) - 2;
	} else
	if (chan->user.oclass < VOLTA_CHANNEL_GPFIFO_A) {
	if (chan->user.oclass < FERMI_CHANNEL_GPFIFO) {
		ret = nvif_chan506f_ctor(&chan->chan, chan->userd->map.ptr,
					 (u8*)chan->push.buffer->kmap.virtual + 0x10000, 0x2000,
					 chan->push.buffer->kmap.virtual, chan->push.addr, 0x10000);
		if (ret)
			return ret;
	} else
	if (chan->user.oclass < VOLTA_CHANNEL_GPFIFO_A) {
		ret = nvif_chan906f_ctor(&chan->chan, chan->userd->map.ptr,
					 (u8*)chan->push.buffer->kmap.virtual + 0x10000, 0x2000,
					 chan->push.buffer->kmap.virtual, chan->push.addr, 0x10000,
					 chan->sema.bo->kmap.virtual, chan->sema.vma->addr);
		if (ret)
			return ret;
	} else {
		ret = nvif_chanc36f_ctor(&chan->chan, chan->userd->map.ptr,
					 (u8*)chan->push.buffer->kmap.virtual + 0x10000, 0x2000,
					 chan->push.buffer->kmap.virtual, chan->push.addr, 0x10000,
					 chan->sema.bo->kmap.virtual, chan->sema.vma->addr,
					 &drm->client.device.user, chan->token);
		if (ret)
			return ret;
+5 −0
Original line number Diff line number Diff line
@@ -43,6 +43,11 @@ struct nouveau_channel {
	u32 user_get;
	u32 user_put;

	struct {
		struct nouveau_bo *bo;
		struct nouveau_vma *vma;
	} sema;

	struct nvif_object user;
	struct nvif_object blit;

Loading