* [PATCH] nouveau: Fix rerunning VBIOS on GF104
@ 2026-10-20 17:48 Matt Harding
0 siblings, 0 replies; only message in thread
From: Matt Harding @ 2026-10-20 17:48 UTC (permalink / raw)
To: nouveau; +Cc: dakr, Matt Harding
In 2016, in commit a6a0f67ca7aae2e6 `drm/nouveau/devinit/gf100-: detect if BIOS invoked devinit`
Nvidia engineer Gnurou changed how Nouveau detects that the VBIOS has
already run for GF100 GPUs and newer. This was by reading a bit called
NV_PTOP_SCRATCH1_DEVINIT_COMPLETED in a register at address 0x2240c.
However, on my Nvidia GTX 460, a GF104 card, this register doesn't appear
to exist or behave that way. This results in Nouveau re-running the VBIOS,
when the card had already been initialised by the BIOS at boot time. This
causes the hardware to get in a bad state, causing symptoms in the system
log such as an MMIO fault with the message:
`nouveau 0000:01:00.0: bus: MMIO write of 00000002 FAULT at 13c1d4 [ PRIVRING ]`
among other MMIO faults, and a stack trace in:
`drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c:305 nvkm_outp_inherit+0xf5/0x140`
among others.
I've seen another report of the same problem on the ubuntu mailing list:
https://www.mail-archive.com/ubuntu-bugs%40lists.ubuntu.com/msg6269141.html
My proposed fix for this is to revert the GF100 preinit subroutine to
nv50_devinit_preinit(), and to push the logic in gf100_devinit_preinit()
up to gm107.c.
I also have a laptop with a GTX 630M, with a GF108, and I note that the
register bit in question appears to exist and function as expected on that
chip. So it appears that it exists on some GF chips, but not all. So it
may be be possible, with enough investigation, to make this more snuggly
fit the exact chips which support this feature. However,
nv50_devinit_preinit() seems to work well enough for both of these chips,
and as it was used for this family of chips before the bug was introduced,
I think reverting to it is acceptable.
Fixes: a6a0f67ca7aa ("drm/nouveau/devinit/gf100-: detect if BIOS invoked devinit")
Signed-off-by: Matt Harding <majaharding@gmail.com>
---
.../gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c | 16 +---------------
.../gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c | 16 +++++++++++++++-
.../gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c | 2 +-
.../gpu/drm/nouveau/nvkm/subdev/devinit/gv100.c | 2 +-
.../gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h | 2 +-
5 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
index 5368e705e7fd..069f64283b45 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
@@ -87,23 +87,9 @@ gf100_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 1);
}
-void
-gf100_devinit_preinit(struct nvkm_devinit *base)
-{
- struct nv50_devinit *init = nv50_devinit(base);
- struct nvkm_subdev *subdev = &init->base.subdev;
- struct nvkm_device *device = subdev->device;
-
- /*
- * This bit is set by devinit, and flips back to 0 on suspend. We
- * can use it as a reliable way to know whether we should run devinit.
- */
- base->post = ((nvkm_rd32(device, 0x2240c) & BIT(1)) == 0);
-}
-
static const struct nvkm_devinit_func
gf100_devinit = {
- .preinit = gf100_devinit_preinit,
+ .preinit = nv50_devinit_preinit,
.init = nv50_devinit_init,
.post = nv04_devinit_post,
.pll_set = gf100_devinit_pll_set,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
index 271bfa038f5b..caabd6975a92 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
@@ -45,9 +45,23 @@ gm107_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_DISP, 0);
}
+void
+gm107_devinit_preinit(struct nvkm_devinit *base)
+{
+ struct nv50_devinit *init = nv50_devinit(base);
+ struct nvkm_subdev *subdev = &init->base.subdev;
+ struct nvkm_device *device = subdev->device;
+
+ /*
+ * This bit is set by devinit, and flips back to 0 on suspend. We
+ * can use it as a reliable way to know whether we should run devinit.
+ */
+ base->post = ((nvkm_rd32(device, 0x2240c) & BIT(1)) == 0);
+}
+
static const struct nvkm_devinit_func
gm107_devinit = {
- .preinit = gf100_devinit_preinit,
+ .preinit = gm107_devinit_preinit,
.init = nv50_devinit_init,
.post = nv04_devinit_post,
.pll_set = gf100_devinit_pll_set,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
index f30718d7e61a..86e6585244b7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c
@@ -177,7 +177,7 @@ gm200_devinit_post(struct nvkm_devinit *base, bool post)
static const struct nvkm_devinit_func
gm200_devinit = {
- .preinit = gf100_devinit_preinit,
+ .preinit = gm107_devinit_preinit,
.init = nv50_devinit_init,
.post = gm200_devinit_post,
.pll_set = gf100_devinit_pll_set,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gv100.c
index b4d1688517d5..2c20460201a8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gv100.c
@@ -64,7 +64,7 @@ gv100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
static const struct nvkm_devinit_func
gv100_devinit = {
- .preinit = gf100_devinit_preinit,
+ .preinit = gm107_devinit_preinit,
.init = nv50_devinit_init,
.post = gm200_devinit_post,
.pll_set = gv100_devinit_pll_set,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
index 8de409c084c1..8697c2cbd409 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
@@ -21,7 +21,7 @@ int gf100_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
struct nvkm_oclass *, void *, u32,
struct nvkm_object **);
int gf100_devinit_pll_set(struct nvkm_devinit *, u32, u32);
-void gf100_devinit_preinit(struct nvkm_devinit *);
+void gm107_devinit_preinit(struct nvkm_devinit *);
void gm107_devinit_disable(struct nvkm_devinit *);
--
2.53.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-20 17:53 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 17:48 [PATCH] nouveau: Fix rerunning VBIOS on GF104 Matt Harding
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.