summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c394
1 files changed, 366 insertions, 28 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index fa2d3b4..5565159 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -228,6 +228,7 @@ bool gsp_phys_boot_requested(void)
#define GSP_PHYS_RMCALL_CTRL_SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX 0xc36f010au
#define GSP_PHYS_RMCALL_CTRL_GPFIFO_SCHEDULE 0xa06f0103u
#define GSP_PHYS_RMCALL_CTRL_BIND_CHANNEL 0xa06f0104u
+#define GSP_PHYS_RMCALL_CTRL_TSG_GPFIFO_SCHEDULE 0xa06c0101u
#define GSP_PHYS_RMCALL_CTRL_DMA_SET_PAGE_DIRECTORY 0x801813u
#define GSP_PHYS_RMCALL_ENGINE_COPY0 0x9u
@@ -286,6 +287,19 @@ bool gsp_phys_boot_requested(void)
#define GSP_PHYS_RMCALL_PDB_SUBDEVICE_ID 1u
/*
+ * Channel page-directory GPU VA window. The GPFIFO and the pushbuffer are
+ * fetched by GPU VA (the GPFIFO from gpFifoOffset, the pushbuffer from the
+ * GPFIFO ring entry GET), so the channel's external root must translate them.
+ * Both pages live in one 2 MB PD0 slot below the VAS vaSize limit: with
+ * VA_BASE = 0x00100000 every parent index (48:47, 46:38, 37:29, 28:21) is 0
+ * and the two 4 KB pages take small-PT slots 0x100/0x101
+ * (kern_gmmu_fmt_gp10x.c:16-83; uvm_pascal_mmu.c:25-32,172-204).
+ */
+#define GSP_PHYS_RMCALL_VA_BASE 0x00100000ULL
+#define GSP_PHYS_RMCALL_VA_GPFIFO GSP_PHYS_RMCALL_VA_BASE
+#define GSP_PHYS_RMCALL_VA_PB (GSP_PHYS_RMCALL_VA_BASE + GSP_PHYS_PAGE_SIZE)
+
+/*
* Channel alloc flags/internal flags (alloc/alloc_channel.h:141-143 bit 5 =
* NVOS04_FLAGS_PRIVILEGED_CHANNEL; generated/g_kernel_channel_nvoc.h:185-188
* internalFlags 1:0 = privilege, KERNEL=2). These are sent as a hint only:
@@ -330,6 +344,7 @@ bool gsp_phys_boot_requested(void)
#define GSP_PHYS_RMCALL_HANDLE_CHANNEL_V3 0xcaf00018u
#define GSP_PHYS_RMCALL_HANDLE_CHANNEL_V5 0xcaf00024u
#define GSP_PHYS_RMCALL_HANDLE_NOTIFIER_MEM 0xcaf00028u
+#define GSP_PHYS_RMCALL_HANDLE_USERD_MEM 0xcaf0002cu
#define GSP_PHYS_RMCALL_HANDLE_MEM_BASE 0xcaf01000u
#define GSP_PHYS_RMCALL_HANDLE_MEM_STRIDE 4u
@@ -362,6 +377,15 @@ enum gsp_phys_rmcall_buf {
GSP_PHYS_RMCALL_BUF_RAMFC,
GSP_PHYS_RMCALL_BUF_MTHDBUF,
GSP_PHYS_RMCALL_BUF_VASPDB,
+ /*
+ * Client-owned channel page-directory hierarchy behind the external
+ * root: PD2/PD1 single 8 B PDE levels, PD0 16 B dual PDE and the 4 KB
+ * small-page PT (GP10X v2, kern_gmmu_fmt_gp10x.c:16-83).
+ */
+ GSP_PHYS_RMCALL_BUF_PD2,
+ GSP_PHYS_RMCALL_BUF_PD1,
+ GSP_PHYS_RMCALL_BUF_PD0,
+ GSP_PHYS_RMCALL_BUF_PT,
GSP_PHYS_RMCALL_BUF_COUNT
};
@@ -904,6 +928,18 @@ static struct gsp_phys_boot_stage {
u32 rmcall_notifier_mem; /* FBMEM error-notifier object handle */
u64 rmcall_notifier_base; /* its returned frame-buffer address */
bool rmcall_notifier_valid; /* the FBMEM notifier alloc succeeded */
+ u32 rmcall_userd_mem; /* FBMEM USERD object handle */
+ u64 rmcall_userd_base; /* its returned frame-buffer address */
+ bool rmcall_userd_valid; /* the FBMEM USERD alloc succeeded */
+ u64 rmcall_va_base; /* channel PDB VA window base */
+ u64 rmcall_va_gpfifo; /* GPFIFO GPU VA in that window */
+ u64 rmcall_va_pb; /* pushbuffer GPU VA in that window */
+ u64 rmcall_pdb_root; /* root entry -> PD2 */
+ u64 rmcall_pdb_pd2; /* PD2 entry -> PD1 */
+ u64 rmcall_pdb_pd1; /* PD1 entry -> PD0 */
+ u64 rmcall_pdb_pd0_small; /* PD0 dual entry, small (4 KB) half */
+ u64 rmcall_pt_gpfifo; /* small-PT entry for the GPFIFO page */
+ u64 rmcall_pt_pb; /* small-PT entry for the PB page */
struct pci_dev *pdev; /* borrowed claim pdev (valid while primed) */
struct gsp_phys_boot_chunk rmcall_chunks[GSP_PHYS_RMCALL_BUF_COUNT];
u32 rmcall_mem_handles[GSP_PHYS_RMCALL_BUF_COUNT];
@@ -1419,6 +1455,18 @@ static void gsp_phys_rmcall_reset(void)
boot_stage.rmcall_notifier_mem = 0;
boot_stage.rmcall_notifier_base = 0;
boot_stage.rmcall_notifier_valid = false;
+ boot_stage.rmcall_userd_mem = 0;
+ boot_stage.rmcall_userd_base = 0;
+ boot_stage.rmcall_userd_valid = false;
+ boot_stage.rmcall_va_base = 0;
+ boot_stage.rmcall_va_gpfifo = 0;
+ boot_stage.rmcall_va_pb = 0;
+ boot_stage.rmcall_pdb_root = 0;
+ boot_stage.rmcall_pdb_pd2 = 0;
+ boot_stage.rmcall_pdb_pd1 = 0;
+ boot_stage.rmcall_pdb_pd0_small = 0;
+ boot_stage.rmcall_pt_gpfifo = 0;
+ boot_stage.rmcall_pt_pb = 0;
for (i = 0; i < GSP_PHYS_RMCALL_BUF_COUNT; i++) {
boot_stage.rmcall_mem_handles[i] = 0;
boot_stage.rmcall_mem_registered[i] = false;
@@ -4737,6 +4785,83 @@ static int gsp_phys_rmcall_alloc_notifier_mem(void __iomem *bar0)
}
/*
+ * Allocate the channel's USERD page in FBMEM. Same class-0x40 shape as the
+ * error-notifier allocation above (owner HEAP_OWNER_RM_CLIENT_GENERIC, type
+ * IMAGE, VIDMEM|UNCACHED, SKIP_SCRUB); the reference defaults USERD to
+ * VIDMEM (mem_utils_gm107.c:792-804,1132-1161) and the client push path
+ * allocates NV01_MEMORY_LOCAL_USER with these flags (nvidia-push-init.c:
+ * 515-554). The server returns the allocated FB offset in
+ * NV_MEMORY_ALLOCATION_PARAMS.offset, which userdMem.base carries with
+ * addressSpace FBMEM.
+ *
+ * Failure is non-fatal: the channel params then fall back to the sysmem
+ * USERD chunk and log the fallback.
+ */
+static int gsp_phys_rmcall_alloc_userd_mem(void __iomem *bar0)
+{
+ struct gsp_phys_rmcall_memory_alloc_params mem;
+ struct gsp_phys_rmcall_rm_alloc_req *req;
+ struct gsp_phys_rx_record rec;
+ u32 req_len = sizeof(*req) + sizeof(mem);
+ u32 status;
+ u64 base;
+ int ret;
+
+ memset(&mem, 0, sizeof(mem));
+ mem.owner = cpu_to_le32(GSP_PHYS_RMCALL_HEAP_OWNER_RM_CLIENT_GENERIC);
+ mem.type = cpu_to_le32(GSP_PHYS_RMCALL_OS32_TYPE_IMAGE);
+ mem.size = cpu_to_le64(GSP_PHYS_RMCALL_COPY_SIZE);
+ mem.attr = cpu_to_le32(GSP_PHYS_RMCALL_OS32_ATTR_VIDMEM_UNCACHED);
+ mem.internalflags =
+ cpu_to_le32(GSP_PHYS_RMCALL_OS32_INTERNAL_FLAG_SKIP_SCRUB);
+
+ req = kvzalloc(req_len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ req->h_client = cpu_to_le32(boot_stage.rmcall_client);
+ req->h_parent = cpu_to_le32(boot_stage.rmcall_device);
+ req->h_object = cpu_to_le32(GSP_PHYS_RMCALL_HANDLE_USERD_MEM);
+ req->h_class = cpu_to_le32(GSP_PHYS_RMCALL_CLASS_MEMORY_LOCAL_USER);
+ req->params_size = cpu_to_le32(sizeof(mem));
+ memcpy(req->params, &mem, sizeof(mem));
+
+ ret = gsp_phys_rmcall_rpc(bar0, GSP_PHYS_RMCALL_FUNC_GSP_RM_ALLOC,
+ req, req_len, 20, &rec, true, NULL);
+ kvfree(req);
+ if (ret) {
+ pr_err("gsp-phys-boot: rm-call: FBMEM USERD alloc (hMemory=0x%x class=0x40 size=0x%x) RPC failed: %d\n",
+ GSP_PHYS_RMCALL_HANDLE_USERD_MEM,
+ GSP_PHYS_RMCALL_COPY_SIZE, ret);
+ gsp_phys_rx_record_free(&rec);
+ return ret;
+ }
+
+ status = gsp_phys_rmcall_reply_u32(&rec, 16);
+ if (status != 0 ||
+ rec.payload_len < 32 + offsetof(struct gsp_phys_rmcall_memory_alloc_params,
+ offset) + 8) {
+ pr_err("gsp-phys-boot: rm-call: FBMEM USERD alloc rejected: status=0x%x payload=%u B (need the echoed params through offset at +%zu)\n",
+ status, rec.payload_len,
+ offsetof(struct gsp_phys_rmcall_memory_alloc_params,
+ offset) + 8);
+ gsp_phys_rx_record_free(&rec);
+ return -EIO;
+ }
+ base = get_unaligned_le64(rec.buf + GSP_PHYS_MSG_ELEMENT_PAYLOAD_OFF + 32 +
+ offsetof(struct gsp_phys_rmcall_memory_alloc_params,
+ offset));
+ gsp_phys_rx_record_free(&rec);
+
+ boot_stage.rmcall_userd_mem = GSP_PHYS_RMCALL_HANDLE_USERD_MEM;
+ boot_stage.rmcall_userd_base = base;
+ boot_stage.rmcall_userd_valid = true;
+ pr_info("gsp-phys-boot: rm-call: FBMEM USERD allocated: hMemory=0x%x class=0x40 size=0x%x FB base=0x%llx\n",
+ boot_stage.rmcall_userd_mem, GSP_PHYS_RMCALL_COPY_SIZE,
+ boot_stage.rmcall_userd_base);
+ return 0;
+}
+
+/*
* One GSP_RM_CONTROL (76). Reply status at payload+12, echoed params at
* payload+24 (rpcRmApiControl_GSP, rpc.c:9797-10031). out_status (optional)
* receives the server control status even when it is nonzero; the echoed
@@ -4916,7 +5041,7 @@ static int gsp_phys_rmcall_stage2(void __iomem *bar0)
}
}
- pr_info("gsp-phys-boot: rm-call: stage 2 complete: %u buffers registered (src=0xa5, dst/sem/pb/gpfifo/userd/instance/ramfc/mthdbuf/vaspdb zeroed)\n",
+ pr_info("gsp-phys-boot: rm-call: stage 2 complete: %u buffers registered (src=0xa5, dst/sem/pb/gpfifo/userd/instance/ramfc/mthdbuf/vaspdb/pd2/pd1/pd0/pt zeroed)\n",
GSP_PHYS_RMCALL_BUF_COUNT);
return 0;
}
@@ -5005,11 +5130,31 @@ gsp_phys_rmcall_channel_params_init(struct gsp_phys_rmcall_channel_params *ch,
}
if (v->server_mem)
return; /* zeroed memdescs, gpFifoOffset/gpFifoEntries 0 */
- ch->gp_fifo_offset = cpu_to_le64((u64)gsp_phys_chunk_page_dma(
- &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GPFIFO], 0));
+ /*
+ * The PBDMA/CE fetch the GPFIFO by GPU VA through the channel PDB
+ * (NV_RAMFC_GP_BASE from gpFifoOffset, fifo_g100.c:1120-1137), so the
+ * offset is the VA built in gsp_phys_rmcall_pdb_build, not the host DMA.
+ */
+ ch->gp_fifo_offset = cpu_to_le64(GSP_PHYS_RMCALL_VA_GPFIFO);
ch->gp_fifo_entries = cpu_to_le32(GSP_PHYS_RMCALL_GPFIFO_ENTRIES);
ch->instance_mem = gsp_phys_rmcall_mem_desc(GSP_PHYS_RMCALL_BUF_INSTANCE);
- ch->userd_mem = gsp_phys_rmcall_mem_desc(GSP_PHYS_RMCALL_BUF_USERD);
+ /*
+ * USERD is the reference default FBMEM page (mem_utils_gm107.c:
+ * 792-804,1132-1161; nvidia-push-init.c:515-554) when stage 3's
+ * class-0x40 allocation succeeded; the sysmem chunk remains the
+ * fallback when it did not.
+ */
+ if (boot_stage.rmcall_userd_valid) {
+ ch->userd_mem.base = cpu_to_le64(boot_stage.rmcall_userd_base);
+ ch->userd_mem.size = cpu_to_le64(GSP_PHYS_RMCALL_COPY_SIZE);
+ ch->userd_mem.address_space =
+ cpu_to_le32(GSP_PHYS_RMCALL_ADDR_FBMEM);
+ ch->userd_mem.cache_attrib =
+ cpu_to_le32(GSP_PHYS_RMCALL_CACHE_UNCACHED);
+ } else {
+ ch->userd_mem =
+ gsp_phys_rmcall_mem_desc(GSP_PHYS_RMCALL_BUF_USERD);
+ }
ch->ramfc_mem = gsp_phys_rmcall_mem_desc(GSP_PHYS_RMCALL_BUF_RAMFC);
ch->mthdbuf_mem = gsp_phys_rmcall_mem_desc(GSP_PHYS_RMCALL_BUF_MTHDBUF);
}
@@ -5078,6 +5223,118 @@ static int gsp_phys_rmcall_alloc_channel(void __iomem *bar0)
}
/*
+ * GP10X GMMU (format version 2) sysmem-noncoherent PDE/PTE encoders. The
+ * single PDE is IS_PDE=0 (bit 0), APERTURE=3 in bits 2:1, VOL=1 (bit 3) and
+ * the physical page number in bits 53:8 (ADDRESS_SYS, shift 12); the leaf PTE
+ * adds VALID=1 (bit 0) with KIND=PITCH (bits 63:56 zero). The PD0 dual entry
+ * stores the big (64K/2M) half in qword 0 and the small (4K) half in qword 1
+ * with the same aperture/address fields at the same bit positions
+ * (swref/published/pascal/gp100/dev_mmu.h:97-119,157;
+ * uvm_pascal_mmu.c:64-141,235-303).
+ */
+static u64 gsp_phys_rmcall_pde(u64 pa)
+{
+ return 0xeull | ((pa >> 12) << 8);
+}
+
+static u64 gsp_phys_rmcall_pte(u64 pa)
+{
+ return 0xfull | ((pa >> 12) << 8);
+}
+
+/*
+ * Build the channel's page-directory hierarchy around the 2 MB VA window
+ * GSP_PHYS_RMCALL_VA_BASE that maps the GPFIFO and pushbuffer sysmem pages:
+ *
+ * root/PD3 [48:47] -> PD2 [46:38] -> PD1 [37:29] -> PD0 dual [28:21]
+ * -> small PT [20:12]
+ *
+ * (kern_gmmu_fmt_gp10x.c:16-83; uvm_pascal_mmu.c:25-32,143-161). The window
+ * puts every parent index at 0 and the two pages at small-PT slots
+ * 0x100/0x101, so only root[0], PD2[0], PD1[0], the PD0[0] small half and
+ * those two PT slots are written; the root chunk itself is the
+ * DMA_SET_PAGE_DIRECTORY payload. The external root merely stores the
+ * memdesc, so filling before the channel alloc (after a successful
+ * SET_PAGE_DIRECTORY) is equivalent to filling before the control.
+ */
+static void gsp_phys_rmcall_pdb_build(void)
+{
+ struct gsp_phys_boot_chunk *root =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_VASPDB];
+ struct gsp_phys_boot_chunk *pd2 =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PD2];
+ struct gsp_phys_boot_chunk *pd1 =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PD1];
+ struct gsp_phys_boot_chunk *pd0 =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PD0];
+ struct gsp_phys_boot_chunk *pt =
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PT];
+ u32 gpfifo_idx = (u32)((GSP_PHYS_RMCALL_VA_GPFIFO >> 12) & 0x1ffu);
+ u32 pb_idx = (u32)((GSP_PHYS_RMCALL_VA_PB >> 12) & 0x1ffu);
+ u64 root_ent, pd2_ent, pd1_ent, pd0_small, pt_gpfifo, pt_pb;
+
+ root_ent = gsp_phys_rmcall_pde(
+ (u64)gsp_phys_chunk_page_dma(pd2, 0));
+ pd2_ent = gsp_phys_rmcall_pde(
+ (u64)gsp_phys_chunk_page_dma(pd1, 0));
+ pd1_ent = gsp_phys_rmcall_pde(
+ (u64)gsp_phys_chunk_page_dma(pd0, 0));
+ pd0_small = gsp_phys_rmcall_pde(
+ (u64)gsp_phys_chunk_page_dma(pt, 0));
+ pt_gpfifo = gsp_phys_rmcall_pte(
+ (u64)gsp_phys_chunk_page_dma(
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GPFIFO],
+ 0));
+ pt_pb = gsp_phys_rmcall_pte(
+ (u64)gsp_phys_chunk_page_dma(
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PB], 0));
+
+ put_unaligned_le64(root_ent, gsp_phys_chunk_page_va(root, 0));
+ put_unaligned_le64(pd2_ent, gsp_phys_chunk_page_va(pd2, 0));
+ put_unaligned_le64(pd1_ent, gsp_phys_chunk_page_va(pd1, 0));
+ /* 16 B dual PDE: big (64K/2M) half unused, small half -> 4 KB PT. */
+ put_unaligned_le64(0, gsp_phys_chunk_page_va(pd0, 0));
+ put_unaligned_le64(pd0_small,
+ (u8 *)gsp_phys_chunk_page_va(pd0, 0) + 8);
+ put_unaligned_le64(pt_gpfifo,
+ (u8 *)gsp_phys_chunk_page_va(pt, 0) +
+ (size_t)gpfifo_idx * 8);
+ put_unaligned_le64(pt_pb,
+ (u8 *)gsp_phys_chunk_page_va(pt, 0) +
+ (size_t)pb_idx * 8);
+ dma_wmb();
+
+ boot_stage.rmcall_va_base = GSP_PHYS_RMCALL_VA_BASE;
+ boot_stage.rmcall_va_gpfifo = GSP_PHYS_RMCALL_VA_GPFIFO;
+ boot_stage.rmcall_va_pb = GSP_PHYS_RMCALL_VA_PB;
+ boot_stage.rmcall_pdb_root = root_ent;
+ boot_stage.rmcall_pdb_pd2 = pd2_ent;
+ boot_stage.rmcall_pdb_pd1 = pd1_ent;
+ boot_stage.rmcall_pdb_pd0_small = pd0_small;
+ boot_stage.rmcall_pt_gpfifo = pt_gpfifo;
+ boot_stage.rmcall_pt_pb = pt_pb;
+
+ pr_info("gsp-phys-boot: rm-call: channel PDB built: vaBase=0x%llx vaGpfifo=0x%llx vaPb=0x%llx gpFifoOffset=0x%llx root dma=0x%llx pd2 dma=0x%llx pd1 dma=0x%llx pd0 dma=0x%llx pt dma=0x%llx\n",
+ GSP_PHYS_RMCALL_VA_BASE, GSP_PHYS_RMCALL_VA_GPFIFO,
+ GSP_PHYS_RMCALL_VA_PB, GSP_PHYS_RMCALL_VA_GPFIFO,
+ (u64)gsp_phys_chunk_page_dma(root, 0),
+ (u64)gsp_phys_chunk_page_dma(pd2, 0),
+ (u64)gsp_phys_chunk_page_dma(pd1, 0),
+ (u64)gsp_phys_chunk_page_dma(pd0, 0),
+ (u64)gsp_phys_chunk_page_dma(pt, 0));
+ pr_info("gsp-phys-boot: rm-call: channel PDB entries: root[0]=0x%016llx pd2[0]=0x%016llx pd1[0]=0x%016llx pd0[0].small=0x%016llx\n",
+ root_ent, pd2_ent, pd1_ent, pd0_small);
+ pr_info("gsp-phys-boot: rm-call: channel PDB PT: pt[%u]=0x%016llx (gpfifo dma=0x%llx) pt[%u]=0x%016llx (pb dma=0x%llx)\n",
+ gpfifo_idx, pt_gpfifo,
+ (u64)gsp_phys_chunk_page_dma(
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GPFIFO],
+ 0),
+ pb_idx, pt_pb,
+ (u64)gsp_phys_chunk_page_dma(
+ &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_PB], 0));
+}
+
+/*
* Stage 3: explicit VAS with its page directory, then channel group (COPY0,
* physical) and the channel. The VAS and PDB must both succeed: a channel
* whose VAS has no page-directory base fails the context-share/instance-block
@@ -5095,7 +5352,10 @@ static int gsp_phys_rmcall_alloc_channel(void __iomem *bar0)
* requested here: its generator requires BIND + GPFIFO_SCHEDULE (runlist
* membership, kernel_fifo_tu102.c:110-116), so the whole BIND -> SCHEDULE ->
* SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX -> GET_WORK_SUBMIT_TOKEN order lives in
- * stage 4.
+ * stage 4. After SET_PAGE_DIRECTORY the root's lower levels are built
+ * (gsp_phys_rmcall_pdb_build), because the engine fetches the GPFIFO and the
+ * pushbuffer by GPU VA through that hierarchy; the USERD page is allocated in
+ * FBMEM alongside the notifier.
*/
static int gsp_phys_rmcall_stage3(void __iomem *bar0)
{
@@ -5151,6 +5411,12 @@ static int gsp_phys_rmcall_stage3(void __iomem *bar0)
pdb_rpc);
return ret;
}
+ /*
+ * The server only stored our root memdesc; the GPFIFO and pushbuffer
+ * fetches translate through it, so fill the hierarchy before the
+ * channel alloc commits the instance block's page-directory base.
+ */
+ gsp_phys_rmcall_pdb_build();
memset(&tsg, 0, sizeof(tsg));
tsg.h_va_space = cpu_to_le32(boot_stage.rmcall_vas);
@@ -5185,15 +5451,26 @@ static int gsp_phys_rmcall_stage3(void __iomem *bar0)
pr_warn("gsp-phys-boot: rm-call: FBMEM error-notifier allocation failed (%d); channel allocs carry a zeroed notifier memdesc and only the stage-4 token recovery can save the token\n",
ret);
+ /*
+ * Allocate the USERD page in FBMEM as well (reference default); on
+ * failure the channel variants fall back to the sysmem USERD chunk.
+ */
+ ret = gsp_phys_rmcall_alloc_userd_mem(bar0);
+ if (ret)
+ pr_warn("gsp-phys-boot: rm-call: FBMEM USERD allocation failed (%d); channel allocs fall back to the sysmem USERD chunk\n",
+ ret);
+
ret = gsp_phys_rmcall_alloc_channel(bar0);
if (ret)
return ret;
- pr_info("gsp-phys-boot: rm-call: stage 3 complete: hVas=0x%x hTsg=0x%x hChannel=0x%x variant=V%u notifier=%s base=0x%llx engine=COPY0 (cid is server-assigned, request value ignored; token is requested in stage 4)\n",
+ pr_info("gsp-phys-boot: rm-call: stage 3 complete: hVas=0x%x hTsg=0x%x hChannel=0x%x variant=V%u notifier=%s base=0x%llx userd=%s base=0x%llx engine=COPY0 (cid is server-assigned, request value ignored; token is requested in stage 4)\n",
boot_stage.rmcall_vas, boot_stage.rmcall_tsg,
boot_stage.rmcall_channel, boot_stage.rmcall_channel_variant,
boot_stage.rmcall_notifier_valid ? "FBMEM" : "none",
- boot_stage.rmcall_notifier_base);
+ boot_stage.rmcall_notifier_base,
+ boot_stage.rmcall_userd_valid ? "FBMEM" : "sysmem",
+ boot_stage.rmcall_userd_base);
return 0;
}
@@ -5254,21 +5531,26 @@ static u32 gsp_phys_rmcall_build_methods(u32 *pb, u64 sem_dma, u64 src_dma,
/*
* Stage 4: the corrected token sequence - BIND (COPY0) -> GPFIFO_SCHEDULE ->
- * SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX -> GET_WORK_SUBMIT_TOKEN - then the first
- * real work item: write the CE method block to the pushbuffer, publish the
- * GPFIFO entry and the USERD GP_PUT (mem_utils_gm107.c:1815-1904), ring the
- * PF channel doorbell (kernel_fifo_tu102.c:46-59) and poll the sysmem
- * semaphore word. Afterwards dst must equal src byte for byte.
+ * TSG_GPFIFO_SCHEDULE -> SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX ->
+ * GET_WORK_SUBMIT_TOKEN - then the first real work item: write the CE method
+ * block to the pushbuffer, publish the GPFIFO entry (GET = the pushbuffer GPU
+ * VA) and the USERD GP_PUT (mem_utils_gm107.c:1815-1904), ring the PF channel
+ * doorbell (kernel_fifo_tu102.c:46-59) and poll the sysmem semaphore word.
+ * Afterwards dst must equal src byte for byte.
*
* BIND is the precondition the TU102 token generator needs (runlist
* membership, kernel_fifo_tu102.c:110-116; GPFIFO_SCHEDULE alone only sets
* RUNLIST_SET at kernel_channel.c:3244), and SET_NOTIF_INDEX (index 3 for
* subdevice 0, nvidia-push-init.c:303-316) gives the FBMEM notifier write a
* target slot; it is advisory here because no error-context object exists.
- * Every other control failure logs its rpc_result/status and aborts
- * before the doorbell; a 0x40 GET_WORK_SUBMIT_TOKEN whose echoed params carry
- * a nonzero token still proceeds (the server writes the token before the
- * notifier update, kernel_channel.c:3471-3477).
+ * The TSG-level NVA06C_CTRL_CMD_GPFIFO_SCHEDULE 0xa06c0101 ("schedules a
+ * channel group in hardware", ctrla06c.h:82-101) is insurance on top of the
+ * channel-level schedule, whose internal HAL is a stub in the shipped
+ * dispatch; it too is advisory. Every other control failure logs its
+ * rpc_result/status and aborts before the doorbell; a 0x40
+ * GET_WORK_SUBMIT_TOKEN whose echoed params carry a nonzero token still
+ * proceeds (the server writes the token before the notifier update,
+ * kernel_channel.c:3471-3477).
*/
static int gsp_phys_rmcall_stage4(void __iomem *bar0)
{
@@ -5340,6 +5622,30 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0)
}
/*
+ * (b2) TSG-level NVA06C_CTRL_CMD_GPFIFO_SCHEDULE (0xa06c0101, the
+ * "schedules a channel group in hardware" call, ctrla06c.h:82-101,
+ * same 2-byte NVA06F params) as insurance: the channel-level
+ * GPFIFO_SCHEDULE's internal HAL is a stub in the shipped dispatch, so
+ * the runlist entry is only fully committed by the group schedule.
+ * Advisory, not fatal: the channel-level schedule already set
+ * RUNLIST_SET, which is what the token generator consumes
+ * (kernel_channel.c:3237-3245).
+ */
+ rpc_result = 0;
+ status = 0;
+ ret = gsp_phys_rmcall_control(bar0, boot_stage.rmcall_tsg,
+ GSP_PHYS_RMCALL_CTRL_TSG_GPFIFO_SCHEDULE,
+ sched_params, sizeof(sched_params), 16,
+ NULL, 0, &rpc_result, &status,
+ "TSG_GPFIFO_SCHEDULE");
+ if (ret)
+ pr_warn("gsp-phys-boot: rm-call: TSG_GPFIFO_SCHEDULE (0xa06c0101 bEnable=1 bSkipSubmit=0 on hTsg=0x%x) advisory failure: rpc_result=0x%x status=0x%x; the channel-level schedule already set RUNLIST_SET, continuing\n",
+ boot_stage.rmcall_tsg, rpc_result, status);
+ else
+ pr_info("gsp-phys-boot: rm-call: TSG_GPFIFO_SCHEDULE 0xa06c0101 on hTsg=0x%x accepted (rpc_result=0x%x status=0x%x)\n",
+ boot_stage.rmcall_tsg, rpc_result, status);
+
+ /*
* (c) SET_WORK_SUBMIT_TOKEN_NOTIF_INDEX (nvidia-push-init.c:303-316).
* Advisory, not fatal: with no error-context object (hErrorContext=0)
* the server's memory and ctxdma lookups both fail and it returns
@@ -5412,18 +5718,25 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0)
slot = gpput;
/*
- * e0: GET = pushbuffer address >> 2 in bits 31:2, FETCH/NO_CONTEXT_
- * SWITCH 0 (class/cl906f.h:136-142); e1: GET_HI 7:0 = the address high
- * dword and LENGTH 30:10 in dwords, exactly as the reference RM's own
- * submission does it (mem_utils_gm107.c:1861-1868: NvU64_HI32(get) in
- * GET_HI, NvU64_LO32(get) >> 2 in GET). The physical channel model
- * addresses the ring and pushbuffer by their system DMA addresses.
+ * e0: GET = pushbuffer GPU VA >> 2 in bits 31:2, FETCH/NO_CONTEXT_
+ * SWITCH 0 (class/cl906f.h:136-142); e1: GET_HI 7:0 = the VA high byte
+ * and LENGTH 30:10 in dwords, exactly the reference RM's own submission
+ * (mem_utils_gm107.c:1858-1868: get = pbGpuVA + offset, NvU64_HI32(get)
+ * in GET_HI, NvU64_LO32(get) >> 2 in GET, PRIV USER and LEVEL MAIN).
+ * The engine translates this VA through the channel PDB built in
+ * gsp_phys_rmcall_pdb_build.
*/
- e0 = (u32)(pb_dma >> 2) & 0x3fffffffu;
- e1 = (u32)((pb_dma >> 32) & 0xffu) | (words << 10);
+ e0 = (u32)(GSP_PHYS_RMCALL_VA_PB >> 2) & 0x3fffffffu;
+ e1 = (u32)((GSP_PHYS_RMCALL_VA_PB >> 32) & 0xffu) | (words << 10);
put_unaligned_le32(e0, (u8 *)ring_va + slot * 8);
put_unaligned_le32(e1, (u8 *)ring_va + slot * 8 + 4);
dma_wmb();
+ /*
+ * GP_PUT stays on the client sysmem USERD chunk, which is the hardware
+ * USERD only on the FBMEM-alloc fallback path; when the server used the
+ * FBMEM USERD page this host write cannot reach it (no BAR1/PRAMIN
+ * aperture here), kept as-is for the fallback.
+ */
put_unaligned_le32((gpput + 1) % GSP_PHYS_RMCALL_GPFIFO_ENTRIES,
(u8 *)userd + GSP_PHYS_RMCALL_USERD_GPPUT_OFF);
/*
@@ -5442,8 +5755,10 @@ static int gsp_phys_rmcall_stage4(void __iomem *bar0)
wmb();
writel(doorbell, bar0 + GSP_PHYS_RMCALL_DOORBELL_OFF);
- pr_info("gsp-phys-boot: rm-call: submitted: pb=0x%llx words=%u slot=%u (was GPGet=%u GPPut=%u) e0=0x%08x e1=0x%08x token=0x%08x (runlistId=%u chId=0x%x) doorbell=0x%08x @0x%x; polling sem=0x%llx for 0x%08x (<=%u ms)\n",
- pb_dma, words, slot, gpget, gpput, e0, e1,
+ pr_info("gsp-phys-boot: rm-call: submitted: pb=0x%llx pbVa=0x%llx gpFifoVa=0x%llx userd=%s words=%u slot=%u (was GPGet=%u GPPut=%u) e0=0x%08x e1=0x%08x token=0x%08x (runlistId=%u chId=0x%x) doorbell=0x%08x @0x%x; polling sem=0x%llx for 0x%08x (<=%u ms)\n",
+ pb_dma, GSP_PHYS_RMCALL_VA_PB, GSP_PHYS_RMCALL_VA_GPFIFO,
+ boot_stage.rmcall_userd_valid ? "FBMEM" : "sysmem",
+ words, slot, gpget, gpput, e0, e1,
boot_stage.rmcall_token, runlist_id, ch_id, doorbell,
GSP_PHYS_RMCALL_DOORBELL_OFF, sem_dma,
GSP_PHYS_RMCALL_SEM_PAYLOAD, GSP_PHYS_RMCALL_TIMEOUT_MS);
@@ -5731,6 +6046,17 @@ static int gsp_phys_state_show(struct seq_file *m, void *v)
boot_stage.rmcall_notifier_valid ? "FBMEM" : "none",
boot_stage.rmcall_notifier_base);
seq_printf(m,
+ "rm_call_userd: userd=%s hMemory=0x%x base=0x%llx | rm_call_pdb: vaBase=0x%llx vaGpfifo=0x%llx vaPb=0x%llx\n",
+ boot_stage.rmcall_userd_valid ? "FBMEM" : "sysmem",
+ boot_stage.rmcall_userd_mem, boot_stage.rmcall_userd_base,
+ boot_stage.rmcall_va_base, boot_stage.rmcall_va_gpfifo,
+ boot_stage.rmcall_va_pb);
+ seq_printf(m,
+ "rm_call_pdb_entries: root=0x%016llx pd2=0x%016llx pd1=0x%016llx pd0Small=0x%016llx ptGpfifo=0x%016llx ptPb=0x%016llx\n",
+ boot_stage.rmcall_pdb_root, boot_stage.rmcall_pdb_pd2,
+ boot_stage.rmcall_pdb_pd1, boot_stage.rmcall_pdb_pd0_small,
+ boot_stage.rmcall_pt_gpfifo, boot_stage.rmcall_pt_pb);
+ seq_printf(m,
"wpr2: LO=0x%08x (VAL=0x%x) HI=0x%08x (VAL=0x%x) state=%s\n",
wpr2_lo, gsp_phys_fwsec_wpr2_lo_val(bar0),
wpr2_hi, gsp_phys_fwsec_wpr2_hi_val(bar0),
@@ -6625,12 +6951,24 @@ static_assert(offsetof(struct gsp_phys_rmcall_channel_params, process_id) == 296
"NV_CHANNEL_ALLOC_PARAMS.ProcessID must be at offset 296");
static_assert(offsetof(struct gsp_phys_rmcall_channel_params, tpc_config_id) == 360,
"NV_CHANNEL_ALLOC_PARAMS.tpcConfigID must be at offset 360");
-static_assert(GSP_PHYS_RMCALL_BUF_COUNT == 10,
- "the rm-call ladder registers exactly ten DMA buffers");
+static_assert(GSP_PHYS_RMCALL_BUF_COUNT == 14,
+ "the rm-call ladder registers exactly fourteen DMA buffers");
static_assert((GSP_PHYS_RMCALL_HANDLE_MEM_BASE +
(GSP_PHYS_RMCALL_BUF_COUNT - 1) *
GSP_PHYS_RMCALL_HANDLE_MEM_STRIDE) < 0xcaf80000u,
"rm-call memory handles must stay inside the RM client handle range");
+static_assert(GSP_PHYS_RMCALL_VA_PB + GSP_PHYS_PAGE_SIZE <=
+ GSP_PHYS_RMCALL_VAS_SIZE,
+ "the channel PDB VA window must stay below the VAS vaSize limit");
+static_assert(((GSP_PHYS_RMCALL_VA_BASE >> 47) & 0x3) == 0 &&
+ ((GSP_PHYS_RMCALL_VA_BASE >> 38) & 0x1ff) == 0 &&
+ ((GSP_PHYS_RMCALL_VA_BASE >> 29) & 0x1ff) == 0 &&
+ ((GSP_PHYS_RMCALL_VA_BASE >> 21) & 0xff) == 0 &&
+ ((GSP_PHYS_RMCALL_VA_PB >> 21) & 0xff) == 0,
+ "the channel PDB VA window must sit in root/PD2/PD1/PD0 index 0 (GP10X 48:47/46:38/37:29/28:21 splits)");
+static_assert(((GSP_PHYS_RMCALL_VA_GPFIFO >> 12) & 0x1ff) !=
+ ((GSP_PHYS_RMCALL_VA_PB >> 12) & 0x1ff),
+ "the GPFIFO and pushbuffer VAs must take distinct small-PT slots");
/*
* GspSystemInfo wire ABI, pinned against the reference header compile