drm/nouveau: synchronize BOs when required
authorAlexandre Courbot <acourbot@nvidia.com>
Mon, 27 Oct 2014 09:49:19 +0000 (18:49 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 2 Dec 2014 05:44:00 +0000 (15:44 +1000)
On architectures for which access to GPU memory is non-coherent,
caches need to be flushed and invalidated explicitly when BO control
changes between CPU and GPU.

This patch adds buffer synchronization functions which invokes the
correct API (PCI or DMA) to ensure synchronization is effective.

Based on the TTM DMA cache helper patches by Lucas Stach.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_gem.c

index ed9a6946f6d65c79e8d526b96f286ab1e23d1256..d2a4768e3efd67fe7a1484832c74a3b35fddf8c8 100644 (file)
@@ -426,6 +426,46 @@ nouveau_bo_unmap(struct nouveau_bo *nvbo)
                ttm_bo_kunmap(&nvbo->kmap);
 }
 
+void
+nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
+       struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
+       int i;
+
+       if (!ttm_dma)
+               return;
+
+       /* Don't waste time looping if the object is coherent */
+       if (nvbo->force_coherent)
+               return;
+
+       for (i = 0; i < ttm_dma->ttm.num_pages; i++)
+               dma_sync_single_for_device(nv_device_base(device),
+                       ttm_dma->dma_address[i], PAGE_SIZE, DMA_TO_DEVICE);
+}
+
+void
+nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
+       struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
+       int i;
+
+       if (!ttm_dma)
+               return;
+
+       /* Don't waste time looping if the object is coherent */
+       if (nvbo->force_coherent)
+               return;
+
+       for (i = 0; i < ttm_dma->ttm.num_pages; i++)
+               dma_sync_single_for_cpu(nv_device_base(device),
+                       ttm_dma->dma_address[i], PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
 int
 nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
                    bool no_wait_gpu)
@@ -437,6 +477,8 @@ nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
        if (ret)
                return ret;
 
+       nouveau_bo_sync_for_device(nvbo);
+
        return 0;
 }
 
index 0f8bbd48a0b9a9579ebc158f522eea24b2609b4c..c827f233e41deb1ddd9553ec2b32791f12c94260 100644 (file)
@@ -85,6 +85,8 @@ void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val);
 void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *, bool exclusive);
 int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
                         bool no_wait_gpu);
+void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
+void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
 
 struct nouveau_vma *
 nouveau_bo_vma_find(struct nouveau_bo *, struct nouveau_vm *);
index ebba9deb0d04c572f9a09e76fcc4cbe1af955258..28d51a22a4bf18b5729f8f4e9cd159c830cbbfca 100644 (file)
@@ -870,6 +870,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
                else
                        ret = lret;
        }
+       nouveau_bo_sync_for_cpu(nvbo);
        drm_gem_object_unreference_unlocked(gem);
 
        return ret;
@@ -879,6 +880,17 @@ int
 nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
                           struct drm_file *file_priv)
 {
+       struct drm_nouveau_gem_cpu_fini *req = data;
+       struct drm_gem_object *gem;
+       struct nouveau_bo *nvbo;
+
+       gem = drm_gem_object_lookup(dev, file_priv, req->handle);
+       if (!gem)
+               return -ENOENT;
+       nvbo = nouveau_gem_object(gem);
+
+       nouveau_bo_sync_for_device(nvbo);
+       drm_gem_object_unreference_unlocked(gem);
        return 0;
 }