diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvif')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/Kbuild | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/chan.c | 156 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/chan506f.c | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/chan906f.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/chanc36f.c | 77 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/conn.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/disp.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/outp.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/user.c | 8 |
9 files changed, 423 insertions, 19 deletions
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild index b7963a39dd91..198889c20ce1 100644 --- a/drivers/gpu/drm/nouveau/nvif/Kbuild +++ b/drivers/gpu/drm/nouveau/nvif/Kbuild @@ -14,6 +14,12 @@ 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/chan906f.o +nvif-y += nvif/chanc36f.o + # Usermode classes nvif-y += nvif/user.o nvif-y += nvif/userc361.o diff --git a/drivers/gpu/drm/nouveau/nvif/chan.c b/drivers/gpu/drm/nouveau/nvif/chan.c new file mode 100644 index 000000000000..baa10227d51a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/chan.c @@ -0,0 +1,156 @@ +/* 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; + + if (chan->func->gpfifo.post) { + if (push->end - push->cur < chan->func->gpfifo.post_size) + push->end = push->cur + chan->func->gpfifo.post_size; + + WARN_ON(nvif_chan_gpfifo_post(chan)); + } + + 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); +} + +int +nvif_chan_gpfifo_post(struct nvif_chan *chan) +{ + const u32 *map = chan->push.mem.object.map.ptr; + const u32 pbptr = (chan->push.cur - map) + chan->func->gpfifo.post_size; + const u32 gpptr = (chan->gpfifo.cur + 1) & chan->gpfifo.max; + + return chan->func->gpfifo.post(chan, gpptr, pbptr); +} + +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; + + if (gpfifo_nr) { + /* Account for pushbuf space needed by nvif_chan_gpfifo_post(), + * if used after pushing userspace GPFIFO entries. + */ + if (chan->func->gpfifo.post) + push_nr += chan->func->gpfifo.post_size; + } + + /* 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; + + nr += chan->func->gpfifo.post_size; + + 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 - chan->func->gpfifo.post_size; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvif/chan506f.c b/drivers/gpu/drm/nouveau/nvif/chan506f.c new file mode 100644 index 000000000000..d3900887c4a7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/chan506f.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. + */ +#include <nvif/chan.h> + +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; +} + +static u32 +nvif_chan506f_gpfifo_read_get(struct nvif_chan *chan) +{ + return nvif_rd32(&chan->userd, 0x88); +} + +static 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; +} diff --git a/drivers/gpu/drm/nouveau/nvif/chan906f.c b/drivers/gpu/drm/nouveau/nvif/chan906f.c new file mode 100644 index 000000000000..c9cfb85179b0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/chan906f.c @@ -0,0 +1,93 @@ +/* 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/cl906f.h> + +/* Limits GPFIFO size to 1MiB, and "main" push buffer size to 64KiB. */ +#define NVIF_CHAN906F_PBPTR_BITS 15 +#define NVIF_CHAN906F_PBPTR_MASK ((1 << NVIF_CHAN906F_PBPTR_BITS) - 1) + +#define NVIF_CHAN906F_GPPTR_SHIFT NVIF_CHAN906F_PBPTR_BITS +#define NVIF_CHAN906F_GPPTR_BITS (32 - NVIF_CHAN906F_PBPTR_BITS) +#define NVIF_CHAN906F_GPPTR_MASK ((1 << NVIF_CHAN906F_GPPTR_BITS) - 1) + +#define NVIF_CHAN906F_SEM_RELEASE_SIZE 5 + +static int +nvif_chan906f_sem_release(struct nvif_chan *chan, u64 addr, u32 data) +{ + struct nvif_push *push = &chan->push; + int ret; + + ret = PUSH_WAIT(push, NVIF_CHAN906F_SEM_RELEASE_SIZE); + if (ret) + return ret; + + PUSH_MTHD(push, NV906F, SEMAPHOREA, + NVVAL(NV906F, SEMAPHOREA, OFFSET_UPPER, upper_32_bits(addr)), + + SEMAPHOREB, lower_32_bits(addr), + + SEMAPHOREC, data, + + SEMAPHORED, + NVDEF(NV906F, SEMAPHORED, OPERATION, RELEASE) | + NVDEF(NV906F, SEMAPHORED, RELEASE_WFI, DIS) | + NVDEF(NV906F, SEMAPHORED, RELEASE_SIZE, 16BYTE)); + + return 0; +} + +int +nvif_chan906f_gpfifo_post(struct nvif_chan *chan, u32 gpptr, u32 pbptr) +{ + return chan->func->sem.release(chan, chan->sema.addr, + (gpptr << NVIF_CHAN906F_GPPTR_SHIFT) | pbptr); +} + +u32 +nvif_chan906f_gpfifo_read_get(struct nvif_chan *chan) +{ + return nvif_rd32(&chan->sema, 0) >> NVIF_CHAN906F_GPPTR_SHIFT; +} + +u32 +nvif_chan906f_read_get(struct nvif_chan *chan) +{ + return nvif_rd32(&chan->sema, 0) & NVIF_CHAN906F_PBPTR_MASK; +} + +static const struct nvif_chan_func +nvif_chan906f = { + .push.read_get = nvif_chan906f_read_get, + .gpfifo.read_get = nvif_chan906f_gpfifo_read_get, + .gpfifo.push = nvif_chan506f_gpfifo_push, + .gpfifo.kick = nvif_chan506f_gpfifo_kick, + .gpfifo.post = nvif_chan906f_gpfifo_post, + .gpfifo.post_size = NVIF_CHAN906F_SEM_RELEASE_SIZE, + .sem.release = nvif_chan906f_sem_release, +}; + +int +nvif_chan906f_ctor_(const struct nvif_chan_func *func, void *userd, void *gpfifo, u32 gpfifo_size, + void *push, u64 push_addr, u32 push_size, void *sema, u64 sema_addr, + struct nvif_chan *chan) +{ + nvif_chan_gpfifo_ctor(func, userd, gpfifo, gpfifo_size, push, push_addr, push_size, chan); + chan->sema.map.ptr = sema; + chan->sema.addr = sema_addr; + return 0; +} + +int +nvif_chan906f_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) +{ + return nvif_chan906f_ctor_(&nvif_chan906f, userd, gpfifo, gpfifo_size, + push, push_addr, push_size, sema, sema_addr, chan); +} diff --git a/drivers/gpu/drm/nouveau/nvif/chanc36f.c b/drivers/gpu/drm/nouveau/nvif/chanc36f.c new file mode 100644 index 000000000000..ca02b939c3fd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/chanc36f.c @@ -0,0 +1,77 @@ +/* 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; +} diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c index 9ee18cb99264..5a1a83c62a2a 100644 --- a/drivers/gpu/drm/nouveau/nvif/conn.c +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -30,17 +30,17 @@ int nvif_conn_event_ctor(struct nvif_conn *conn, const char *name, nvif_event_func func, u8 types, struct nvif_event *event) { - struct { - struct nvif_event_v0 base; - struct nvif_conn_event_v0 conn; - } args; + DEFINE_RAW_FLEX(struct nvif_event_v0, args, data, + sizeof(struct nvif_conn_event_v0)); + struct nvif_conn_event_v0 *args_conn = + (struct nvif_conn_event_v0 *)args->data; int ret; - args.conn.version = 0; - args.conn.types = types; + args_conn->version = 0; + args_conn->types = types; ret = nvif_event_ctor_(&conn->object, name ?: "nvifConnHpd", nvif_conn_id(conn), - func, true, &args.base, sizeof(args), false, event); + func, true, args, __struct_size(args), false, event); NVIF_DEBUG(&conn->object, "[NEW EVENT:HPD types:%02x]", types); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c index 14da22fa3b5b..fa42146252da 100644 --- a/drivers/gpu/drm/nouveau/nvif/disp.c +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -36,6 +36,7 @@ int nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct nvif_disp *disp) { static const struct nvif_mclass disps[] = { + { GB202_DISP, 0 }, { AD102_DISP, 0 }, { GA102_DISP, 0 }, { TU102_DISP, 0 }, diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 6daeb7f0b09b..32f6c5eb92af 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -195,20 +195,17 @@ nvif_outp_dp_aux_pwr(struct nvif_outp *outp, bool enable) int nvif_outp_hda_eld(struct nvif_outp *outp, int head, void *data, u32 size) { - struct { - struct nvif_outp_hda_eld_v0 mthd; - u8 data[128]; - } args; + DEFINE_RAW_FLEX(struct nvif_outp_hda_eld_v0, mthd, data, 128); int ret; - if (WARN_ON(size > ARRAY_SIZE(args.data))) + if (WARN_ON(size > __member_size(mthd->data))) return -EINVAL; - args.mthd.version = 0; - args.mthd.head = head; + mthd->version = 0; + mthd->head = head; - memcpy(args.data, data, size); - ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, &args, sizeof(args.mthd) + size); + memcpy(mthd->data, data, size); + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, mthd, sizeof(*mthd) + size); NVIF_ERRON(ret, &outp->object, "[HDA_ELD head:%d size:%d]", head, size); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvif/user.c b/drivers/gpu/drm/nouveau/nvif/user.c index b648a5e036af..53f03fa1c9c2 100644 --- a/drivers/gpu/drm/nouveau/nvif/user.c +++ b/drivers/gpu/drm/nouveau/nvif/user.c @@ -41,9 +41,11 @@ nvif_user_ctor(struct nvif_device *device, const char *name) int version; const struct nvif_user_func *func; } users[] = { - { AMPERE_USERMODE_A, -1, &nvif_userc361 }, - { TURING_USERMODE_A, -1, &nvif_userc361 }, - { VOLTA_USERMODE_A, -1, &nvif_userc361 }, + { BLACKWELL_USERMODE_A, -1, &nvif_userc361 }, + { HOPPER_USERMODE_A, -1, &nvif_userc361 }, + { AMPERE_USERMODE_A, -1, &nvif_userc361 }, + { TURING_USERMODE_A, -1, &nvif_userc361 }, + { VOLTA_USERMODE_A, -1, &nvif_userc361 }, {} }; int cid, ret; |