summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 00:14:09 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-01 00:14:09 -0400
commitd9f8a360ae17cb3386b4d7e660a69fb92c81367e (patch)
treefdad5e0085eb9d68fcb8bf09d7e7eeea34f808cd
parentcfa57c6a4640a6dabba25ec3c71ff9292049bdaa (diff)
downloadopen-iov-d9f8a360ae17cb3386b4d7e660a69fb92c81367e.tar.gz
open-iov-d9f8a360ae17cb3386b4d7e660a69fb92c81367e.zip
gsp-phys: harden the D0 lock (pre-lock readiness, no unlock without rebind, strict board check)
-rw-r--r--kernel/gsp_phys_gpu.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/kernel/gsp_phys_gpu.c b/kernel/gsp_phys_gpu.c
index f9fffc4..40759a1 100644
--- a/kernel/gsp_phys_gpu.c
+++ b/kernel/gsp_phys_gpu.c
@@ -26,9 +26,14 @@
* the whole unbind -> claim -> release window. The GPU config ID and the
* root-port link status are re-read after the claim and again before
* rebinding the distribution driver; an unresponsive board aborts the
- * handoff and the locks are deliberately left in place. Residual risk: a
- * platform power cut that is not driven by PCI D3 (EC/SMI or thermal) has
- * the same signature; if it happens, do not retry in that boot.
+ * handoff and the locks are deliberately left in place. The root-port lock
+ * is the load-bearing one: once the port cannot enter D3, a driverless
+ * GPU's own D3hot alone cannot cut the board rail. The GPU-side runtime-PM
+ * forbid is best-effort only, because the distribution driver's remove may
+ * itself consume the GPU's runtime-PM reference; the port lock and
+ * no_d3cold are the real guarantees. Residual risk: a platform power cut
+ * that is not driven by PCI D3 (EC/SMI or thermal) has the same signature;
+ * if it happens, do not retry in that boot.
*
* Therefore claim now requires BOTH gsp_phys_gpu=1 AND
* gsp_phys_hazard_ack=1, and must not be enabled without a reviewed
@@ -511,8 +516,8 @@ static int gsp_phys_board_check(struct pci_dev *pdev, const char *phase)
int ret;
ret = pci_read_config_dword(pdev, PCI_VENDOR_ID, &id);
- if (ret != PCIBIOS_SUCCESSFUL || id == 0xffffffff ||
- (id & 0xffff) == 0x0000) {
+ if (ret != PCIBIOS_SUCCESSFUL || PCI_POSSIBLE_ERROR(id) ||
+ (id & 0xffff) != GSP_PHYS_VENDOR) {
WARN(1, "gsp-phys: board unresponsive %s: %s config id=0x%08x rc=%d; aborting - do not retry in this boot\n",
phase, pci_name(pdev), id, ret);
return -EIO;
@@ -587,6 +592,20 @@ int gsp_phys_gpu_claim(void)
}
/*
+ * Pre-lock readiness: pm_runtime_forbid() below calls rpm_resume(),
+ * which on an already power-gated board runs the exact freeze path
+ * we are trying to avoid. If the GPU or its root port is already
+ * runtime-suspended, refuse instead of resuming it.
+ */
+ if (pdev->dev.power.runtime_status == RPM_SUSPENDED ||
+ (pci_upstream_bridge(pdev) &&
+ pci_upstream_bridge(pdev)->dev.power.runtime_status == RPM_SUSPENDED)) {
+ pr_err("gsp-phys: refusing claim: GPU or root port already runtime-suspended; the board may be power-gated (refusing to resume it)\n");
+ pci_dev_put(pdev);
+ return -EBUSY;
+ }
+
+ /*
* Lock the whole board and its root port into D0 before the unbind;
* see the hazard note at the top of this file.
*/
@@ -697,13 +716,15 @@ void gsp_phys_gpu_release(void)
ret = device_attach(&pdev->dev);
drv = pdev->dev.driver;
- if (drv)
- pr_info("gsp-phys: released %s; rebound to %s (rc=%d)\n",
- pci_name(pdev), drv->name, ret);
- else
- pr_warn("gsp-phys: released %s; no driver rebound "
- "(rc=%d), run `modprobe nvidia`\n",
- pci_name(pdev), ret);
+ if (!drv) {
+ pr_err("gsp-phys: %s did not rebind (rc=%d); power domain stays LOCKED; rebind the distribution driver manually (e.g. `modprobe nvidia`), then unload\n",
+ pci_name(pdev), ret);
+ pci_dev_put(pdev);
+ return;
+ }
+
+ pr_info("gsp-phys: released %s; rebound to %s (rc=%d)\n",
+ pci_name(pdev), drv->name, ret);
pci_dev_put(pdev);
msleep(GSP_PHYS_POWER_SETTLE_MS);