[PATCH] drm/nouveau/kms/nvd9-: Use contiguous memory for CRC notifier context

From: Lyude Paul

Date: Fri May 01 2026 - 17:59:41 EST


It looks like CRC read back has been slightly broken for a while now, in
particular on GPUs using GSP. On my test machines, it's worked normally
when attempting to use it from fbcon. After gnome-shell gets started
however, attempting to read /sys/kernel/debug/dri/$CARD/$CRTC/crc/data just
returns -EINVAL.

It turns out what's been happening is that since we've been using
nvif_mem_ctor_map() to both allocate and map the CRC notifier region - we
haven't actually asked for a contiguous allocation, and simply ask for
whatever type of memory allocation nouveau can find first. This doesn't
work because the CRC engine on nvidia GPUs doesn't support non-contiguous
allocations, which also causes us to fail setting up the kmsCrcNtfyCtxDma
object on pre-blackwell platforms since we don't have a single memory
address we can point nvif_object_ctor() to. Instead, ctx->mem.addr gets set
to ~0ULL.

It does however, seem to work when fbcon is running. The only reason I can
think of this is that before we start up a display environment, there is
pretty much nothing allocated in our VRAM that wasn't allocated by nouveau
itself - making it dramatically more likely that we end up finding a
contiguous allocation by default.

So, fix this by manually requesting a contiguous allocation when we
allocate our context notifiers.

Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx>
Fixes: 12885ecbfe62 ("drm/nouveau/kms/nvd9-: Add CRC support")
Cc: Lyude Paul <lyude@xxxxxxxxxx>
Cc: Dave Airlie <airlied@xxxxxxxxx>
Cc: Danilo Krummrich <dakr@xxxxxxxxxx>
Cc: Dave Airlie <airlied@xxxxxxxxxx>
Cc: Timur Tabi <ttabi@xxxxxxxxxx>
Cc: Suraj Kandpal <suraj.kandpal@xxxxxxxxx>
Cc: James Jones <jajones@xxxxxxxxxx>
Cc: Faith Ekstrand <faith.ekstrand@xxxxxxxxxxxxx>
Cc: dri-devel@xxxxxxxxxxxxxxxxxxxxx
Cc: nouveau@xxxxxxxxxxxxxxxxxxxxx
Cc: <stable@xxxxxxxxxxxxxxx> # v5.9+
---
drivers/gpu/drm/nouveau/dispnv50/crc.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c
index deb6af40ef328..5817f39934a8b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/crc.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c
@@ -10,6 +10,7 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/timer.h>
+#include <nvif/if900b.h>

#include <nvhw/class/cl907d.h>

@@ -499,16 +500,24 @@ nv50_crc_raster_type(enum nv50_crc_source source)
* notifier needs it's own handle
*/
static inline int
-nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu *mmu,
+nv50_crc_ctx_init(struct drm_device *dev, struct nv50_head *head, struct nvif_mmu *mmu,
struct nv50_crc_notifier_ctx *ctx, size_t len, int idx)
{
- struct nv50_core *core = nv50_disp(head->base.base.dev)->core;
+ struct nv50_core *core = nv50_disp(dev)->core;
int ret;

- ret = nvif_mem_ctor_map(mmu, "kmsCrcNtfy", NVIF_MEM_VRAM, len, &ctx->mem);
+ /* The display engine requires a contiguous region of memory for the CRC notifier context */
+ ret = nvif_mem_ctor(mmu, "kmsCrcNtfy", mmu->mem, NVIF_MEM_VRAM | NVIF_MEM_MAPPABLE, 0, len,
+ &(struct gf100_mem_v0) {
+ .contig = true,
+ }, sizeof(struct gf100_mem_v0), &ctx->mem);
if (ret)
return ret;

+ ret = nvif_object_map(&ctx->mem.object, NULL, 0);
+ if (ret)
+ goto fail_fini;
+
/* No CTXDMAs on Blackwell. */
if (core->chan.base.user.oclass >= GB202_DISP_CORE_CHANNEL_DMA)
return 0;
@@ -576,7 +585,7 @@ int nv50_crc_set_source(struct drm_crtc *crtc, const char *source_str)

if (source) {
for (i = 0; i < ARRAY_SIZE(head->crc.ctx); i++) {
- ret = nv50_crc_ctx_init(head, mmu, &crc->ctx[i],
+ ret = nv50_crc_ctx_init(dev, head, mmu, &crc->ctx[i],
func->notifier_len, i);
if (ret)
goto out_ctx_fini;

base-commit: 29d6da40d0b8bf3bbc3dcd1d2198434a0e1f71b0
--
2.54.0