summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_gpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_gpu.c')
-rw-r--r--kernel/gsp_phys_gpu.c182
1 files changed, 139 insertions, 43 deletions
diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c
index a507793..79c79bf 100644
--- a/kernel/gsp_phys_gpu.c
+++ b/kernel/gsp_phys_gpu.c
@@ -61,6 +61,7 @@
#include "gsp_phys_gpu.h"
#include "gsp_phys_boot.h"
+#include "gsp_phys_booter.h"
#include "gsp_phys_fwsec.h"
#define GSP_PHYS_VENDOR 0x10de
@@ -73,6 +74,12 @@
*/
#define GSP_PHYS_FW_DEFAULT "nvidia/570.211.01/gsp_tu10x.bin"
+/*
+ * Signature section of the GSP-RM ELF the booter verifies against
+ * (TU102/TU104 use the tu10x generation name).
+ */
+#define GSP_PHYS_FW_SIGNATURE_SECTION ".fwsignature_tu10x"
+
static char *gsp_phys_fw_name = GSP_PHYS_FW_DEFAULT;
module_param_named(gsp_phys_fw, gsp_phys_fw_name, charp, 0644);
MODULE_PARM_DESC(gsp_phys_fw, "GSP firmware image to load (default " GSP_PHYS_FW_DEFAULT ")");
@@ -134,7 +141,10 @@ struct gsp_phys_gpu {
resource_size_t bar3_len;
const struct firmware *fw;
u32 fw_crc32;
+ u64 fw_image_offset;
u64 fw_image_size;
+ u64 fw_sig_offset;
+ u64 fw_sig_size;
bool fw_loaded;
bool enabled;
bool regions;
@@ -202,7 +212,10 @@ static void gsp_phys_fw_unload(void)
phys.fw = NULL;
phys.fw_loaded = false;
phys.fw_crc32 = 0;
+ phys.fw_image_offset = 0;
phys.fw_image_size = 0;
+ phys.fw_sig_offset = 0;
+ phys.fw_sig_size = 0;
}
static const char *gsp_phys_fw_section_name(const struct firmware *fw,
@@ -279,8 +292,14 @@ static int gsp_phys_fw_load(void)
sh->sh_size > phys.fw->size - sh->sh_offset)
continue;
name = gsp_phys_fw_section_name(phys.fw, sh);
- if (!strcmp(name, ".fwimage"))
+ if (!strcmp(name, ".fwimage")) {
+ phys.fw_image_offset = sh->sh_offset;
phys.fw_image_size = sh->sh_size;
+ }
+ if (!strcmp(name, GSP_PHYS_FW_SIGNATURE_SECTION)) {
+ phys.fw_sig_offset = sh->sh_offset;
+ phys.fw_sig_size = sh->sh_size;
+ }
pr_info("gsp-phys-fw: [%02u] %-24s type=%u addr=0x%llx "
"off=0x%llx size=0x%llx\n", i, name,
sh->sh_type, (u64)sh->sh_addr,
@@ -289,8 +308,13 @@ static int gsp_phys_fw_load(void)
if (phys.fw_image_size)
pr_info("gsp-phys-fw: GSP-RM image section .fwimage "
- "size=0x%llx (boot-layout input)\n",
- phys.fw_image_size);
+ "off=0x%llx size=0x%llx (boot-layout input)\n",
+ phys.fw_image_offset, phys.fw_image_size);
+ if (phys.fw_sig_size)
+ pr_info("gsp-phys-fw: boot signature section %s "
+ "off=0x%llx size=0x%llx (boot input)\n",
+ GSP_PHYS_FW_SIGNATURE_SECTION,
+ phys.fw_sig_offset, phys.fw_sig_size);
}
return 0;
@@ -627,6 +651,14 @@ static void gsp_phys_claim_failed(struct pci_dev *pdev)
gsp_phys_power_unlock();
}
+static void gsp_phys_fw_boot_sources(struct gsp_phys_boot_sources *src)
+{
+ src->fw_image = (const u8 *)phys.fw->data + phys.fw_image_offset;
+ src->fw_image_size = phys.fw_image_size;
+ src->fw_signature = (const u8 *)phys.fw->data + phys.fw_sig_offset;
+ src->fw_signature_size = phys.fw_sig_size;
+}
+
int gsp_phys_gpu_claim(void)
{
struct pci_dev *pdev;
@@ -715,43 +747,102 @@ int gsp_phys_gpu_claim(void)
} else {
pr_info("gsp-phys: real GSP firmware staged (backend rung 2)\n");
- if (gsp_phys_layout_enabled()) {
- if (gsp_phys_boot_layout_init(&phys.boot, phys.pdev,
- phys.bar0,
- phys.fw_image_size,
- phys.bar1_len)) {
- pr_warn("gsp-phys: boot layout/allocation failed; "
- "backend stays at rung 2\n");
- } else if (gsp_phys_fwsec_enabled() ||
- gsp_phys_fwsec_dryrun_enabled()) {
- if (gsp_phys_fwsec_enabled() &&
- gsp_phys_fwsec_dryrun_enabled()) {
- pr_err("gsp-phys: gsp_phys_fwsec=1 and "
- "gsp_phys_fwsec_dryrun=1 are "
- "mutually exclusive; refusing "
- "both (no writes, nothing run)\n");
- } else if (gsp_phys_fwsec_dryrun_enabled()) {
- if (gsp_phys_fwsec_dryrun_run(
- &phys.boot, phys.pdev,
- phys.bar0))
- pr_warn("gsp-phys: stage 3c "
- "dry-run failed "
- "(read-only; see log "
- "above)\n");
- else
- pr_info("gsp-phys: stage 3c "
- "dry-run complete "
- "(read-only; nothing "
- "written)\n");
- } else if (gsp_phys_fwsec_run(&phys.boot,
+ {
+ bool boot = gsp_phys_boot_enabled();
+ bool boot_dry = gsp_phys_boot_dryrun_enabled();
+ bool fwsec = gsp_phys_fwsec_enabled();
+ bool fwsec_dry = gsp_phys_fwsec_dryrun_enabled();
+
+ /*
+ * Mutually exclusive stage combinations refuse loudly
+ * and write nothing. The boot lifecycle (gsp_phys_boot)
+ * owns the only device-writing FWSEC path: FWSEC alone
+ * is not host-recoverable (its WPR2 carve cannot pass
+ * the booter-unload handoff gate), so it is refused
+ * outright.
+ */
+ if ((boot && boot_dry) || (boot && fwsec_dry) ||
+ (boot_dry && fwsec)) {
+ pr_err("gsp-phys: REFUSED: conflicting stage parameters (gsp_phys_boot=%u gsp_phys_boot_dryrun=%u gsp_phys_fwsec=%u gsp_phys_fwsec_dryrun=%u); refusing all stages (nothing written)\n",
+ (unsigned int)boot, (unsigned int)boot_dry,
+ (unsigned int)fwsec,
+ (unsigned int)fwsec_dry);
+ } else if (fwsec && !boot) {
+ pr_err("gsp-phys-fwsec: REFUSED: FWSEC-only carve is not host-recoverable; use gsp_phys_boot=1 (full boot lifecycle) or gsp_phys_fwsec_dryrun=1 (read-only)\n");
+ } else if (gsp_phys_layout_enabled() ||
+ gsp_phys_boot_requested() || fwsec_dry) {
+ if (!gsp_phys_layout_enabled() &&
+ !gsp_phys_boot_requested() && fwsec_dry)
+ pr_info("gsp-phys: gsp_phys_fwsec_dryrun set without gsp_phys_layout (or gsp_phys_boot); initialising the stage-3b boot layout for the read-only dry-run (nothing written)\n");
+ if (gsp_phys_boot_layout_init(&phys.boot,
phys.pdev,
- phys.bar0)) {
- pr_warn("gsp-phys: stage 3c FWSEC failed "
- "(see recovery log above)\n");
- } else {
- pr_info("gsp-phys: stage 3c FWSEC complete "
- "(WPR2 up; release will tear it "
- "down)\n");
+ phys.bar0,
+ phys.fw_image_size,
+ phys.bar1_len)) {
+ pr_warn("gsp-phys: boot layout/allocation failed; backend stays at rung 2\n");
+ } else if (boot) {
+ struct gsp_phys_boot_sources src;
+
+ if (!phys.fw_loaded || !phys.fw_image_size ||
+ !phys.fw_sig_size) {
+ pr_err("gsp-phys: gsp_phys_boot=1 but the staged firmware lacks .fwimage/%s; refusing the boot stages (no writes)\n",
+ GSP_PHYS_FW_SIGNATURE_SECTION);
+ } else if (gsp_phys_fwsec_board_debug(phys.bar0)) {
+ pr_err("gsp-phys: gsp_phys_boot=1 on a debug-fuse board but only production boot images are staged; refusing all boot stages before FWSEC (nothing written)\n");
+ } else if (gsp_phys_fwsec_run(&phys.boot,
+ phys.pdev,
+ phys.bar0)) {
+ pr_warn("gsp-phys: stage 3c FWSEC failed (see recovery log above)\n");
+ } else {
+ gsp_phys_fw_boot_sources(&src);
+ pr_info("gsp-phys: stage 3c FWSEC complete (WPR2 up; release will tear it down)\n");
+ if (gsp_phys_boot_prime(&phys.boot,
+ phys.pdev,
+ phys.bar0,
+ &src,
+ false)) {
+ pr_warn("gsp-phys: stage 3d boot staging failed (see log above)\n");
+ } else if (gsp_phys_boot_run(&phys.boot,
+ phys.pdev,
+ phys.bar0)) {
+ pr_warn("gsp-phys: stage 3d boot failed (see log above); release runs the existing WPR2 teardown\n");
+ } else {
+ pr_info("gsp-phys: stage 3d boot complete\n");
+ gsp_phys_boot_rmwait(&phys.boot,
+ phys.bar0,
+ phys.bar0_len);
+ }
+ }
+ } else if (fwsec_dry || boot_dry) {
+ struct gsp_phys_boot_sources src;
+
+ if (fwsec_dry) {
+ if (gsp_phys_fwsec_dryrun_run(
+ &phys.boot, phys.pdev,
+ phys.bar0))
+ pr_warn("gsp-phys: stage 3c dry-run failed (read-only; see log above)\n");
+ else
+ pr_info("gsp-phys: stage 3c dry-run complete (read-only; nothing written)\n");
+ }
+ if (boot_dry) {
+ if (!phys.fw_loaded ||
+ !phys.fw_image_size ||
+ !phys.fw_sig_size) {
+ pr_warn("gsp-phys: stage 3d dry-run unavailable: staged firmware lacks .fwimage/%s (read-only)\n",
+ GSP_PHYS_FW_SIGNATURE_SECTION);
+ } else {
+ gsp_phys_fw_boot_sources(&src);
+ if (gsp_phys_boot_prime(
+ &phys.boot,
+ phys.pdev,
+ phys.bar0,
+ &src,
+ true))
+ pr_warn("gsp-phys: stage 3d dry-run prime failed (read-only; see log above)\n");
+ else
+ pr_info("gsp-phys: stage 3d dry-run prime complete (read-only; nothing written)\n");
+ }
+ }
}
}
}
@@ -795,18 +886,23 @@ void gsp_phys_gpu_release(void)
* WPR2 teardown must run while this module still owns BAR0. A
* successful stage 3c leaves WPR2 carved in FB; the distribution
* driver refuses to boot against an unexpected WPR2, so it has to be
- * removed (FWSEC-SB + booter unload) before the hand-back. If the
- * board stopped answering, skip the teardown (writes to a dead
- * device are pointless) and let the fail-safe below refuse the
- * hand-back.
+ * removed (FWSEC-SB + booter unload) before the hand-back. If stage 3d
+ * issued a Booter Load kick, the GSP falcon is quiesced first; the boot
+ * staging is then freed only after the teardown has reset both falcons,
+ * so no ucode can still DMA from it. If the board stopped answering,
+ * skip device writes (staging is still freed) and let the fail-safe
+ * below refuse the hand-back.
*/
if (phys.pdev) {
if (gsp_phys_board_check(phys.pdev, "before WPR2 teardown")) {
wpr2_ret = -EIO;
+ gsp_phys_boot_staging_free(phys.pdev);
} else {
+ gsp_phys_boot_quiesce(phys.bar0);
wpr2_ret = gsp_phys_fwsec_release(&phys.boot,
phys.pdev,
phys.bar0);
+ gsp_phys_boot_staging_free(phys.pdev);
}
}