mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 03:10:30 -04:00
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 <bskeggs@nvidia.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Timur Tabi <ttabi@nvidia.com> Tested-by: Timur Tabi <ttabi@nvidia.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
56
drivers/gpu/drm/nouveau/include/nvif/chan.h
Normal file
56
drivers/gpu/drm/nouveau/include/nvif/chan.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
push->kick(push);
|
||||
if (push->cur != push->bgn) {
|
||||
push->kick(push);
|
||||
push->bgn = push->cur;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#define __NOUVEAU_CHAN_H__
|
||||
#include <nvif/object.h>
|
||||
#include <nvif/event.h>
|
||||
#include <nvif/push.h>
|
||||
#include <nvif/chan.h>
|
||||
struct nvif_device;
|
||||
|
||||
struct nouveau_channel {
|
||||
struct {
|
||||
struct nvif_push push;
|
||||
} chan;
|
||||
struct nvif_chan chan;
|
||||
|
||||
struct nouveau_cli *cli;
|
||||
struct nouveau_vmm *vmm;
|
||||
@@ -41,12 +39,7 @@ struct nouveau_channel {
|
||||
int free;
|
||||
int cur;
|
||||
int put;
|
||||
int ib_base;
|
||||
int ib_max;
|
||||
int ib_free;
|
||||
int ib_put;
|
||||
} dma;
|
||||
u32 user_get_hi;
|
||||
u32 user_get;
|
||||
u32 user_put;
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
|
||||
uint64_t val;
|
||||
|
||||
val = nvif_rd32(chan->userd, chan->user_get);
|
||||
if (chan->user_get_hi)
|
||||
val |= (uint64_t)nvif_rd32(chan->userd, chan->user_get_hi) << 32;
|
||||
|
||||
/* reset counter as long as GET is still advancing, this is
|
||||
* 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)
|
||||
return (val - chan->push.addr) >> 2;
|
||||
}
|
||||
|
||||
void
|
||||
nv50_dma_push(struct nouveau_channel *chan, u64 offset, u32 length,
|
||||
bool no_prefetch)
|
||||
{
|
||||
struct nvif_user *user = &chan->cli->drm->client.device.user;
|
||||
struct nouveau_bo *pb = chan->push.buffer;
|
||||
int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
|
||||
|
||||
BUG_ON(chan->dma.ib_free < 1);
|
||||
WARN_ON(length > NV50_DMA_PUSH_MAX_LENGTH);
|
||||
|
||||
nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
|
||||
nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8 |
|
||||
(no_prefetch ? (1 << 31) : 0));
|
||||
|
||||
chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
|
||||
|
||||
mb();
|
||||
/* Flush writes. */
|
||||
nouveau_bo_rd32(pb, 0);
|
||||
|
||||
nvif_wr32(chan->userd, 0x8c, chan->dma.ib_put);
|
||||
if (user->func && user->func->doorbell)
|
||||
user->func->doorbell(user, chan->token);
|
||||
chan->dma.ib_free--;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_dma_push_wait(struct nouveau_channel *chan, int count)
|
||||
{
|
||||
uint32_t cnt = 0, prev_get = 0;
|
||||
|
||||
while (chan->dma.ib_free < count) {
|
||||
uint32_t get = nvif_rd32(chan->userd, 0x88);
|
||||
if (get != prev_get) {
|
||||
prev_get = get;
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
if ((++cnt & 0xff) == 0) {
|
||||
udelay(1);
|
||||
if (cnt > 100000)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
chan->dma.ib_free = get - chan->dma.ib_put;
|
||||
if (chan->dma.ib_free <= 0)
|
||||
chan->dma.ib_free += chan->dma.ib_max;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
|
||||
{
|
||||
uint64_t prev_get = 0;
|
||||
int ret, cnt = 0;
|
||||
|
||||
ret = nv50_dma_push_wait(chan, slots + 1);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
while (chan->dma.free < count) {
|
||||
int get = READ_GET(chan, &prev_get, &cnt);
|
||||
if (unlikely(get < 0)) {
|
||||
if (get == -EINVAL)
|
||||
continue;
|
||||
|
||||
return get;
|
||||
}
|
||||
|
||||
if (get <= chan->dma.cur) {
|
||||
chan->dma.free = chan->dma.max - chan->dma.cur;
|
||||
if (chan->dma.free >= count)
|
||||
break;
|
||||
|
||||
FIRE_RING(chan);
|
||||
do {
|
||||
get = READ_GET(chan, &prev_get, &cnt);
|
||||
if (unlikely(get < 0)) {
|
||||
if (get == -EINVAL)
|
||||
continue;
|
||||
return get;
|
||||
}
|
||||
} while (get == 0);
|
||||
chan->dma.cur = 0;
|
||||
chan->dma.put = 0;
|
||||
}
|
||||
|
||||
chan->dma.free = get - chan->dma.cur - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
|
||||
nouveau_dma_wait(struct nouveau_channel *chan, int size)
|
||||
{
|
||||
uint64_t prev_get = 0;
|
||||
int cnt = 0, get;
|
||||
|
||||
if (chan->dma.ib_max)
|
||||
return nv50_dma_wait(chan, slots, size);
|
||||
|
||||
while (chan->dma.free < size) {
|
||||
get = READ_GET(chan, &prev_get, &cnt);
|
||||
if (unlikely(get == -EBUSY))
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
#include "nouveau_bo.h"
|
||||
#include "nouveau_chan.h"
|
||||
|
||||
int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
|
||||
void nv50_dma_push(struct nouveau_channel *, u64 addr, u32 length,
|
||||
bool no_prefetch);
|
||||
int nouveau_dma_wait(struct nouveau_channel *, int size);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nouveau_dma_wait(chan, 1, size);
|
||||
ret = nouveau_dma_wait(chan, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -94,12 +92,7 @@ FIRE_RING(struct nouveau_channel *chan)
|
||||
return;
|
||||
chan->accel_done = true;
|
||||
|
||||
if (chan->dma.ib_max) {
|
||||
nv50_dma_push(chan, chan->push.addr + (chan->dma.put << 2),
|
||||
(chan->dma.cur - chan->dma.put) << 2, false);
|
||||
} else {
|
||||
WRITE_PUT(chan->dma.cur);
|
||||
}
|
||||
WRITE_PUT(chan->dma.cur);
|
||||
|
||||
chan->dma.put = chan->dma.cur;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "nouveau_sched.h"
|
||||
#include "nouveau_uvmm.h"
|
||||
|
||||
#include <nvif/class.h>
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
*
|
||||
@@ -131,7 +133,7 @@ nouveau_exec_job_run(struct nouveau_job *job)
|
||||
struct nouveau_fence *fence = exec_job->fence;
|
||||
int i, ret;
|
||||
|
||||
ret = nouveau_dma_wait(chan, exec_job->push.count + 1, 16);
|
||||
ret = nvif_chan_gpfifo_wait(&chan->chan, exec_job->push.count + 1, 16);
|
||||
if (ret) {
|
||||
NV_PRINTK(err, job->cli, "nv50cal_space: %d\n", ret);
|
||||
return ERR_PTR(ret);
|
||||
@@ -141,7 +143,7 @@ nouveau_exec_job_run(struct nouveau_job *job)
|
||||
struct drm_nouveau_exec_push *p = &exec_job->push.s[i];
|
||||
bool no_prefetch = p->flags & DRM_NOUVEAU_EXEC_PUSH_NO_PREFETCH;
|
||||
|
||||
nv50_dma_push(chan, p->va, p->va_len, no_prefetch);
|
||||
nvif_chan_gpfifo_push(&chan->chan, p->va, p->va_len, no_prefetch);
|
||||
}
|
||||
|
||||
ret = nouveau_fence_emit(fence);
|
||||
@@ -375,10 +377,10 @@ nouveau_exec_ioctl_exec(struct drm_device *dev,
|
||||
if (unlikely(atomic_read(&chan->killed)))
|
||||
return nouveau_abi16_put(abi16, -ENODEV);
|
||||
|
||||
if (!chan->dma.ib_max)
|
||||
if (chan->user.oclass < NV50_CHANNEL_GPFIFO)
|
||||
return nouveau_abi16_put(abi16, -ENOSYS);
|
||||
|
||||
push_max = nouveau_exec_push_max_from_ib_max(chan->dma.ib_max);
|
||||
push_max = nouveau_exec_push_max_from_ib_max(chan->chan.gpfifo.max);
|
||||
if (unlikely(req->push_count > push_max)) {
|
||||
NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
|
||||
req->push_count, push_max);
|
||||
|
||||
@@ -850,8 +850,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
if (chan->dma.ib_max) {
|
||||
ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
|
||||
if (chan->user.oclass >= NV50_CHANNEL_GPFIFO) {
|
||||
ret = nvif_chan_gpfifo_wait(&chan->chan, req->nr_push + 1, 16);
|
||||
if (ret) {
|
||||
NV_PRINTK(err, cli, "nv50cal_space: %d\n", ret);
|
||||
goto out;
|
||||
@@ -864,7 +864,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
|
||||
u32 length = push[i].length & ~NOUVEAU_GEM_PUSHBUF_NO_PREFETCH;
|
||||
bool no_prefetch = push[i].length & NOUVEAU_GEM_PUSHBUF_NO_PREFETCH;
|
||||
|
||||
nv50_dma_push(chan, addr, length, no_prefetch);
|
||||
nvif_chan_gpfifo_push(&chan->chan, addr, length, no_prefetch);
|
||||
}
|
||||
} else
|
||||
if (drm->client.device.info.chipset >= 0x25) {
|
||||
@@ -958,7 +958,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
|
||||
u_free(push);
|
||||
|
||||
out_next:
|
||||
if (chan->dma.ib_max) {
|
||||
if (chan->user.oclass >= NV50_CHANNEL_GPFIFO) {
|
||||
req->suffix0 = 0x00000000;
|
||||
req->suffix1 = 0x00000000;
|
||||
} else
|
||||
|
||||
@@ -14,6 +14,11 @@ nvif-y += nvif/outp.o
|
||||
nvif-y += nvif/timer.o
|
||||
nvif-y += nvif/vmm.o
|
||||
|
||||
# Channel classes
|
||||
nvif-y += nvif/chan.o
|
||||
nvif-y += nvif/chan506f.o
|
||||
nvif-y += nvif/chanc36f.o
|
||||
|
||||
# Usermode classes
|
||||
nvif-y += nvif/user.o
|
||||
nvif-y += nvif/userc361.o
|
||||
|
||||
127
drivers/gpu/drm/nouveau/nvif/chan.c
Normal file
127
drivers/gpu/drm/nouveau/nvif/chan.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
#include <nvif/chan.h>
|
||||
|
||||
static void
|
||||
nvif_chan_gpfifo_push_kick(struct nvif_push *push)
|
||||
{
|
||||
struct nvif_chan *chan = container_of(push, typeof(*chan), push);
|
||||
u32 put = push->bgn - (u32 *)chan->push.mem.object.map.ptr;
|
||||
u32 cnt = push->cur - push->bgn;
|
||||
|
||||
chan->func->gpfifo.push(chan, true, chan->push.addr + (put << 2), cnt << 2, false);
|
||||
chan->func->gpfifo.kick(chan);
|
||||
}
|
||||
|
||||
static int
|
||||
nvif_chan_gpfifo_push_wait(struct nvif_push *push, u32 push_nr)
|
||||
{
|
||||
struct nvif_chan *chan = container_of(push, typeof(*chan), push);
|
||||
|
||||
return nvif_chan_gpfifo_wait(chan, 1, push_nr);
|
||||
}
|
||||
|
||||
void
|
||||
nvif_chan_gpfifo_push(struct nvif_chan *chan, u64 addr, u32 size, bool no_prefetch)
|
||||
{
|
||||
chan->func->gpfifo.push(chan, false, addr, size, no_prefetch);
|
||||
}
|
||||
|
||||
int
|
||||
nvif_chan_gpfifo_wait(struct nvif_chan *chan, u32 gpfifo_nr, u32 push_nr)
|
||||
{
|
||||
struct nvif_push *push = &chan->push;
|
||||
int ret = 0, time = 1000000;
|
||||
|
||||
/* Account for the GPFIFO entry needed to submit pushbuf. */
|
||||
if (push_nr)
|
||||
gpfifo_nr++;
|
||||
|
||||
/* Wait for space in main push buffer. */
|
||||
if (push->cur + push_nr > push->end) {
|
||||
ret = nvif_chan_dma_wait(chan, push_nr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for GPFIFO space. */
|
||||
while (chan->gpfifo.free < gpfifo_nr) {
|
||||
chan->gpfifo.free = chan->func->gpfifo.read_get(chan) - chan->gpfifo.cur - 1;
|
||||
if (chan->gpfifo.free < 0)
|
||||
chan->gpfifo.free += chan->gpfifo.max + 1;
|
||||
|
||||
if (chan->gpfifo.free < gpfifo_nr) {
|
||||
if (!time--)
|
||||
return -ETIMEDOUT;
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nvif_chan_gpfifo_ctor(const struct nvif_chan_func *func, void *userd, void *gpfifo, u32 gpfifo_size,
|
||||
void *push, u64 push_addr, u32 push_size, struct nvif_chan *chan)
|
||||
{
|
||||
chan->func = func;
|
||||
|
||||
chan->userd.map.ptr = userd;
|
||||
|
||||
chan->gpfifo.map.ptr = gpfifo;
|
||||
chan->gpfifo.max = (gpfifo_size >> 3) - 1;
|
||||
chan->gpfifo.free = chan->gpfifo.max;
|
||||
|
||||
chan->push.mem.object.map.ptr = push;
|
||||
chan->push.wait = nvif_chan_gpfifo_push_wait;
|
||||
chan->push.kick = nvif_chan_gpfifo_push_kick;
|
||||
chan->push.addr = push_addr;
|
||||
chan->push.hw.max = push_size >> 2;
|
||||
chan->push.bgn = chan->push.cur = chan->push.end = push;
|
||||
}
|
||||
|
||||
int
|
||||
nvif_chan_dma_wait(struct nvif_chan *chan, u32 nr)
|
||||
{
|
||||
struct nvif_push *push = &chan->push;
|
||||
u32 cur = push->cur - (u32 *)push->mem.object.map.ptr;
|
||||
u32 free, time = 1000000;
|
||||
|
||||
do {
|
||||
u32 get = chan->func->push.read_get(chan);
|
||||
|
||||
if (get <= cur) {
|
||||
free = push->hw.max - cur;
|
||||
if (free >= nr)
|
||||
break;
|
||||
|
||||
PUSH_KICK(push);
|
||||
|
||||
while (get == 0) {
|
||||
get = chan->func->push.read_get(chan);
|
||||
if (get == 0) {
|
||||
if (!time--)
|
||||
return -ETIMEDOUT;
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
free = get - cur - 1;
|
||||
|
||||
if (free < nr) {
|
||||
if (!time--)
|
||||
return -ETIMEDOUT;
|
||||
udelay(1);
|
||||
}
|
||||
} while (free < nr);
|
||||
|
||||
push->bgn = (u32 *)push->mem.object.map.ptr + cur;
|
||||
push->cur = push->bgn;
|
||||
push->end = push->bgn + free;
|
||||
return 0;
|
||||
}
|
||||
72
drivers/gpu/drm/nouveau/nvif/chan506f.c
Normal file
72
drivers/gpu/drm/nouveau/nvif/chan506f.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
#include <nvif/chan.h>
|
||||
|
||||
static void
|
||||
nvif_chan506f_gpfifo_kick(struct nvif_chan *chan)
|
||||
{
|
||||
wmb();
|
||||
nvif_wr32(&chan->userd, 0x8c, chan->gpfifo.cur);
|
||||
}
|
||||
|
||||
void
|
||||
nvif_chan506f_gpfifo_push(struct nvif_chan *chan, bool main, u64 addr, u32 size, bool no_prefetch)
|
||||
{
|
||||
u32 gpptr = chan->gpfifo.cur << 3;
|
||||
|
||||
if (WARN_ON(!chan->gpfifo.free))
|
||||
return;
|
||||
|
||||
nvif_wr32(&chan->gpfifo, gpptr + 0, lower_32_bits(addr));
|
||||
nvif_wr32(&chan->gpfifo, gpptr + 4, upper_32_bits(addr) |
|
||||
(main ? 0 : BIT(9)) |
|
||||
(size >> 2) << 10 |
|
||||
(no_prefetch ? BIT(31) : 0));
|
||||
|
||||
chan->gpfifo.cur = (chan->gpfifo.cur + 1) & chan->gpfifo.max;
|
||||
chan->gpfifo.free--;
|
||||
if (!chan->gpfifo.free)
|
||||
chan->push.end = chan->push.cur;
|
||||
}
|
||||
|
||||
u32
|
||||
nvif_chan506f_gpfifo_read_get(struct nvif_chan *chan)
|
||||
{
|
||||
return nvif_rd32(&chan->userd, 0x88);
|
||||
}
|
||||
|
||||
u32
|
||||
nvif_chan506f_read_get(struct nvif_chan *chan)
|
||||
{
|
||||
u32 tlgetlo = nvif_rd32(&chan->userd, 0x58);
|
||||
u32 tlgethi = nvif_rd32(&chan->userd, 0x5c);
|
||||
struct nvif_push *push = &chan->push;
|
||||
|
||||
/* Update cached GET pointer if TOP_LEVEL_GET is valid. */
|
||||
if (tlgethi & BIT(31)) {
|
||||
u64 tlget = ((u64)(tlgethi & 0xff) << 32) | tlgetlo;
|
||||
|
||||
push->hw.get = (tlget - push->addr) >> 2;
|
||||
}
|
||||
|
||||
return push->hw.get;
|
||||
}
|
||||
|
||||
static const struct nvif_chan_func
|
||||
nvif_chan506f = {
|
||||
.push.read_get = nvif_chan506f_read_get,
|
||||
.gpfifo.read_get = nvif_chan506f_gpfifo_read_get,
|
||||
.gpfifo.push = nvif_chan506f_gpfifo_push,
|
||||
.gpfifo.kick = nvif_chan506f_gpfifo_kick,
|
||||
};
|
||||
|
||||
int
|
||||
nvif_chan506f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
|
||||
void *push, u64 push_addr, u32 push_size)
|
||||
{
|
||||
nvif_chan_gpfifo_ctor(&nvif_chan506f, userd, gpfifo, gpfifo_size,
|
||||
push, push_addr, push_size, chan);
|
||||
return 0;
|
||||
}
|
||||
39
drivers/gpu/drm/nouveau/nvif/chanc36f.c
Normal file
39
drivers/gpu/drm/nouveau/nvif/chanc36f.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
#include <nvif/chan.h>
|
||||
#include <nvif/user.h>
|
||||
|
||||
static void
|
||||
nvif_chanc36f_gpfifo_kick(struct nvif_chan *chan)
|
||||
{
|
||||
struct nvif_user *usermode = chan->usermode;
|
||||
|
||||
nvif_wr32(&chan->userd, 0x8c, chan->gpfifo.cur);
|
||||
|
||||
wmb(); /* ensure CPU writes are flushed to BAR1 */
|
||||
nvif_rd32(&chan->userd, 0); /* ensure BAR1 writes are flushed to vidmem */
|
||||
|
||||
usermode->func->doorbell(usermode, chan->doorbell_token);
|
||||
}
|
||||
|
||||
static const struct nvif_chan_func
|
||||
nvif_chanc36f = {
|
||||
.push.read_get = nvif_chan506f_read_get,
|
||||
.gpfifo.read_get = nvif_chan506f_gpfifo_read_get,
|
||||
.gpfifo.push = nvif_chan506f_gpfifo_push,
|
||||
.gpfifo.kick = nvif_chanc36f_gpfifo_kick,
|
||||
};
|
||||
|
||||
int
|
||||
nvif_chanc36f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
|
||||
void *push, u64 push_addr, u32 push_size,
|
||||
struct nvif_user *usermode, u32 doorbell_token)
|
||||
{
|
||||
nvif_chan_gpfifo_ctor(&nvif_chanc36f, userd, gpfifo, gpfifo_size,
|
||||
push, push_addr, push_size, chan);
|
||||
chan->usermode = usermode;
|
||||
chan->doorbell_token = doorbell_token;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user