summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_fwsec.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 01:21:50 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 01:21:50 -0400
commit12db41d77c899400fffc0486b64ebd057a1e95fa (patch)
tree726093bf0948a6eb8aa764e0b1ed38a520ea589e /kernel/gsp_phys_fwsec.c
parent55a8591fb503c3924f5037c39479ca811e00514b (diff)
downloadopen-iov-12db41d77c899400fffc0486b64ebd057a1e95fa.tar.gz
open-iov-12db41d77c899400fffc0486b64ebd057a1e95fa.zip
gsp-phys: fix the WPR2-up release hand-back and tighten FWSEC/VBIOS checks
Diffstat (limited to 'kernel/gsp_phys_fwsec.c')
-rw-r--r--kernel/gsp_phys_fwsec.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/kernel/gsp_phys_fwsec.c b/kernel/gsp_phys_fwsec.c
index 93a4208..a6f81e2 100644
--- a/kernel/gsp_phys_fwsec.c
+++ b/kernel/gsp_phys_fwsec.c
@@ -413,22 +413,29 @@ static int gsp_phys_falcon_wait_halt(void __iomem *bar0, u32 base,
}
}
-/* Wait for GFW boot completion: falcon halted and progress 0xff. */
+/* Wait for GFW boot completion: falcon halted, PLM lowered and progress 0xff. */
static int gsp_phys_fwsec_wait_gfw_boot(void __iomem *bar0)
{
unsigned long deadline = jiffies +
msecs_to_jiffies(GSP_PHYS_GFW_BOOT_TIMEOUT_MS);
- u32 cpuctl = 0, progress = 0;
+ u32 cpuctl = 0, progress = 0, plm = 0;
for (;;) {
cpuctl = readl(bar0 + GSP_PHYS_GSP_BASE +
GSP_PHYS_FALCON_CPUCTL);
+ plm = readl(bar0 + GSP_PHYS_GFW_PLM);
progress = readl(bar0 + GSP_PHYS_GFW_BOOT) &
GSP_PHYS_GFW_BOOT_PROGRESS_MASK;
+ /*
+ * FWSEC lowers its read-protection level before GFW posts
+ * progress; level0 must be readable for the progress to be
+ * meaningful.
+ */
if ((cpuctl & GSP_PHYS_CPUCTL_HALTED) &&
+ (plm & GSP_PHYS_GFW_PLM_LEVEL0) &&
progress == GSP_PHYS_GFW_BOOT_COMPLETED) {
- pr_info("gsp-phys-fwsec: GFW boot complete: CPUCTL=0x%08x (halted) progress=0xff\n",
- cpuctl);
+ pr_info("gsp-phys-fwsec: GFW boot complete: CPUCTL=0x%08x (halted) PLM=0x%08x progress=0xff\n",
+ cpuctl, plm);
return 0;
}
if (time_after_eq(jiffies, deadline))
@@ -436,8 +443,8 @@ static int gsp_phys_fwsec_wait_gfw_boot(void __iomem *bar0)
msleep(1);
}
- pr_err("gsp-phys-fwsec: GFW boot not complete (CPUCTL=0x%08x progress=0x%x, timeout %ums); not resetting or kicking the falcon\n",
- cpuctl, progress, GSP_PHYS_GFW_BOOT_TIMEOUT_MS);
+ pr_err("gsp-phys-fwsec: GFW boot not complete (CPUCTL=0x%08x PLM=0x%08x progress=0x%x, timeout %ums); not resetting or kicking the falcon\n",
+ cpuctl, plm, progress, GSP_PHYS_GFW_BOOT_TIMEOUT_MS);
return -ETIMEDOUT;
}
@@ -876,6 +883,13 @@ int gsp_phys_fwsec_run(struct gsp_phys_boot *boot, struct pci_dev *pdev,
return -EINVAL;
}
+ if (boot->frts_size != ((u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12)) {
+ pr_err("gsp-phys-fwsec: FRTS region size mismatch: boot layout 0x%llx, FWSEC constant 0x%llx; refusing stage 3c\n",
+ boot->frts_size,
+ (u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12);
+ return -EINVAL;
+ }
+
pr_info("gsp-phys-fwsec: stage 3c FWSEC/FRTS on %s: frtsOffset=0x%llx frtsSize=0x%llx\n",
pci_name(pdev), boot->frts_offset, boot->frts_size);
@@ -991,10 +1005,10 @@ int gsp_phys_fwsec_release(struct gsp_phys_boot *boot, struct pci_dev *pdev,
{
int ret;
- if (!fwsec.touched)
- return 0;
if (!pdev || !bar0)
return -EIO;
+ if (!fwsec.touched && !gsp_phys_fwsec_wpr2_up(bar0))
+ return 0;
if (!gsp_phys_fwsec_wpr2_up(bar0)) {
pr_info("gsp-phys-fwsec: release: WPR2 already down; freeing FWSEC staging and handing back\n");