Skip to content

Commit d1fb887

Browse files
Ben Skeggsairlied
authored andcommitted
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: Ben Skeggs <[email protected]> Reviewed-by: Dave Airlie <[email protected]> Reviewed-by: Timur Tabi <[email protected]> Tested-by: Timur Tabi <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
1 parent 627664d commit d1fb887

File tree

14 files changed

+344
-149
lines changed

14 files changed

+344
-149
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* SPDX-License-Identifier: MIT
2+
*
3+
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4+
*/
5+
#ifndef __NVIF_CHAN_H__
6+
#define __NVIF_CHAN_H__
7+
#include "push.h"
8+
9+
struct nvif_chan {
10+
const struct nvif_chan_func {
11+
struct {
12+
u32 (*read_get)(struct nvif_chan *);
13+
} push;
14+
15+
struct {
16+
u32 (*read_get)(struct nvif_chan *);
17+
void (*push)(struct nvif_chan *, bool main, u64 addr, u32 size,
18+
bool no_prefetch);
19+
void (*kick)(struct nvif_chan *);
20+
} gpfifo;
21+
} *func;
22+
23+
struct {
24+
struct nvif_map map;
25+
} userd;
26+
27+
struct {
28+
struct nvif_map map;
29+
u32 cur;
30+
u32 max;
31+
int free;
32+
} gpfifo;
33+
34+
struct nvif_push push;
35+
36+
struct nvif_user *usermode;
37+
u32 doorbell_token;
38+
};
39+
40+
int nvif_chan_dma_wait(struct nvif_chan *, u32 push_nr);
41+
42+
void nvif_chan_gpfifo_ctor(const struct nvif_chan_func *, void *userd, void *gpfifo, u32 gpfifo_size,
43+
void *push, u64 push_addr, u32 push_size, struct nvif_chan *);
44+
int nvif_chan_gpfifo_wait(struct nvif_chan *, u32 gpfifo_nr, u32 push_nr);
45+
void nvif_chan_gpfifo_push(struct nvif_chan *, u64 addr, u32 size, bool no_prefetch);
46+
47+
int nvif_chan506f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
48+
void *push, u64 push_addr, u32 push_size);
49+
u32 nvif_chan506f_read_get(struct nvif_chan *);
50+
u32 nvif_chan506f_gpfifo_read_get(struct nvif_chan *);
51+
void nvif_chan506f_gpfifo_push(struct nvif_chan *, bool main, u64 addr, u32 size, bool no_prefetch);
52+
53+
int nvif_chanc36f_ctor(struct nvif_chan *, void *userd, void *gpfifo, u32 gpfifo_size,
54+
void *push, u64 push_addr, u32 push_size,
55+
struct nvif_user *usermode, u32 doorbell_token);
56+
#endif

drivers/gpu/drm/nouveau/include/nvif/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct nvif_object {
1616
u32 handle;
1717
s32 oclass;
1818
void *priv; /*XXX: hack */
19-
struct {
19+
struct nvif_map {
2020
void __iomem *ptr;
2121
u64 size;
2222
} map;

drivers/gpu/drm/nouveau/include/nvif/push.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ struct nvif_push {
3131
void (*kick)(struct nvif_push *push);
3232

3333
struct nvif_mem mem;
34+
u64 addr;
35+
36+
struct {
37+
u32 get;
38+
u32 max;
39+
} hw;
3440

3541
u32 *bgn;
3642
u32 *cur;
@@ -41,7 +47,7 @@ struct nvif_push {
4147
static inline __must_check int
4248
PUSH_WAIT(struct nvif_push *push, u32 size)
4349
{
44-
if (push->cur + size >= push->end) {
50+
if (push->cur + size > push->end) {
4551
int ret = push->wait(push, size);
4652
if (ret)
4753
return ret;
@@ -55,7 +61,11 @@ PUSH_WAIT(struct nvif_push *push, u32 size)
5561
static inline int
5662
PUSH_KICK(struct nvif_push *push)
5763
{
58-
push->kick(push);
64+
if (push->cur != push->bgn) {
65+
push->kick(push);
66+
push->bgn = push->cur;
67+
}
68+
5969
return 0;
6070
}
6171

drivers/gpu/drm/nouveau/nouveau_abi16.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
416416
*/
417417
if (nouveau_cli_uvmm(cli)) {
418418
ret = nouveau_sched_create(&chan->sched, drm, drm->sched_wq,
419-
chan->chan->dma.ib_max);
419+
chan->chan->chan.gpfifo.max);
420420
if (ret)
421421
goto done;
422422
}

drivers/gpu/drm/nouveau/nouveau_chan.c

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -424,25 +424,24 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
424424
}
425425

426426
/* initialise dma tracking parameters */
427-
switch (chan->user.oclass) {
428-
case NV03_CHANNEL_DMA:
429-
case NV10_CHANNEL_DMA:
430-
case NV17_CHANNEL_DMA:
431-
case NV40_CHANNEL_DMA:
427+
if (chan->user.oclass < NV50_CHANNEL_GPFIFO) {
432428
chan->user_put = 0x40;
433429
chan->user_get = 0x44;
434430
chan->dma.max = (0x10000 / 4) - 2;
435-
break;
436-
default:
437-
chan->user_put = 0x40;
438-
chan->user_get = 0x44;
439-
chan->user_get_hi = 0x60;
440-
chan->dma.ib_base = 0x10000 / 4;
441-
chan->dma.ib_max = NV50_DMA_IB_MAX;
442-
chan->dma.ib_put = 0;
443-
chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
444-
chan->dma.max = chan->dma.ib_base;
445-
break;
431+
} else
432+
if (chan->user.oclass < VOLTA_CHANNEL_GPFIFO_A) {
433+
ret = nvif_chan506f_ctor(&chan->chan, chan->userd->map.ptr,
434+
(u8*)chan->push.buffer->kmap.virtual + 0x10000, 0x2000,
435+
chan->push.buffer->kmap.virtual, chan->push.addr, 0x10000);
436+
if (ret)
437+
return ret;
438+
} else {
439+
ret = nvif_chanc36f_ctor(&chan->chan, chan->userd->map.ptr,
440+
(u8*)chan->push.buffer->kmap.virtual + 0x10000, 0x2000,
441+
chan->push.buffer->kmap.virtual, chan->push.addr, 0x10000,
442+
&drm->client.device.user, chan->token);
443+
if (ret)
444+
return ret;
446445
}
447446

448447
chan->dma.put = 0;

drivers/gpu/drm/nouveau/nouveau_chan.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33
#define __NOUVEAU_CHAN_H__
44
#include <nvif/object.h>
55
#include <nvif/event.h>
6-
#include <nvif/push.h>
6+
#include <nvif/chan.h>
77
struct nvif_device;
88

99
struct nouveau_channel {
10-
struct {
11-
struct nvif_push push;
12-
} chan;
10+
struct nvif_chan chan;
1311

1412
struct nouveau_cli *cli;
1513
struct nouveau_vmm *vmm;
@@ -41,12 +39,7 @@ struct nouveau_channel {
4139
int free;
4240
int cur;
4341
int put;
44-
int ib_base;
45-
int ib_max;
46-
int ib_free;
47-
int ib_put;
4842
} dma;
49-
u32 user_get_hi;
5043
u32 user_get;
5144
u32 user_put;
5245

drivers/gpu/drm/nouveau/nouveau_dma.c

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
4343
uint64_t val;
4444

4545
val = nvif_rd32(chan->userd, chan->user_get);
46-
if (chan->user_get_hi)
47-
val |= (uint64_t)nvif_rd32(chan->userd, chan->user_get_hi) << 32;
4846

4947
/* reset counter as long as GET is still advancing, this is
5048
* to avoid misdetecting a GPU lockup if the GPU happens to
@@ -68,111 +66,12 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
6866
return (val - chan->push.addr) >> 2;
6967
}
7068

71-
void
72-
nv50_dma_push(struct nouveau_channel *chan, u64 offset, u32 length,
73-
bool no_prefetch)
74-
{
75-
struct nvif_user *user = &chan->cli->drm->client.device.user;
76-
struct nouveau_bo *pb = chan->push.buffer;
77-
int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
78-
79-
BUG_ON(chan->dma.ib_free < 1);
80-
WARN_ON(length > NV50_DMA_PUSH_MAX_LENGTH);
81-
82-
nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
83-
nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8 |
84-
(no_prefetch ? (1 << 31) : 0));
85-
86-
chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
87-
88-
mb();
89-
/* Flush writes. */
90-
nouveau_bo_rd32(pb, 0);
91-
92-
nvif_wr32(chan->userd, 0x8c, chan->dma.ib_put);
93-
if (user->func && user->func->doorbell)
94-
user->func->doorbell(user, chan->token);
95-
chan->dma.ib_free--;
96-
}
97-
98-
static int
99-
nv50_dma_push_wait(struct nouveau_channel *chan, int count)
100-
{
101-
uint32_t cnt = 0, prev_get = 0;
102-
103-
while (chan->dma.ib_free < count) {
104-
uint32_t get = nvif_rd32(chan->userd, 0x88);
105-
if (get != prev_get) {
106-
prev_get = get;
107-
cnt = 0;
108-
}
109-
110-
if ((++cnt & 0xff) == 0) {
111-
udelay(1);
112-
if (cnt > 100000)
113-
return -EBUSY;
114-
}
115-
116-
chan->dma.ib_free = get - chan->dma.ib_put;
117-
if (chan->dma.ib_free <= 0)
118-
chan->dma.ib_free += chan->dma.ib_max;
119-
}
120-
121-
return 0;
122-
}
123-
124-
static int
125-
nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
126-
{
127-
uint64_t prev_get = 0;
128-
int ret, cnt = 0;
129-
130-
ret = nv50_dma_push_wait(chan, slots + 1);
131-
if (unlikely(ret))
132-
return ret;
133-
134-
while (chan->dma.free < count) {
135-
int get = READ_GET(chan, &prev_get, &cnt);
136-
if (unlikely(get < 0)) {
137-
if (get == -EINVAL)
138-
continue;
139-
140-
return get;
141-
}
142-
143-
if (get <= chan->dma.cur) {
144-
chan->dma.free = chan->dma.max - chan->dma.cur;
145-
if (chan->dma.free >= count)
146-
break;
147-
148-
FIRE_RING(chan);
149-
do {
150-
get = READ_GET(chan, &prev_get, &cnt);
151-
if (unlikely(get < 0)) {
152-
if (get == -EINVAL)
153-
continue;
154-
return get;
155-
}
156-
} while (get == 0);
157-
chan->dma.cur = 0;
158-
chan->dma.put = 0;
159-
}
160-
161-
chan->dma.free = get - chan->dma.cur - 1;
162-
}
163-
164-
return 0;
165-
}
166-
16769
int
168-
nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
70+
nouveau_dma_wait(struct nouveau_channel *chan, int size)
16971
{
17072
uint64_t prev_get = 0;
17173
int cnt = 0, get;
17274

173-
if (chan->dma.ib_max)
174-
return nv50_dma_wait(chan, slots, size);
175-
17675
while (chan->dma.free < size) {
17776
get = READ_GET(chan, &prev_get, &cnt);
17877
if (unlikely(get == -EBUSY))

drivers/gpu/drm/nouveau/nouveau_dma.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
#include "nouveau_bo.h"
3131
#include "nouveau_chan.h"
3232

33-
int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
34-
void nv50_dma_push(struct nouveau_channel *, u64 addr, u32 length,
35-
bool no_prefetch);
33+
int nouveau_dma_wait(struct nouveau_channel *, int size);
3634

3735
/*
3836
* There's a hw race condition where you can't jump to your PUT offset,
@@ -67,7 +65,7 @@ RING_SPACE(struct nouveau_channel *chan, int size)
6765
{
6866
int ret;
6967

70-
ret = nouveau_dma_wait(chan, 1, size);
68+
ret = nouveau_dma_wait(chan, size);
7169
if (ret)
7270
return ret;
7371

@@ -94,12 +92,7 @@ FIRE_RING(struct nouveau_channel *chan)
9492
return;
9593
chan->accel_done = true;
9694

97-
if (chan->dma.ib_max) {
98-
nv50_dma_push(chan, chan->push.addr + (chan->dma.put << 2),
99-
(chan->dma.cur - chan->dma.put) << 2, false);
100-
} else {
101-
WRITE_PUT(chan->dma.cur);
102-
}
95+
WRITE_PUT(chan->dma.cur);
10396

10497
chan->dma.put = chan->dma.cur;
10598
}

drivers/gpu/drm/nouveau/nouveau_exec.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "nouveau_sched.h"
1111
#include "nouveau_uvmm.h"
1212

13+
#include <nvif/class.h>
14+
1315
/**
1416
* DOC: Overview
1517
*
@@ -131,7 +133,7 @@ nouveau_exec_job_run(struct nouveau_job *job)
131133
struct nouveau_fence *fence = exec_job->fence;
132134
int i, ret;
133135

134-
ret = nouveau_dma_wait(chan, exec_job->push.count + 1, 16);
136+
ret = nvif_chan_gpfifo_wait(&chan->chan, exec_job->push.count + 1, 16);
135137
if (ret) {
136138
NV_PRINTK(err, job->cli, "nv50cal_space: %d\n", ret);
137139
return ERR_PTR(ret);
@@ -141,7 +143,7 @@ nouveau_exec_job_run(struct nouveau_job *job)
141143
struct drm_nouveau_exec_push *p = &exec_job->push.s[i];
142144
bool no_prefetch = p->flags & DRM_NOUVEAU_EXEC_PUSH_NO_PREFETCH;
143145

144-
nv50_dma_push(chan, p->va, p->va_len, no_prefetch);
146+
nvif_chan_gpfifo_push(&chan->chan, p->va, p->va_len, no_prefetch);
145147
}
146148

147149
ret = nouveau_fence_emit(fence);
@@ -375,10 +377,10 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
375377
if (unlikely(atomic_read(&chan->killed)))
376378
return nouveau_abi16_put(abi16, -ENODEV);
377379

378-
if (!chan->dma.ib_max)
380+
if (chan->user.oclass < NV50_CHANNEL_GPFIFO)
379381
return nouveau_abi16_put(abi16, -ENOSYS);
380382

381-
push_max = nouveau_exec_push_max_from_ib_max(chan->dma.ib_max);
383+
push_max = nouveau_exec_push_max_from_ib_max(chan->chan.gpfifo.max);
382384
if (unlikely(req->push_count > push_max)) {
383385
NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
384386
req->push_count, push_max);

0 commit comments

Comments
 (0)