drm/nouveau/kms/nv50-: allocate push buffers in vidmem on pascal
authorBen Skeggs <bskeggs@redhat.com>
Tue, 17 Jul 2018 23:33:39 +0000 (09:33 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 19 Jul 2018 04:38:09 +0000 (14:38 +1000)
Workaround for issues seen on systems with large amounts of RAM, caused
by display not supporting the same physical address limits as the other
parts of the GPU.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/dispnv50/disp.c

index 7d00d833bbe5aae666ccda2baeeda657028526ee..4a372f805eb91774c0c5563c84f47621927f8485 100644 (file)
@@ -136,12 +136,24 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
 {
        struct nouveau_cli *cli = (void *)device->object.client;
        struct nv50_disp_core_channel_dma_v0 *args = data;
+       u8 type = NVIF_MEM_COHERENT;
        int ret;
 
        mutex_init(&dmac->lock);
 
-       ret = nvif_mem_init_map(&cli->mmu, NVIF_MEM_COHERENT, 0x1000,
-                               &dmac->push);
+       /* Pascal added support for 47-bit physical addresses, but some
+        * parts of EVO still only accept 40-bit PAs.
+        *
+        * To avoid issues on systems with large amounts of RAM, and on
+        * systems where an IOMMU maps pages at a high address, we need
+        * to allocate push buffers in VRAM instead.
+        *
+        * This appears to match NVIDIA's behaviour on Pascal.
+        */
+       if (device->info.family == NV_DEVICE_INFO_V0_PASCAL)
+               type |= NVIF_MEM_VRAM;
+
+       ret = nvif_mem_init_map(&cli->mmu, type, 0x1000, &dmac->push);
        if (ret)
                return ret;
 
@@ -216,6 +228,19 @@ void
 evo_kick(u32 *push, struct nv50_dmac *evoc)
 {
        struct nv50_dmac *dmac = evoc;
+
+       /* Push buffer fetches are not coherent with BAR1, we need to ensure
+        * writes have been flushed right through to VRAM before writing PUT.
+        */
+       if (dmac->push.type & NVIF_MEM_VRAM) {
+               struct nvif_device *device = dmac->base.device;
+               nvif_wr32(&device->object, 0x070000, 0x00000001);
+               nvif_msec(device, 2000,
+                       if (!(nvif_rd32(&device->object, 0x070000) & 0x00000002))
+                               break;
+               );
+       }
+
        nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
        mutex_unlock(&dmac->lock);
 }