diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-01 10:07:14 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-01 10:07:14 -0400 |
| commit | 5f372957a5fd0dd7ca7d4b5f06e959cce92dd49e (patch) | |
| tree | 03000df095fa084c733f87634d92d1b8e8be1e0f /kernel/gsp_phys_fwsec.c | |
| parent | 4805f88b6d1449d23bf8af2e80a9b2b1984f7189 (diff) | |
| download | open-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.c | 136 |
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); |
