1 // SPDX-License-Identifier: GPL-2.0
2 #include "virtgpu_drv.h"
3
4 #include <linux/dma-mapping.h>
5
6 static DEFINE_MUTEX(map_lock);
7
virtio_gpu_vram_free(struct drm_gem_object * obj)8 static void virtio_gpu_vram_free(struct drm_gem_object *obj)
9 {
10 struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
11 struct virtio_gpu_device *vgdev = obj->dev->dev_private;
12 struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
13 bool unmap;
14
15 if (bo->created) {
16 spin_lock(&vgdev->host_visible_lock);
17 unmap = drm_mm_node_allocated(&vram->vram_node);
18 spin_unlock(&vgdev->host_visible_lock);
19
20 if (unmap)
21 virtio_gpu_cmd_unmap(vgdev, bo);
22
23 virtio_gpu_remove_from_restore_list(bo);
24 virtio_gpu_cmd_unref_resource(vgdev, bo, false);
25 virtio_gpu_notify(vgdev);
26 return;
27 }
28 }
29
30 static const struct vm_operations_struct virtio_gpu_vram_vm_ops = {
31 .open = drm_gem_vm_open,
32 .close = drm_gem_vm_close,
33 };
34
virtio_gpu_vram_mmap(struct drm_gem_object * obj,struct vm_area_struct * vma)35 static int virtio_gpu_vram_mmap(struct drm_gem_object *obj,
36 struct vm_area_struct *vma)
37 {
38 int ret;
39 struct virtio_gpu_device *vgdev = obj->dev->dev_private;
40 struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
41 struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
42 unsigned long vm_size = vma->vm_end - vma->vm_start;
43 unsigned long vm_end;
44
45 if (!(bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE))
46 return -EINVAL;
47
48 virtio_gpu_vram_map_deferred(vram);
49
50 if (vram->map_state == STATE_INITIALIZING)
51 virtio_gpu_notify(vgdev);
52
53 wait_event(vgdev->resp_wq, vram->map_state != STATE_INITIALIZING);
54 if (vram->map_state != STATE_OK)
55 return -EINVAL;
56
57 vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
58 vm_flags_set(vma, VM_MIXEDMAP | VM_DONTEXPAND);
59 vma->vm_page_prot = vma_get_page_prot(vma);
60 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
61 vma->vm_ops = &virtio_gpu_vram_vm_ops;
62
63 if (vram->map_info == VIRTIO_GPU_MAP_CACHE_WC)
64 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
65 else if (vram->map_info == VIRTIO_GPU_MAP_CACHE_UNCACHED)
66 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
67
68 if (check_add_overflow(vma->vm_pgoff << PAGE_SHIFT, vm_size, &vm_end))
69 return -EINVAL;
70
71 if (vm_end > vram->vram_node.size)
72 return -EINVAL;
73
74 ret = io_remap_pfn_range(vma, vma->vm_start,
75 (vram->vram_node.start >> PAGE_SHIFT) + vma->vm_pgoff,
76 vm_size, vma->vm_page_prot);
77 return ret;
78 }
79
virtio_gpu_vram_map_dma_buf(struct virtio_gpu_object * bo,struct device * dev,enum dma_data_direction dir)80 struct sg_table *virtio_gpu_vram_map_dma_buf(struct virtio_gpu_object *bo,
81 struct device *dev,
82 enum dma_data_direction dir)
83 {
84 struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
85 struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
86 struct sg_table *sgt;
87 dma_addr_t addr;
88 int ret;
89
90 sgt = kzalloc_obj(*sgt);
91 if (!sgt)
92 return ERR_PTR(-ENOMEM);
93
94 if (!(bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) {
95 // Virtio devices can access the dma-buf via its UUID. Return a stub
96 // sg_table so the dma-buf API still works.
97 if (!is_virtio_device(dev) || !vgdev->has_resource_assign_uuid) {
98 ret = -EIO;
99 goto out;
100 }
101 return sgt;
102 }
103
104 ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
105 if (ret)
106 goto out;
107
108 addr = dma_map_resource(dev, vram->vram_node.start,
109 vram->vram_node.size, dir,
110 DMA_ATTR_SKIP_CPU_SYNC);
111 ret = dma_mapping_error(dev, addr);
112 if (ret)
113 goto out;
114
115 sg_set_page(sgt->sgl, NULL, vram->vram_node.size, 0);
116 sg_dma_address(sgt->sgl) = addr;
117 sg_dma_len(sgt->sgl) = vram->vram_node.size;
118
119 return sgt;
120 out:
121 sg_free_table(sgt);
122 kfree(sgt);
123 return ERR_PTR(ret);
124 }
125
virtio_gpu_vram_unmap_dma_buf(struct device * dev,struct sg_table * sgt,enum dma_data_direction dir)126 void virtio_gpu_vram_unmap_dma_buf(struct device *dev,
127 struct sg_table *sgt,
128 enum dma_data_direction dir)
129 {
130 if (sgt->nents) {
131 dma_unmap_resource(dev, sg_dma_address(sgt->sgl),
132 sg_dma_len(sgt->sgl), dir,
133 DMA_ATTR_SKIP_CPU_SYNC);
134 }
135 sg_free_table(sgt);
136 kfree(sgt);
137 }
138
139 static const struct drm_gem_object_funcs virtio_gpu_vram_funcs = {
140 .open = virtio_gpu_gem_object_open,
141 .close = virtio_gpu_gem_object_close,
142 .free = virtio_gpu_vram_free,
143 .mmap = virtio_gpu_vram_mmap,
144 .export = virtgpu_gem_prime_export,
145 };
146
virtio_gpu_is_vram(struct virtio_gpu_object * bo)147 bool virtio_gpu_is_vram(struct virtio_gpu_object *bo)
148 {
149 return bo->base.base.funcs == &virtio_gpu_vram_funcs;
150 }
151
virtio_gpu_vram_map(struct virtio_gpu_object * bo)152 static int virtio_gpu_vram_map(struct virtio_gpu_object *bo)
153 {
154 int ret;
155 uint64_t offset;
156 struct virtio_gpu_object_array *objs;
157 struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
158 struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo);
159
160 if (!vgdev->has_host_visible)
161 return -EINVAL;
162
163 spin_lock(&vgdev->host_visible_lock);
164 ret = drm_mm_insert_node(&vgdev->host_visible_mm, &vram->vram_node,
165 bo->base.base.size);
166 spin_unlock(&vgdev->host_visible_lock);
167
168 if (ret)
169 return ret;
170
171 objs = virtio_gpu_array_alloc(1);
172 if (!objs) {
173 ret = -ENOMEM;
174 goto err_remove_node;
175 }
176
177 virtio_gpu_array_add_obj(objs, &bo->base.base);
178 /*TODO: Add an error checking helper function in drm_mm.h */
179 offset = vram->vram_node.start - vgdev->host_visible_region.addr;
180
181 ret = virtio_gpu_cmd_map(vgdev, objs, offset);
182 if (ret) {
183 virtio_gpu_array_put_free(objs);
184 goto err_remove_node;
185 }
186
187 return 0;
188
189 err_remove_node:
190 spin_lock(&vgdev->host_visible_lock);
191 drm_mm_remove_node(&vram->vram_node);
192 spin_unlock(&vgdev->host_visible_lock);
193 return ret;
194 }
195
virtio_gpu_vram_create(struct virtio_gpu_device * vgdev,struct virtio_gpu_object_params * params,struct virtio_gpu_object ** bo_ptr)196 int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev,
197 struct virtio_gpu_object_params *params,
198 struct virtio_gpu_object **bo_ptr)
199 {
200 struct drm_gem_object *obj;
201 struct virtio_gpu_object_vram *vram;
202 int ret;
203
204 vram = kzalloc_obj(*vram);
205 if (!vram)
206 return -ENOMEM;
207
208 obj = &vram->base.base.base;
209 obj->funcs = &virtio_gpu_vram_funcs;
210
211 INIT_LIST_HEAD(&vram->base.restore_node);
212
213 params->size = PAGE_ALIGN(params->size);
214 drm_gem_private_object_init(vgdev->ddev, obj, params->size);
215
216 /* Create fake offset */
217 ret = drm_gem_create_mmap_offset(obj);
218 if (ret)
219 goto err_release_obj;
220
221 ret = virtio_gpu_resource_id_get(vgdev, &vram->base.hw_res_handle);
222 if (ret)
223 goto err_release_obj;
224
225 virtio_gpu_cmd_resource_create_blob(vgdev, &vram->base, params, NULL,
226 0);
227 if (!(params->blob_hints & DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING)) {
228 if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) {
229 ret = virtio_gpu_vram_map(&vram->base);
230 if (ret) {
231 virtio_gpu_vram_free(obj);
232 return ret;
233 }
234 }
235 }
236
237 *bo_ptr = &vram->base;
238 return 0;
239
240 err_release_obj:
241 drm_gem_object_release(obj);
242 kfree(vram);
243 return ret;
244 }
245
virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram * vram)246 void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram)
247 {
248 if (!(vram->base.blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE))
249 return;
250
251 mutex_lock(&map_lock);
252 if (!drm_mm_node_allocated(&vram->vram_node))
253 virtio_gpu_vram_map(&vram->base);
254 mutex_unlock(&map_lock);
255 }
256