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

drm/nouveau/nv50-: separate CHANNEL_GPFIFO handling out from CHANNEL_DMA



Primarily a cleanup to allow for changes in newer CHANNEL_GPFIFO classes
to be more easily implemented.

Compared to the prior implementation, this submits userspace push buffer
segments as subroutines and uses the NV_RAMUSERD_TOP_LEVEL_GET registers
to track the main (kernel) push buffer progress.

Fixes a number of sporadic failures seen during piglit runs.

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 627664de
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT
 *
 * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
 */
#ifndef __NVIF_CHAN_H__
#define __NVIF_CHAN_H__
#include "push.h"

struct nvif_chan {
	const struct nvif_chan_func {
		struct {
			u32 (*read_get)(struct nvif_chan *);
		} push;

		struct {
			u32 (*read_get)(struct nvif_chan *);
			void (*push)(struct nvif_chan *, bool main, u64 addr, u32 size,
				     bool no_prefetch);
			void (*kick)(struct nvif_chan *);
		} gpfifo;
	} *func;

	struct {
		struct nvif_map map;
	} userd;

	struct {
		struct nvif_map map;
		u32 cur;
		u32 max;
		int free;
	} gpfifo;

	struct nvif_push push;

	struct nvif_user *usermode;
	u32 doorbell_token;
};

int nvif_chan_dma_wait(struct nvif_chan *, u32 push_nr);

void nvif_chan_gpfifo_ctor(const struct nvif_chan_func *, void *userd, void *gpfifo, u32 gpfifo_size,
			   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_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);

int nvif_chanc36f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
		       void *push, u64 push_addr, u32 push_size,
		       struct nvif_user *usermode, u32 doorbell_token);
#endif
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ struct nvif_object {
	u32 handle;
	s32 oclass;
	void *priv; /*XXX: hack */
	struct {
	struct nvif_map {
		void __iomem *ptr;
		u64 size;
	} map;
+12 −2
Original line number Diff line number Diff line
@@ -31,6 +31,12 @@ struct nvif_push {
	void (*kick)(struct nvif_push *push);

	struct nvif_mem mem;
	u64 addr;

	struct {
		u32 get;
		u32 max;
	} hw;

	u32 *bgn;
	u32 *cur;
@@ -41,7 +47,7 @@ struct nvif_push {
static inline __must_check int
PUSH_WAIT(struct nvif_push *push, u32 size)
{
	if (push->cur + size >= push->end) {
	if (push->cur + size > push->end) {
		int ret = push->wait(push, size);
		if (ret)
			return ret;
@@ -55,7 +61,11 @@ PUSH_WAIT(struct nvif_push *push, u32 size)
static inline int
PUSH_KICK(struct nvif_push *push)
{
	if (push->cur != push->bgn) {
		push->kick(push);
		push->bgn = push->cur;
	}

	return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -416,7 +416,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
	 */
	if (nouveau_cli_uvmm(cli)) {
		ret = nouveau_sched_create(&chan->sched, drm, drm->sched_wq,
					   chan->chan->dma.ib_max);
					   chan->chan->chan.gpfifo.max);
		if (ret)
			goto done;
	}
+15 −16
Original line number Diff line number Diff line
@@ -424,25 +424,24 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
	}

	/* initialise dma tracking parameters */
	switch (chan->user.oclass) {
	case NV03_CHANNEL_DMA:
	case NV10_CHANNEL_DMA:
	case NV17_CHANNEL_DMA:
	case NV40_CHANNEL_DMA:
	if (chan->user.oclass < NV50_CHANNEL_GPFIFO) {
		chan->user_put = 0x40;
		chan->user_get = 0x44;
		chan->dma.max = (0x10000 / 4) - 2;
		break;
	default:
		chan->user_put = 0x40;
		chan->user_get = 0x44;
		chan->user_get_hi = 0x60;
		chan->dma.ib_base =  0x10000 / 4;
		chan->dma.ib_max  = NV50_DMA_IB_MAX;
		chan->dma.ib_put  = 0;
		chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
		chan->dma.max = chan->dma.ib_base;
		break;
	} else
	if (chan->user.oclass < VOLTA_CHANNEL_GPFIFO_A) {
		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 {
		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,
					 &drm->client.device.user, chan->token);
		if (ret)
			return ret;
	}

	chan->dma.put = 0;
Loading