drm/virtio: add iommu support.
authorGerd Hoffmann <kraxel@redhat.com>
Wed, 29 Aug 2018 12:20:26 +0000 (14:20 +0200)
committerGerd Hoffmann <kraxel@redhat.com>
Wed, 5 Sep 2018 06:26:26 +0000 (08:26 +0200)
Use the dma mapping api and properly add iommu mappings for
objects, unless virtio is in iommu quirk mode.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20180829122026.27012-3-kraxel@redhat.com
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_vq.c

index 4fda0da..f8f4a40 100644 (file)
@@ -57,6 +57,7 @@ struct virtio_gpu_object {
        uint32_t hw_res_handle;
 
        struct sg_table *pages;
+       uint32_t mapped;
        void *vmap;
        bool dumb;
        struct ttm_place                placement_code;
index e23c192..5784c3e 100644 (file)
@@ -424,7 +424,8 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
 }
 
 static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
-                                                 uint32_t resource_id)
+                                                 uint32_t resource_id,
+                                                 struct virtio_gpu_fence **fence)
 {
        struct virtio_gpu_resource_detach_backing *cmd_p;
        struct virtio_gpu_vbuffer *vbuf;
@@ -435,7 +436,7 @@ static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgde
        cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING);
        cmd_p->resource_id = cpu_to_le32(resource_id);
 
-       virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
 }
 
 void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
@@ -849,9 +850,10 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
                             uint32_t resource_id,
                             struct virtio_gpu_fence **fence)
 {
+       bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
        struct virtio_gpu_mem_entry *ents;
        struct scatterlist *sg;
-       int si;
+       int si, nents;
 
        if (!obj->pages) {
                int ret;
@@ -861,23 +863,33 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
                        return ret;
        }
 
+       if (use_dma_api) {
+               obj->mapped = dma_map_sg(vgdev->vdev->dev.parent,
+                                        obj->pages->sgl, obj->pages->nents,
+                                        DMA_TO_DEVICE);
+               nents = obj->mapped;
+       } else {
+               nents = obj->pages->nents;
+       }
+
        /* gets freed when the ring has consumed it */
-       ents = kmalloc_array(obj->pages->nents,
-                            sizeof(struct virtio_gpu_mem_entry),
+       ents = kmalloc_array(nents, sizeof(struct virtio_gpu_mem_entry),
                             GFP_KERNEL);
        if (!ents) {
                DRM_ERROR("failed to allocate ent list\n");
                return -ENOMEM;
        }
 
-       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, si) {
-               ents[si].addr = cpu_to_le64(sg_phys(sg));
+       for_each_sg(obj->pages->sgl, sg, nents, si) {
+               ents[si].addr = cpu_to_le64(use_dma_api
+                                           ? sg_dma_address(sg)
+                                           : sg_phys(sg));
                ents[si].length = cpu_to_le32(sg->length);
                ents[si].padding = 0;
        }
 
        virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id,
-                                              ents, obj->pages->nents,
+                                              ents, nents,
                                               fence);
        obj->hw_res_handle = resource_id;
        return 0;
@@ -886,7 +898,23 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
 void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
                              struct virtio_gpu_object *obj)
 {
-       virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle);
+       bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
+       struct virtio_gpu_fence *fence;
+
+       if (use_dma_api && obj->mapped) {
+               /* detach backing and wait for the host process it ... */
+               virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence);
+               dma_fence_wait(&fence->f, true);
+               dma_fence_put(&fence->f);
+
+               /* ... then tear down iommu mappings */
+               dma_unmap_sg(vgdev->vdev->dev.parent,
+                            obj->pages->sgl, obj->mapped,
+                            DMA_TO_DEVICE);
+               obj->mapped = 0;
+       } else {
+               virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, NULL);
+       }
 }
 
 void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,