r535_bar_bar2_init() warns if the FB zero object cannot be wrapped or
mapped, but then continues and maps bar->flushFBZero through nvkm_kmap().

If the object was not created, nvkm_kmap() dereferences NULL. If
nvkm_kmap() returns NULL, assigning the result to bar->flushBAR2 clears
the existing physical-mode flush mapping and later r535_bar_flush() can
dereference NULL after the generic BAR2 init wrapper marks BAR2 active.

Keep the physical-mode flush mapping unless the BAR2 flush mapping was
successfully acquired. In fini, call nvkm_done() only for an acquired
BAR2 flush mapping, because nvkm_done() is not NULL-safe.

This issue was found by a static analysis checker and confirmed by
manual source review.

Fixes: 5bf0257136a2 ("drm/nouveau/mmu/r535: initial support")
Signed-off-by: Ruoyu Wang <[email protected]>
---
 .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/bar.c  | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/bar.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/bar.c
index fae08ac3b18c7..eb3a7ddfa3355 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/bar.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/bar.c
@@ -71,8 +71,9 @@ r535_bar_bar2_fini(struct nvkm_bar *bar)
        struct nvkm_vmm *vmm = gf100_bar(bar)->bar[0].vmm;
        struct nvkm_gsp *gsp = bar->subdev.device->gsp;
 
+       if (bar->flushFBZero && bar->flushBAR2 != bar->flushBAR2PhysMode)
+               nvkm_done(bar->flushFBZero);
        bar->flushBAR2 = bar->flushBAR2PhysMode;
-       nvkm_done(bar->flushFBZero);
 
        WARN_ON(r535_bar_bar2_update_pde(gsp, vmm->func->page[0].shift, 0));
 }
@@ -86,6 +87,7 @@ r535_bar_bar2_init(struct nvkm_bar *bar)
        struct nvkm_memory *pdb = vmm->pd->pt[0]->memory;
        u32 pdb_offset = vmm->pd->pt[0]->base;
        u32 pdbe_lo, pdbe_hi;
+       void __iomem *flush;
        u64 pdbe;
 
        nvkm_kmap(pdb);
@@ -106,12 +108,16 @@ r535_bar_bar2_init(struct nvkm_bar *bar)
                        ret = nvkm_memory_kmap(fbZero, &bar->flushFBZero);
                        nvkm_memory_unref(&fbZero);
                }
-               WARN_ON(ret);
+               if (WARN_ON(ret))
+                       return;
        }
 
+       flush = nvkm_kmap(bar->flushFBZero);
+       if (WARN_ON(!flush))
+               return;
+
+       bar->flushBAR2 = flush;
        bar->bar2 = true;
-       bar->flushBAR2 = nvkm_kmap(bar->flushFBZero);
-       WARN_ON(!bar->flushBAR2);
 }
 
 static void
-- 
2.51.0

Reply via email to