mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

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: 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>
77 lines
2 KiB
C
77 lines
2 KiB
C
/* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
|
*/
|
|
#include <nvif/chan.h>
|
|
#include <nvif/user.h>
|
|
|
|
#include <nvif/push906f.h>
|
|
#include <nvhw/class/clc36f.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);
|
|
}
|
|
|
|
#define NVIF_CHANC36F_SEM_RELEASE_SIZE 6
|
|
|
|
static int
|
|
nvif_chanc36f_sem_release(struct nvif_chan *chan, u64 addr, u32 data)
|
|
{
|
|
struct nvif_push *push = &chan->push;
|
|
int ret;
|
|
|
|
ret = PUSH_WAIT(push, NVIF_CHANC36F_SEM_RELEASE_SIZE);
|
|
if (ret)
|
|
return ret;
|
|
|
|
PUSH_MTHD(push, NVC36F, SEM_ADDR_LO, lower_32_bits(addr),
|
|
|
|
SEM_ADDR_HI, upper_32_bits(addr),
|
|
|
|
SEM_PAYLOAD_LO, data);
|
|
|
|
PUSH_MTHD(push, NVC36F, SEM_EXECUTE,
|
|
NVDEF(NVC36F, SEM_EXECUTE, OPERATION, RELEASE) |
|
|
NVDEF(NVC36F, SEM_EXECUTE, RELEASE_WFI, DIS) |
|
|
NVDEF(NVC36F, SEM_EXECUTE, PAYLOAD_SIZE, 32BIT) |
|
|
NVDEF(NVC36F, SEM_EXECUTE, RELEASE_TIMESTAMP, DIS));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct nvif_chan_func
|
|
nvif_chanc36f = {
|
|
.push.read_get = nvif_chan906f_read_get,
|
|
.gpfifo.read_get = nvif_chan906f_gpfifo_read_get,
|
|
.gpfifo.push = nvif_chan506f_gpfifo_push,
|
|
.gpfifo.kick = nvif_chanc36f_gpfifo_kick,
|
|
.gpfifo.post = nvif_chan906f_gpfifo_post,
|
|
.gpfifo.post_size = NVIF_CHANC36F_SEM_RELEASE_SIZE,
|
|
.sem.release = nvif_chanc36f_sem_release,
|
|
};
|
|
|
|
int
|
|
nvif_chanc36f_ctor(struct nvif_chan *chan, void *userd, void *gpfifo, u32 gpfifo_size,
|
|
void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr,
|
|
struct nvif_user *usermode, u32 doorbell_token)
|
|
{
|
|
int ret;
|
|
|
|
ret = nvif_chan906f_ctor_(&nvif_chanc36f, userd, gpfifo, gpfifo_size,
|
|
push, push_addr, push_size, sema, sema_addr, chan);
|
|
if (ret)
|
|
return ret;
|
|
|
|
chan->usermode = usermode;
|
|
chan->doorbell_token = doorbell_token;
|
|
return 0;
|
|
}
|