summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
index 6faaea948fc4..bac7dcc4c2c1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
@@ -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)
{
@@ -125,12 +134,20 @@ nvkm_fb_oneinit(struct nvkm_subdev *subdev)
return nvkm_mm_init(&fb->tags.mm, 0, 0, tags, 1);
}
-static int
-nvkm_fb_init_scrub_vpr(struct nvkm_fb *fb)
+int
+nvkm_fb_mem_unlock(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
int ret;
+ if (!fb->func->vpr.scrub_required)
+ return 0;
+
+ if (!fb->func->vpr.scrub_required(fb)) {
+ nvkm_debug(subdev, "VPR not locked\n");
+ return 0;
+ }
+
nvkm_debug(subdev, "VPR locked, running scrubber binary\n");
if (!fb->vpr_scrubber.size) {
@@ -168,6 +185,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);
@@ -183,13 +202,13 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
if (fb->func->init_unkn)
fb->func->init_unkn(fb);
- if (fb->func->vpr.scrub_required &&
- fb->func->vpr.scrub_required(fb)) {
- ret = nvkm_fb_init_scrub_vpr(fb);
- if (ret)
- return ret;
- }
+ return 0;
+}
+static int
+nvkm_fb_preinit(struct nvkm_subdev *subdev)
+{
+ nvkm_fb_sysmem_flush_page_init(subdev->device);
return 0;
}
@@ -212,20 +231,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 +261,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 +282,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);
}