drm/nouveau/fb: handle sysmem flush page from common code
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:47:51 +0000 (20:47 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 9 Nov 2022 00:44:58 +0000 (10:44 +1000)
- also executes pre-DEVINIT, so early boot is able to DMA sysmem

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
15 files changed:
drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp102.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp10b.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h

index ef6a629..f2bd9b1 100644 (file)
@@ -35,6 +35,11 @@ struct nvkm_fb {
 
        struct nvkm_blob vpr_scrubber;
 
+       struct {
+               struct page *flush_page;
+               dma_addr_t flush_page_addr;
+       } sysmem;
+
        struct nvkm_ram *ram;
 
        struct {
index 6faaea9..2ebdec4 100644 (file)
@@ -57,6 +57,15 @@ nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile)
        }
 }
 
+static void
+nvkm_fb_sysmem_flush_page_init(struct nvkm_device *device)
+{
+       struct nvkm_fb *fb = device->fb;
+
+       if (fb->func->sysmem.flush_page_init)
+               fb->func->sysmem.flush_page_init(fb);
+}
+
 int
 nvkm_fb_bios_memtype(struct nvkm_bios *bios)
 {
@@ -168,6 +177,8 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
        for (i = 0; i < fb->tile.regions; i++)
                fb->func->tile.prog(fb, i, &fb->tile.region[i]);
 
+       nvkm_fb_sysmem_flush_page_init(subdev->device);
+
        if (fb->func->init)
                fb->func->init(fb);
 
@@ -193,6 +204,13 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
        return 0;
 }
 
+static int
+nvkm_fb_preinit(struct nvkm_subdev *subdev)
+{
+       nvkm_fb_sysmem_flush_page_init(subdev->device);
+       return 0;
+}
+
 static void *
 nvkm_fb_dtor(struct nvkm_subdev *subdev)
 {
@@ -212,20 +230,28 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev)
 
        nvkm_blob_dtor(&fb->vpr_scrubber);
 
+       if (fb->sysmem.flush_page) {
+               dma_unmap_page(subdev->device->dev, fb->sysmem.flush_page_addr,
+                              PAGE_SIZE, DMA_BIDIRECTIONAL);
+               __free_page(fb->sysmem.flush_page);
+       }
+
        if (fb->func->dtor)
                return fb->func->dtor(fb);
+
        return fb;
 }
 
 static const struct nvkm_subdev_func
 nvkm_fb = {
        .dtor = nvkm_fb_dtor,
+       .preinit = nvkm_fb_preinit,
        .oneinit = nvkm_fb_oneinit,
        .init = nvkm_fb_init,
        .intr = nvkm_fb_intr,
 };
 
-void
+int
 nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
             enum nvkm_subdev_type type, int inst, struct nvkm_fb *fb)
 {
@@ -234,6 +260,19 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
        fb->tile.regions = fb->func->tile.regions;
        fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", fb->func->default_bigpage);
        mutex_init(&fb->tags.mutex);
+
+       if (func->sysmem.flush_page_init) {
+               fb->sysmem.flush_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (!fb->sysmem.flush_page)
+                       return -ENOMEM;
+
+               fb->sysmem.flush_page_addr = dma_map_page(device->dev, fb->sysmem.flush_page,
+                                                         0, PAGE_SIZE, DMA_BIDIRECTIONAL);
+               if (dma_mapping_error(device->dev, fb->sysmem.flush_page_addr))
+                       return -EFAULT;
+       }
+
+       return 0;
 }
 
 int
@@ -242,6 +281,5 @@ nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
 {
        if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL)))
                return -ENOMEM;
-       nvkm_fb_ctor(func, device, type, inst, *pfb);
-       return 0;
+       return nvkm_fb_ctor(func, device, type, inst, *pfb);
 }
index b47bebf..5098f21 100644 (file)
@@ -26,9 +26,10 @@ static const struct nvkm_fb_func
 ga100_fb = {
        .dtor = gf100_fb_dtor,
        .oneinit = gf100_fb_oneinit,
-       .init = gp100_fb_init,
+       .init = gm200_fb_init,
        .init_page = gv100_fb_init_page,
        .init_unkn = gp100_fb_init_unkn,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = gp100_ram_new,
        .default_bigpage = 16,
 };
index 6ea7908..52435c0 100644 (file)
@@ -26,9 +26,10 @@ static const struct nvkm_fb_func
 ga102_fb = {
        .dtor = gf100_fb_dtor,
        .oneinit = gf100_fb_oneinit,
-       .init = gp100_fb_init,
+       .init = gm200_fb_init,
        .init_page = gv100_fb_init_page,
        .init_unkn = gp100_fb_init_unkn,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = ga102_ram_new,
        .default_bigpage = 16,
 };
index 9dcc40f..07db9b3 100644 (file)
@@ -61,14 +61,6 @@ gf100_fb_oneinit(struct nvkm_fb *base)
        if (ret)
                return ret;
 
-       fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       if (fb->r100c10_page) {
-               fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
-                                          PAGE_SIZE, DMA_BIDIRECTIONAL);
-               if (dma_mapping_error(device->dev, fb->r100c10))
-                       return -EFAULT;
-       }
-
        return 0;
 }
 
@@ -86,14 +78,17 @@ gf100_fb_init_page(struct nvkm_fb *fb)
 }
 
 void
+gf100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
+{
+       nvkm_wr32(fb->subdev.device, 0x100c10, fb->sysmem.flush_page_addr >> 8);
+}
+
+void
 gf100_fb_init(struct nvkm_fb *base)
 {
        struct gf100_fb *fb = gf100_fb(base);
        struct nvkm_device *device = fb->base.subdev.device;
 
-       if (fb->r100c10_page)
-               nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
        if (base->func->clkgate_pack) {
                nvkm_therm_clkgate_init(device->therm,
                                        base->func->clkgate_pack);
@@ -104,13 +99,6 @@ void *
 gf100_fb_dtor(struct nvkm_fb *base)
 {
        struct gf100_fb *fb = gf100_fb(base);
-       struct nvkm_device *device = fb->base.subdev.device;
-
-       if (fb->r100c10_page) {
-               dma_unmap_page(device->dev, fb->r100c10, PAGE_SIZE,
-                              DMA_BIDIRECTIONAL);
-               __free_page(fb->r100c10_page);
-       }
 
        return fb;
 }
@@ -136,6 +124,7 @@ gf100_fb = {
        .init = gf100_fb_init,
        .init_page = gf100_fb_init_page,
        .intr = gf100_fb_intr,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = gf100_ram_new,
        .default_bigpage = 17,
 };
index 0cac7b0..77472b5 100644 (file)
@@ -6,8 +6,6 @@
 
 struct gf100_fb {
        struct nvkm_fb base;
-       struct page *r100c10_page;
-       dma_addr_t r100c10;
 };
 
 int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
@@ -16,7 +14,5 @@ void *gf100_fb_dtor(struct nvkm_fb *);
 void gf100_fb_init(struct nvkm_fb *);
 void gf100_fb_intr(struct nvkm_fb *);
 
-void gp100_fb_init(struct nvkm_fb *);
-
 void gm200_fb_init(struct nvkm_fb *base);
 #endif
index 5acf8d1..fb02092 100644 (file)
@@ -46,9 +46,6 @@ gm200_fb_init(struct nvkm_fb *base)
        struct gf100_fb *fb = gf100_fb(base);
        struct nvkm_device *device = fb->base.subdev.device;
 
-       if (fb->r100c10_page)
-               nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
        nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8);
        nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8);
        nvkm_mask(device, 0x100cc4, 0x00060000,
@@ -62,6 +59,7 @@ gm200_fb = {
        .init = gm200_fb_init,
        .init_page = gm200_fb_init_page,
        .intr = gf100_fb_intr,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = gm200_ram_new,
        .default_bigpage = 0 /* per-instance. */,
 };
index 86f61a3..50875af 100644 (file)
@@ -30,6 +30,7 @@ gm20b_fb = {
        .init = gm200_fb_init,
        .init_page = gm200_fb_init_page,
        .intr = gf100_fb_intr,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .default_bigpage = 0 /* per-instance. */,
 };
 
index 09e943e..110c08c 100644 (file)
@@ -44,29 +44,15 @@ gp100_fb_init_remapper(struct nvkm_fb *fb)
        nvkm_mask(device, 0x100c14, 0x00040000, 0x00000000);
 }
 
-void
-gp100_fb_init(struct nvkm_fb *base)
-{
-       struct gf100_fb *fb = gf100_fb(base);
-       struct nvkm_device *device = fb->base.subdev.device;
-
-       if (fb->r100c10_page)
-               nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8);
-
-       nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8);
-       nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8);
-       nvkm_mask(device, 0x100cc4, 0x00060000,
-                 min(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17);
-}
-
 static const struct nvkm_fb_func
 gp100_fb = {
        .dtor = gf100_fb_dtor,
        .oneinit = gf100_fb_oneinit,
-       .init = gp100_fb_init,
+       .init = gm200_fb_init,
        .init_remapper = gp100_fb_init_remapper,
        .init_page = gm200_fb_init_page,
        .init_unkn = gp100_fb_init_unkn,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = gp100_ram_new,
 };
 
index e15ac4b..2658481 100644 (file)
@@ -55,9 +55,10 @@ static const struct nvkm_fb_func
 gp102_fb = {
        .dtor = gf100_fb_dtor,
        .oneinit = gf100_fb_oneinit,
-       .init = gp100_fb_init,
+       .init = gm200_fb_init,
        .init_remapper = gp100_fb_init_remapper,
        .init_page = gm200_fb_init_page,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .vpr.scrub_required = gp102_fb_vpr_scrub_required,
        .vpr.scrub = gp102_fb_vpr_scrub,
        .ram_new = gp100_ram_new,
index 84c9815..a04a5f7 100644 (file)
@@ -28,6 +28,7 @@ gp10b_fb = {
        .init = gm200_fb_init,
        .init_page = gm200_fb_init_page,
        .intr = gf100_fb_intr,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
 };
 
 int
index 63daa83..1f01264 100644 (file)
@@ -32,9 +32,10 @@ static const struct nvkm_fb_func
 gv100_fb = {
        .dtor = gf100_fb_dtor,
        .oneinit = gf100_fb_oneinit,
-       .init = gp100_fb_init,
+       .init = gm200_fb_init,
        .init_page = gv100_fb_init_page,
        .init_unkn = gp100_fb_init_unkn,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .vpr.scrub_required = gp102_fb_vpr_scrub_required,
        .vpr.scrub = gp102_fb_vpr_scrub,
        .ram_new = gp100_ram_new,
index 4864173..a6efbd9 100644 (file)
@@ -191,35 +191,12 @@ nv50_fb_intr(struct nvkm_fb *base)
        nvkm_chan_put(&chan, flags);
 }
 
-static int
-nv50_fb_oneinit(struct nvkm_fb *base)
-{
-       struct nv50_fb *fb = nv50_fb(base);
-       struct nvkm_device *device = fb->base.subdev.device;
-
-       fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       if (fb->r100c08_page) {
-               fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
-                                          PAGE_SIZE, DMA_BIDIRECTIONAL);
-               if (dma_mapping_error(device->dev, fb->r100c08))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
 static void
 nv50_fb_init(struct nvkm_fb *base)
 {
        struct nv50_fb *fb = nv50_fb(base);
        struct nvkm_device *device = fb->base.subdev.device;
 
-       /* Not a clue what this is exactly.  Without pointing it at a
-        * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
-        * cause IOMMU "read from address 0" errors (rh#561267)
-        */
-       nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8);
-
        /* This is needed to get meaningful information from 100c90
         * on traps. No idea what these values mean exactly. */
        nvkm_wr32(device, 0x100c90, fb->func->trap);
@@ -234,17 +211,16 @@ nv50_fb_tags(struct nvkm_fb *base)
        return 0;
 }
 
+static void
+nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
+{
+       nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8);
+}
+
 static void *
 nv50_fb_dtor(struct nvkm_fb *base)
 {
        struct nv50_fb *fb = nv50_fb(base);
-       struct nvkm_device *device = fb->base.subdev.device;
-
-       if (fb->r100c08_page) {
-               dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE,
-                              DMA_BIDIRECTIONAL);
-               __free_page(fb->r100c08_page);
-       }
 
        return fb;
 }
@@ -253,9 +229,9 @@ static const struct nvkm_fb_func
 nv50_fb_ = {
        .dtor = nv50_fb_dtor,
        .tags = nv50_fb_tags,
-       .oneinit = nv50_fb_oneinit,
        .init = nv50_fb_init,
        .intr = nv50_fb_intr,
+       .sysmem.flush_page_init = nv50_fb_sysmem_flush_page_init,
        .ram_new = nv50_fb_ram_new,
 };
 
index a5e6738..4f68bc4 100644 (file)
@@ -7,8 +7,6 @@
 struct nv50_fb {
        const struct nv50_fb_func *func;
        struct nvkm_fb base;
-       struct page *r100c08_page;
-       dma_addr_t r100c08;
 };
 
 struct nv50_fb_func {
index 3f1be97..ac03eac 100644 (file)
@@ -16,6 +16,10 @@ struct nvkm_fb_func {
        void (*init_unkn)(struct nvkm_fb *);
        void (*intr)(struct nvkm_fb *);
 
+       struct nvkm_fb_func_sysmem {
+               void (*flush_page_init)(struct nvkm_fb *);
+       } sysmem;
+
        struct {
                bool (*scrub_required)(struct nvkm_fb *);
                int (*scrub)(struct nvkm_fb *);
@@ -37,8 +41,8 @@ struct nvkm_fb_func {
        const struct nvkm_therm_clkgate_pack *clkgate_pack;
 };
 
-void nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device,
-                 enum nvkm_subdev_type type, int inst, struct nvkm_fb *);
+int nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device,
+                enum nvkm_subdev_type type, int inst, struct nvkm_fb *);
 int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device,
                 enum nvkm_subdev_type type, int inst, struct nvkm_fb **);
 int nvkm_fb_bios_memtype(struct nvkm_bios *);
@@ -72,6 +76,7 @@ void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
 
 int gf100_fb_oneinit(struct nvkm_fb *);
 int gf100_fb_init_page(struct nvkm_fb *);
+void gf100_fb_sysmem_flush_page_init(struct nvkm_fb *);
 
 int gm200_fb_init_page(struct nvkm_fb *);