summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_fwsec.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 10:07:14 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 10:07:14 -0400
commit5f372957a5fd0dd7ca7d4b5f06e959cce92dd49e (patch)
tree03000df095fa084c733f87634d92d1b8e8be1e0f /kernel/gsp_phys_fwsec.c
parent4805f88b6d1449d23bf8af2e80a9b2b1984f7189 (diff)
downloadopen-iov-5f372957a5fd0dd7ca7d4b5f06e959cce92dd49e.tar.gz
open-iov-5f372957a5fd0dd7ca7d4b5f06e959cce92dd49e.zip
gsp-phys: real GSP boot stages 3d/3e and the GSP-RM run-sequencer event
Stage 3d stages the GSP-RM boot from host sysmem (FMC, radix3 over the GSP-RM ELF, signature, message queues, libos LOGINIT/LOGRM/RMARGS and GSP arguments) and runs Booter Load on SEC2: GSP RISC-V reset, libos mailbox, IMEM/DMEM direct load, BOOTVEC=0, M0==0, FALCON_OS, RISC-V active. Stage 3e links the status queue and polls for GSP-RM events; it now also executes the inline run-sequencer command buffer (event 0x1002) against BAR0 (REG_WRITE/MODIFY/POLL, DELAY, STORE, CORE_* including CORE_RESUME) and then waits for GSP_INIT_DONE 0x1001. Gated by gsp_phys_boot / gsp_phys_boot_dryrun (default off; the normal load path writes nothing). gsp_phys_fwsec=1 without gsp_phys_boot=1 is refused: a FWSEC-only carve cannot pass the booter-unload handoff gate. Release quiesces the GSP, runs the existing FWSEC-SB/booter-unload teardown and frees all staging. tools/gen_gsp_bindata.py decodes the public generated archives into the Booter Load image (prod signature patched at 0x8700) and the GSP-RM boot (FMC) image; both are self-checked at build time.
Diffstat (limited to 'kernel/gsp_phys_fwsec.c')
-rw-r--r--kernel/gsp_phys_fwsec.c136
1 files changed, 72 insertions, 64 deletions
diff --git a/kernel/gsp_phys_fwsec.c b/kernel/gsp_phys_fwsec.c
index 1fda977..83a68ed 100644
--- a/kernel/gsp_phys_fwsec.c
+++ b/kernel/gsp_phys_fwsec.c
@@ -31,6 +31,7 @@
#include <asm/unaligned.h>
#include "gsp_phys_fwsec.h"
+#include "gsp_phys_falcon.h"
#include "gsp_phys_vbios.h"
#include "gsp_phys_sec2_bl.h"
#include "gsp_phys_booter_unload_img.h"
@@ -67,63 +68,10 @@ bool gsp_phys_fwsec_dryrun_enabled(void)
return gsp_phys_fwsec_dryrun_param;
}
-/* Falcon engine bases (BAR0 absolute). */
-#define GSP_PHYS_GSP_BASE 0x00110000
-#define GSP_PHYS_GSP_FBIF_BASE 0x00110600
-#define GSP_PHYS_SEC2_BASE 0x00840000
-#define GSP_PHYS_SEC2_FBIF_BASE 0x00840600
-
-/* Falcon register offsets, relative to the engine base. */
-#define GSP_PHYS_FALCON_MAILBOX0 0x40
-#define GSP_PHYS_FALCON_MAILBOX1 0x44
-#define GSP_PHYS_FALCON_OS 0x80
-#define GSP_PHYS_FALCON_RM 0x84
-#define GSP_PHYS_FALCON_HWCFG2 0xf4
-#define GSP_PHYS_FALCON_CPUCTL 0x100
-#define GSP_PHYS_FALCON_BOOTVEC 0x104
-#define GSP_PHYS_FALCON_HWCFG 0x108
-#define GSP_PHYS_FALCON_DMACTL 0x10c
-#define GSP_PHYS_FALCON_CPUCTL_ALIAS 0x130
-#define GSP_PHYS_FALCON_IMEMC 0x180
-#define GSP_PHYS_FALCON_IMEMD 0x184
-#define GSP_PHYS_FALCON_IMEMT 0x188
-#define GSP_PHYS_FALCON_DMEMC 0x1c0
-#define GSP_PHYS_FALCON_DMEMD 0x1c4
-#define GSP_PHYS_FALCON_ENGINE 0x3c0
-
-/* FBIF registers, relative to the falcon's FBIF base. */
-#define GSP_PHYS_FBIF_TRANSCFG(i) ((i) * 4)
-#define GSP_PHYS_FBIF_CTL 0x24
-
-/* Falcon CPUCTL / ENGINE / DMACTL field bits. */
-#define GSP_PHYS_CPUCTL_STARTCPU BIT(1)
-#define GSP_PHYS_CPUCTL_HALTED BIT(4)
-#define GSP_PHYS_CPUCTL_ALIAS_EN BIT(6)
-#define GSP_PHYS_ENGINE_RESET BIT(0)
-#define GSP_PHYS_DMACTL_DMEM_SCRUBBING BIT(1)
-#define GSP_PHYS_DMACTL_IMEM_SCRUBBING BIT(2)
-#define GSP_PHYS_HWCFG_IMEM_SIZE 0x1ff
/*
- * SEC2 falcon HWCFG DMEM capacity: bits 17:9 in 256-byte blocks (the v04
- * falcon reports IMEM at 8:0 and DMEM at 17:9). Used to check the Booter
- * Unload DMEM data section against the engine's real capacity.
+ * GPU-side boot state registers (the falcon register map and helpers live in
+ * gsp_phys_falcon.h, shared with the Booter Load stage).
*/
-#define GSP_PHYS_HWCFG_DMEM_SIZE 0x0003fe00
-#define GSP_PHYS_HWCFG_DMEM_SIZE_SHIFT 9
-
-/* FBIF CTL / TRANSCFG fields. */
-#define GSP_PHYS_FBIF_CTL_ALLOW_PHYS_NO_CTX BIT(7)
-#define GSP_PHYS_FBIF_TRANSCFG_TARGET_MASK 0x3
-#define GSP_PHYS_FBIF_TRANSCFG_TARGET_COHERENT_SYSMEM 0x1
-#define GSP_PHYS_FBIF_TRANSCFG_MEM_TYPE BIT(2)
-
-/* IMEM/DMEM access port fields. */
-#define GSP_PHYS_FALCON_ADDR_MASK (0x0000fffc)
-#define GSP_PHYS_FALCON_AINCW BIT(24)
-#define GSP_PHYS_FALCON_AINCR BIT(25)
-#define GSP_PHYS_FALCON_IMEMC_SECURE BIT(28)
-
-/* GPU-side boot state registers. */
#define GSP_PHYS_PMC_BOOT_0 0x00000000
#define GSP_PHYS_VBIOS_SCRATCH_0E 0x001438
#define GSP_PHYS_VBIOS_SCRATCH_15 0x001454
@@ -151,6 +99,13 @@ bool gsp_phys_fwsec_dryrun_enabled(void)
#define GSP_PHYS_SCRATCH14_HANDOFF_MASK 0x0f000000u
#define GSP_PHYS_SCRATCH14_HANDOFF_SHIFT 24
#define GSP_PHYS_SCRATCH14_BOOTER_VERSION_TU10X 0u
+/* Remaining scratch-14 fields decoded by the stage-3d telemetry. */
+#define GSP_PHYS_SCRATCH14_ACR_VERSION_MASK 0x00f00000u
+#define GSP_PHYS_SCRATCH14_ACR_VERSION_SHIFT 20
+#define GSP_PHYS_SCRATCH14_BOOTER_LOAD_BIT BIT(24)
+#define GSP_PHYS_SCRATCH14_AHESASC_RELOAD_BIT BIT(25)
+#define GSP_PHYS_SCRATCH14_RELOAD_ACR_UNLOAD_BIT BIT(26)
+#define GSP_PHYS_SCRATCH14_ACR_UNLOAD_BOOTER_UNLOAD_BIT BIT(27)
/*
* Every BSI secure scratch has a companion privilege-level mask. The scratch
* is write-protected to level3 (the SEC2/HS context) by default, so a bare
@@ -323,23 +278,74 @@ static struct gsp_phys_fwsec {
struct gsp_phys_fwsec_ucode ucode;
} fwsec;
-static u32 gsp_phys_fwsec_wpr2_hi_val(void __iomem *bar0)
+u32 gsp_phys_fwsec_wpr2_hi_val(void __iomem *bar0)
{
return (readl(bar0 + GSP_PHYS_WPR2_ADDR_HI) >>
GSP_PHYS_WPR2_VAL_SHIFT) & GSP_PHYS_WPR2_VAL_MASK;
}
-static u32 gsp_phys_fwsec_wpr2_lo_val(void __iomem *bar0)
+u32 gsp_phys_fwsec_wpr2_lo_val(void __iomem *bar0)
{
return (readl(bar0 + GSP_PHYS_WPR2_ADDR_LO) >>
GSP_PHYS_WPR2_VAL_SHIFT) & GSP_PHYS_WPR2_VAL_MASK;
}
-static bool gsp_phys_fwsec_wpr2_up(void __iomem *bar0)
+bool gsp_phys_fwsec_wpr2_up(void __iomem *bar0)
{
return gsp_phys_fwsec_wpr2_hi_val(bar0) != 0;
}
+/*
+ * NV_FUSE_OPT_SECURE_GSP_DEBUG_DIS: the board runs in debug mode when the
+ * fuse field is 0 (the distribution driver then selects the debug FWSEC app
+ * and the debug GSP images). Read-only; shared with the stage-3d production-
+ * booter precondition so the fuse has a single reader.
+ */
+bool gsp_phys_fwsec_board_debug(void __iomem *bar0)
+{
+ u32 fuse = readl(bar0 + GSP_PHYS_FUSE_SECURE_GSP_DEBUG_DIS);
+ bool debug = !(fuse & GSP_PHYS_FUSE_SECURE_GSP_DEBUG_DIS_FIELD);
+
+ pr_info("gsp-phys-fwsec: fuse SECURE_GSP_DEBUG_DIS=0x%08x -> %s board mode\n",
+ fuse, debug ? "debug" : "production");
+ return debug;
+}
+
+/*
+ * Read NV_PGC6_BSI_VPR_SECURE_SCRATCH_14 and decode every field the boot
+ * lifecycle writes: the ACR binary version, the four sequence handoff bits
+ * and the booter binary version. Read-only; shared with the stage-3d
+ * telemetry so the register layout has a single definition.
+ */
+void gsp_phys_fwsec_scratch14_read(void __iomem *bar0,
+ struct gsp_phys_scratch14 *s)
+{
+ u32 raw = readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14);
+
+ s->raw = raw;
+ s->acr_version = (raw & GSP_PHYS_SCRATCH14_ACR_VERSION_MASK) >>
+ GSP_PHYS_SCRATCH14_ACR_VERSION_SHIFT;
+ s->booter_load = !!(raw & GSP_PHYS_SCRATCH14_BOOTER_LOAD_BIT);
+ s->ahesasc_booter_reload =
+ !!(raw & GSP_PHYS_SCRATCH14_AHESASC_RELOAD_BIT);
+ s->booter_reload_acr_unload =
+ !!(raw & GSP_PHYS_SCRATCH14_RELOAD_ACR_UNLOAD_BIT);
+ s->acr_unload_booter_unload =
+ !!(raw & GSP_PHYS_SCRATCH14_ACR_UNLOAD_BOOTER_UNLOAD_BIT);
+ s->booter_binary_version =
+ (raw & GSP_PHYS_SCRATCH14_BOOTER_VERSION_MASK) >>
+ GSP_PHYS_SCRATCH14_BOOTER_VERSION_SHIFT;
+}
+
+/* The booter-unload ucode gates on all four handoff bits being DONE. */
+static bool gsp_phys_fwsec_scratch14_all_done(void __iomem *bar0)
+{
+ u32 raw = readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14);
+
+ return (raw & GSP_PHYS_SCRATCH14_HANDOFF_MASK) ==
+ GSP_PHYS_SCRATCH14_HANDOFF_MASK;
+}
+
static void gsp_phys_fwsec_dump_state(void __iomem *bar0, const char *what)
{
pr_info("gsp-phys-fwsec: %s: GSP_CPUCTL=0x%08x SEC2_CPUCTL=0x%08x GSP_BOOTVEC=0x%08x WPR2_LO=0x%08x WPR2_HI=0x%08x scratch0E=0x%08x scratch15=0x%08x GFW_BOOT=0x%08x SEC2_M0=0x%08x SEC2_M1=0x%08x\n",
@@ -361,7 +367,7 @@ static void gsp_phys_fwsec_dump_state(void __iomem *bar0, const char *what)
* read cycles, wait for the IMEM/DMEM scrubbers to report done (bounded),
* then load FALCON_RM with the raw PMC_BOOT_0 value.
*/
-static int gsp_phys_falcon_reset(void __iomem *bar0, u32 base)
+int gsp_phys_falcon_reset(void __iomem *bar0, u32 base)
{
unsigned long deadline;
u32 i, value;
@@ -410,7 +416,7 @@ static int gsp_phys_falcon_reset(void __iomem *bar0, u32 base)
* Allow physical DMA without a bound context: FBIF CTL bit7 and DMACTL=0,
* so the generic boot-loader can fetch its code/data descriptors.
*/
-static void gsp_phys_falcon_disable_ctx_req(void __iomem *bar0, u32 base,
+void gsp_phys_falcon_disable_ctx_req(void __iomem *bar0, u32 base,
u32 fbif)
{
u32 value;
@@ -425,7 +431,7 @@ static void gsp_phys_falcon_disable_ctx_req(void __iomem *bar0, u32 base,
readl(bar0 + base + GSP_PHYS_FALCON_DMACTL));
}
-static void gsp_phys_falcon_dmem_copy(void __iomem *bar0, u32 base, u32 dest,
+void gsp_phys_falcon_dmem_copy(void __iomem *bar0, u32 base, u32 dest,
const u8 *src, u32 size)
{
u32 words = size / 4;
@@ -442,7 +448,7 @@ static void gsp_phys_falcon_dmem_copy(void __iomem *bar0, u32 base, u32 dest,
* IMEM block copy with per-256-byte tags starting at tag>>8, incrementing
* once per block. The tag names the virtual IMEM block the block belongs to.
*/
-static void gsp_phys_falcon_imem_copy(void __iomem *bar0, u32 base, u32 dest,
+void gsp_phys_falcon_imem_copy(void __iomem *bar0, u32 base, u32 dest,
const u8 *src, u32 size, bool secure,
u32 tag)
{
@@ -494,7 +500,7 @@ static void gsp_phys_falcon_imem_read(void __iomem *bar0, u32 base, u32 dest,
}
}
-static void gsp_phys_falcon_start_cpu(void __iomem *bar0, u32 base)
+void gsp_phys_falcon_start_cpu(void __iomem *bar0, u32 base)
{
u32 cpuctl = readl(bar0 + base + GSP_PHYS_FALCON_CPUCTL);
@@ -509,7 +515,7 @@ static void gsp_phys_falcon_start_cpu(void __iomem *bar0, u32 base)
}
}
-static int gsp_phys_falcon_wait_halt(void __iomem *bar0, u32 base,
+int gsp_phys_falcon_wait_halt(void __iomem *bar0, u32 base,
u32 timeout_ms)
{
unsigned long deadline = jiffies + msecs_to_jiffies(timeout_ms);
@@ -1715,6 +1721,8 @@ int gsp_phys_fwsec_release(struct gsp_phys_boot *boot, struct pci_dev *pdev,
}
pr_info("gsp-phys-fwsec: release: WPR2 is up; tearing down before hand-back\n");
+ pr_info("gsp-phys-fwsec: release: booter-unload gate input: scratch14 handoff bits all four DONE=%u\n",
+ gsp_phys_fwsec_scratch14_all_done(bar0));
ret = gsp_phys_fwsec_teardown(bar0);
gsp_phys_fwsec_ucode_free(pdev, &fwsec.ucode);