]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/nouveau: verify that hardware supports the flush page address
authorTimur Tabi <ttabi@nvidia.com>
Thu, 13 Nov 2025 23:03:23 +0000 (17:03 -0600)
committerLyude Paul <lyude@redhat.com>
Mon, 24 Nov 2025 22:53:22 +0000 (17:53 -0500)
Ensure that the DMA address of the framebuffer flush page is not larger
than its hardware register.

On GPUs older than Hopper, the register for the address can hold up to a
40-bit address (right-shifted by 8 so that it fits in the 32-bit
register), and on Hopper and later it can be 52 bits (64-bit register
where bits 52-63 must be zero).

Recently it was discovered that under certain conditions, the flush page
could be allocated outside this range.  Although this bug was fixed, we
can ensure that any future changes to this code don't accidentally
generate an invalid page address.

Signed-off-by: Timur Tabi <ttabi@nvidia.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patch.msgid.link/20251113230323.1271726-2-ttabi@nvidia.com
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gb100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gb202.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gh100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c

index 1c78c88536179ccb532b3aa4c343f5f9fd7d73be..170776cc82fbf1650025dc5b0a490698dc5310e5 100644 (file)
@@ -15,6 +15,9 @@ gb100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
        const u32 hshub = DRF_LO(NV_PFB_HSHUB0);
        struct nvkm_device *device = fb->subdev.device;
 
+       // Ensure that the address is within hardware limits
+       WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
+
        nvkm_wr32(device, hshub + NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI, addr_hi);
        nvkm_wr32(device, hshub + NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO, addr_lo);
        nvkm_wr32(device, hshub + NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI, addr_hi);
index 848505026d02ce5d8f979cd45e37103ea1857b41..a21bf19e10416518bc6c1828f621f417bace09fb 100644 (file)
@@ -13,6 +13,9 @@ gb202_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
        struct nvkm_device *device = fb->subdev.device;
        const u64 addr = fb->sysmem.flush_page_addr;
 
+       // Ensure that the address is within hardware limits
+       WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
+
        nvkm_wr32(device, NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_HI, upper_32_bits(addr));
        nvkm_wr32(device, NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_LO, lower_32_bits(addr));
 }
index 07db9b397ac1f7cfc488fe1170e783d4e1eb3e53..64281a09fb39e56f1abc00afbee2632ec785e514 100644 (file)
@@ -80,6 +80,9 @@ gf100_fb_init_page(struct nvkm_fb *fb)
 void
 gf100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
 {
+       // Ensure that the address can actually fit in the register
+       WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(40));
+
        nvkm_wr32(fb->subdev.device, 0x100c10, fb->sysmem.flush_page_addr >> 8);
 }
 
index 2d8c51f882d52c6ae4b64bc54a91f981f73483e2..8c9394048f25cfd1739b3a07b8045bd7520f0841 100644 (file)
@@ -13,6 +13,9 @@ gh100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
        const u64 addr = fb->sysmem.flush_page_addr >> NV_PFB_NISO_FLUSH_SYSMEM_ADDR_SHIFT;
        struct nvkm_device *device = fb->subdev.device;
 
+       // Ensure that the address is within hardware limits
+       WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
+
        nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI, upper_32_bits(addr));
        nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO, lower_32_bits(addr));
 }
index a6efbd913c13843baa1ba413e41ba9419d9d0d55..076d968b7297eb03ef780c607c8737fb6f242717 100644 (file)
@@ -214,6 +214,9 @@ nv50_fb_tags(struct nvkm_fb *base)
 static void
 nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
 {
+       // Ensure that the address can actually fit in the register
+       WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(40));
+
        nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8);
 }