xref: /openbmc/linux/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c (revision 4f727ecefefbd180de10e25b3e74c03dce3f1e75)
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
3  *
4  * Copyright 2019 VMware, Inc., Palo Alto, CA., USA
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 #include "vmwgfx_drv.h"
28 
29 /*
30  * Different methods for tracking dirty:
31  * VMW_BO_DIRTY_PAGETABLE - Scan the pagetable for hardware dirty bits
32  * VMW_BO_DIRTY_MKWRITE - Write-protect page table entries and record write-
33  * accesses in the VM mkwrite() callback
34  */
35 enum vmw_bo_dirty_method {
36 	VMW_BO_DIRTY_PAGETABLE,
37 	VMW_BO_DIRTY_MKWRITE,
38 };
39 
40 /*
41  * No dirtied pages at scan trigger a transition to the _MKWRITE method,
42  * similarly a certain percentage of dirty pages trigger a transition to
43  * the _PAGETABLE method. How many triggers should we wait for before
44  * changing method?
45  */
46 #define VMW_DIRTY_NUM_CHANGE_TRIGGERS 2
47 
48 /* Percentage to trigger a transition to the _PAGETABLE method */
49 #define VMW_DIRTY_PERCENTAGE 10
50 
51 /**
52  * struct vmw_bo_dirty - Dirty information for buffer objects
53  * @start: First currently dirty bit
54  * @end: Last currently dirty bit + 1
55  * @method: The currently used dirty method
56  * @change_count: Number of consecutive method change triggers
57  * @ref_count: Reference count for this structure
58  * @bitmap_size: The size of the bitmap in bits. Typically equal to the
59  * nuber of pages in the bo.
60  * @size: The accounting size for this struct.
61  * @bitmap: A bitmap where each bit represents a page. A set bit means a
62  * dirty page.
63  */
64 struct vmw_bo_dirty {
65 	unsigned long start;
66 	unsigned long end;
67 	enum vmw_bo_dirty_method method;
68 	unsigned int change_count;
69 	unsigned int ref_count;
70 	unsigned long bitmap_size;
71 	size_t size;
72 	unsigned long bitmap[0];
73 };
74 
75 /**
76  * vmw_bo_dirty_scan_pagetable - Perform a pagetable scan for dirty bits
77  * @vbo: The buffer object to scan
78  *
79  * Scans the pagetable for dirty bits. Clear those bits and modify the
80  * dirty structure with the results. This function may change the
81  * dirty-tracking method.
82  */
83 static void vmw_bo_dirty_scan_pagetable(struct vmw_buffer_object *vbo)
84 {
85 	struct vmw_bo_dirty *dirty = vbo->dirty;
86 	pgoff_t offset = drm_vma_node_start(&vbo->base.vma_node);
87 	struct address_space *mapping = vbo->base.bdev->dev_mapping;
88 	pgoff_t num_marked;
89 
90 	num_marked = apply_as_clean(mapping,
91 				    offset, dirty->bitmap_size,
92 				    offset, &dirty->bitmap[0],
93 				    &dirty->start, &dirty->end);
94 	if (num_marked == 0)
95 		dirty->change_count++;
96 	else
97 		dirty->change_count = 0;
98 
99 	if (dirty->change_count > VMW_DIRTY_NUM_CHANGE_TRIGGERS) {
100 		dirty->change_count = 0;
101 		dirty->method = VMW_BO_DIRTY_MKWRITE;
102 		apply_as_wrprotect(mapping,
103 				   offset, dirty->bitmap_size);
104 		apply_as_clean(mapping,
105 			       offset, dirty->bitmap_size,
106 			       offset, &dirty->bitmap[0],
107 			       &dirty->start, &dirty->end);
108 	}
109 }
110 
111 /**
112  * vmw_bo_dirty_scan_mkwrite - Reset the mkwrite dirty-tracking method
113  * @vbo: The buffer object to scan
114  *
115  * Write-protect pages written to so that consecutive write accesses will
116  * trigger a call to mkwrite.
117  *
118  * This function may change the dirty-tracking method.
119  */
120 static void vmw_bo_dirty_scan_mkwrite(struct vmw_buffer_object *vbo)
121 {
122 	struct vmw_bo_dirty *dirty = vbo->dirty;
123 	unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
124 	struct address_space *mapping = vbo->base.bdev->dev_mapping;
125 	pgoff_t num_marked;
126 
127 	if (dirty->end <= dirty->start)
128 		return;
129 
130 	num_marked = apply_as_wrprotect(vbo->base.bdev->dev_mapping,
131 					dirty->start + offset,
132 					dirty->end - dirty->start);
133 
134 	if (100UL * num_marked / dirty->bitmap_size >
135 	    VMW_DIRTY_PERCENTAGE) {
136 		dirty->change_count++;
137 	} else {
138 		dirty->change_count = 0;
139 	}
140 
141 	if (dirty->change_count > VMW_DIRTY_NUM_CHANGE_TRIGGERS) {
142 		pgoff_t start = 0;
143 		pgoff_t end = dirty->bitmap_size;
144 
145 		dirty->method = VMW_BO_DIRTY_PAGETABLE;
146 		apply_as_clean(mapping, offset, end, offset, &dirty->bitmap[0],
147 			       &start, &end);
148 		bitmap_clear(&dirty->bitmap[0], 0, dirty->bitmap_size);
149 		if (dirty->start < dirty->end)
150 			bitmap_set(&dirty->bitmap[0], dirty->start,
151 				   dirty->end - dirty->start);
152 		dirty->change_count = 0;
153 	}
154 }
155 
156 /**
157  * vmw_bo_dirty_scan - Scan for dirty pages and add them to the dirty
158  * tracking structure
159  * @vbo: The buffer object to scan
160  *
161  * This function may change the dirty tracking method.
162  */
163 void vmw_bo_dirty_scan(struct vmw_buffer_object *vbo)
164 {
165 	struct vmw_bo_dirty *dirty = vbo->dirty;
166 
167 	if (dirty->method == VMW_BO_DIRTY_PAGETABLE)
168 		vmw_bo_dirty_scan_pagetable(vbo);
169 	else
170 		vmw_bo_dirty_scan_mkwrite(vbo);
171 }
172 
173 /**
174  * vmw_bo_dirty_pre_unmap - write-protect and pick up dirty pages before
175  * an unmap_mapping_range operation.
176  * @vbo: The buffer object,
177  * @start: First page of the range within the buffer object.
178  * @end: Last page of the range within the buffer object + 1.
179  *
180  * If we're using the _PAGETABLE scan method, we may leak dirty pages
181  * when calling unmap_mapping_range(). This function makes sure we pick
182  * up all dirty pages.
183  */
184 static void vmw_bo_dirty_pre_unmap(struct vmw_buffer_object *vbo,
185 				   pgoff_t start, pgoff_t end)
186 {
187 	struct vmw_bo_dirty *dirty = vbo->dirty;
188 	unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
189 	struct address_space *mapping = vbo->base.bdev->dev_mapping;
190 
191 	if (dirty->method != VMW_BO_DIRTY_PAGETABLE || start >= end)
192 		return;
193 
194 	apply_as_wrprotect(mapping, start + offset, end - start);
195 	apply_as_clean(mapping, start + offset, end - start, offset,
196 		       &dirty->bitmap[0], &dirty->start, &dirty->end);
197 }
198 
199 /**
200  * vmw_bo_dirty_unmap - Clear all ptes pointing to a range within a bo
201  * @vbo: The buffer object,
202  * @start: First page of the range within the buffer object.
203  * @end: Last page of the range within the buffer object + 1.
204  *
205  * This is similar to ttm_bo_unmap_virtual_locked() except it takes a subrange.
206  */
207 void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo,
208 			pgoff_t start, pgoff_t end)
209 {
210 	unsigned long offset = drm_vma_node_start(&vbo->base.vma_node);
211 	struct address_space *mapping = vbo->base.bdev->dev_mapping;
212 
213 	vmw_bo_dirty_pre_unmap(vbo, start, end);
214 	unmap_shared_mapping_range(mapping, (offset + start) << PAGE_SHIFT,
215 				   (loff_t) (end - start) << PAGE_SHIFT);
216 }
217 
218 /**
219  * vmw_bo_dirty_add - Add a dirty-tracking user to a buffer object
220  * @vbo: The buffer object
221  *
222  * This function registers a dirty-tracking user to a buffer object.
223  * A user can be for example a resource or a vma in a special user-space
224  * mapping.
225  *
226  * Return: Zero on success, -ENOMEM on memory allocation failure.
227  */
228 int vmw_bo_dirty_add(struct vmw_buffer_object *vbo)
229 {
230 	struct vmw_bo_dirty *dirty = vbo->dirty;
231 	pgoff_t num_pages = vbo->base.num_pages;
232 	size_t size, acc_size;
233 	int ret;
234 	static struct ttm_operation_ctx ctx = {
235 		.interruptible = false,
236 		.no_wait_gpu = false
237 	};
238 
239 	if (dirty) {
240 		dirty->ref_count++;
241 		return 0;
242 	}
243 
244 	size = sizeof(*dirty) + BITS_TO_LONGS(num_pages) * sizeof(long);
245 	acc_size = ttm_round_pot(size);
246 	ret = ttm_mem_global_alloc(&ttm_mem_glob, acc_size, &ctx);
247 	if (ret) {
248 		VMW_DEBUG_USER("Out of graphics memory for buffer object "
249 			       "dirty tracker.\n");
250 		return ret;
251 	}
252 	dirty = kvzalloc(size, GFP_KERNEL);
253 	if (!dirty) {
254 		ret = -ENOMEM;
255 		goto out_no_dirty;
256 	}
257 
258 	dirty->size = acc_size;
259 	dirty->bitmap_size = num_pages;
260 	dirty->start = dirty->bitmap_size;
261 	dirty->end = 0;
262 	dirty->ref_count = 1;
263 	if (num_pages < PAGE_SIZE / sizeof(pte_t)) {
264 		dirty->method = VMW_BO_DIRTY_PAGETABLE;
265 	} else {
266 		struct address_space *mapping = vbo->base.bdev->dev_mapping;
267 		pgoff_t offset = drm_vma_node_start(&vbo->base.vma_node);
268 
269 		dirty->method = VMW_BO_DIRTY_MKWRITE;
270 
271 		/* Write-protect and then pick up already dirty bits */
272 		apply_as_wrprotect(mapping, offset, num_pages);
273 		apply_as_clean(mapping, offset, num_pages, offset,
274 			       &dirty->bitmap[0], &dirty->start, &dirty->end);
275 	}
276 
277 	vbo->dirty = dirty;
278 
279 	return 0;
280 
281 out_no_dirty:
282 	ttm_mem_global_free(&ttm_mem_glob, acc_size);
283 	return ret;
284 }
285 
286 /**
287  * vmw_bo_dirty_release - Release a dirty-tracking user from a buffer object
288  * @vbo: The buffer object
289  *
290  * This function releases a dirty-tracking user from a buffer object.
291  * If the reference count reaches zero, then the dirty-tracking object is
292  * freed and the pointer to it cleared.
293  *
294  * Return: Zero on success, -ENOMEM on memory allocation failure.
295  */
296 void vmw_bo_dirty_release(struct vmw_buffer_object *vbo)
297 {
298 	struct vmw_bo_dirty *dirty = vbo->dirty;
299 
300 	if (dirty && --dirty->ref_count == 0) {
301 		size_t acc_size = dirty->size;
302 
303 		kvfree(dirty);
304 		ttm_mem_global_free(&ttm_mem_glob, acc_size);
305 		vbo->dirty = NULL;
306 	}
307 }
308 
309 /**
310  * vmw_bo_dirty_transfer_to_res - Pick up a resource's dirty region from
311  * its backing mob.
312  * @res: The resource
313  *
314  * This function will pick up all dirty ranges affecting the resource from
315  * it's backup mob, and call vmw_resource_dirty_update() once for each
316  * range. The transferred ranges will be cleared from the backing mob's
317  * dirty tracking.
318  */
319 void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res)
320 {
321 	struct vmw_buffer_object *vbo = res->backup;
322 	struct vmw_bo_dirty *dirty = vbo->dirty;
323 	pgoff_t start, cur, end;
324 	unsigned long res_start = res->backup_offset;
325 	unsigned long res_end = res->backup_offset + res->backup_size;
326 
327 	WARN_ON_ONCE(res_start & ~PAGE_MASK);
328 	res_start >>= PAGE_SHIFT;
329 	res_end = DIV_ROUND_UP(res_end, PAGE_SIZE);
330 
331 	if (res_start >= dirty->end || res_end <= dirty->start)
332 		return;
333 
334 	cur = max(res_start, dirty->start);
335 	res_end = max(res_end, dirty->end);
336 	while (cur < res_end) {
337 		unsigned long num;
338 
339 		start = find_next_bit(&dirty->bitmap[0], res_end, cur);
340 		if (start >= res_end)
341 			break;
342 
343 		end = find_next_zero_bit(&dirty->bitmap[0], res_end, start + 1);
344 		cur = end + 1;
345 		num = end - start;
346 		bitmap_clear(&dirty->bitmap[0], start, num);
347 		vmw_resource_dirty_update(res, start, end);
348 	}
349 
350 	if (res_start <= dirty->start && res_end > dirty->start)
351 		dirty->start = res_end;
352 	if (res_start < dirty->end && res_end >= dirty->end)
353 		dirty->end = res_start;
354 }
355 
356 /**
357  * vmw_bo_dirty_clear_res - Clear a resource's dirty region from
358  * its backing mob.
359  * @res: The resource
360  *
361  * This function will clear all dirty ranges affecting the resource from
362  * it's backup mob's dirty tracking.
363  */
364 void vmw_bo_dirty_clear_res(struct vmw_resource *res)
365 {
366 	unsigned long res_start = res->backup_offset;
367 	unsigned long res_end = res->backup_offset + res->backup_size;
368 	struct vmw_buffer_object *vbo = res->backup;
369 	struct vmw_bo_dirty *dirty = vbo->dirty;
370 
371 	res_start >>= PAGE_SHIFT;
372 	res_end = DIV_ROUND_UP(res_end, PAGE_SIZE);
373 
374 	if (res_start >= dirty->end || res_end <= dirty->start)
375 		return;
376 
377 	res_start = max(res_start, dirty->start);
378 	res_end = min(res_end, dirty->end);
379 	bitmap_clear(&dirty->bitmap[0], res_start, res_end - res_start);
380 
381 	if (res_start <= dirty->start && res_end > dirty->start)
382 		dirty->start = res_end;
383 	if (res_start < dirty->end && res_end >= dirty->end)
384 		dirty->end = res_start;
385 }
386 
387 vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf)
388 {
389 	struct vm_area_struct *vma = vmf->vma;
390 	struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
391 	    vma->vm_private_data;
392 	vm_fault_t ret;
393 	unsigned long page_offset;
394 	struct vmw_buffer_object *vbo =
395 		container_of(bo, typeof(*vbo), base);
396 
397 	ret = ttm_bo_vm_reserve(bo, vmf);
398 	if (ret)
399 		return ret;
400 
401 	page_offset = vmf->pgoff - drm_vma_node_start(&bo->vma_node);
402 	if (unlikely(page_offset >= bo->num_pages)) {
403 		ret = VM_FAULT_SIGBUS;
404 		goto out_unlock;
405 	}
406 
407 	if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE &&
408 	    !test_bit(page_offset, &vbo->dirty->bitmap[0])) {
409 		struct vmw_bo_dirty *dirty = vbo->dirty;
410 
411 		__set_bit(page_offset, &dirty->bitmap[0]);
412 		dirty->start = min(dirty->start, page_offset);
413 		dirty->end = max(dirty->end, page_offset + 1);
414 	}
415 
416 out_unlock:
417 	reservation_object_unlock(bo->resv);
418 	return ret;
419 }
420 
421 vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
422 {
423 	struct vm_area_struct *vma = vmf->vma;
424 	struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
425 	    vma->vm_private_data;
426 	struct vmw_buffer_object *vbo =
427 		container_of(bo, struct vmw_buffer_object, base);
428 	pgoff_t num_prefault;
429 	pgprot_t prot;
430 	vm_fault_t ret;
431 
432 	ret = ttm_bo_vm_reserve(bo, vmf);
433 	if (ret)
434 		return ret;
435 
436 	num_prefault = (vma->vm_flags & VM_RAND_READ) ? 1 :
437 		TTM_BO_VM_NUM_PREFAULT;
438 
439 	if (vbo->dirty) {
440 		pgoff_t allowed_prefault;
441 		unsigned long page_offset;
442 
443 		page_offset = vmf->pgoff - drm_vma_node_start(&bo->vma_node);
444 		if (page_offset >= bo->num_pages ||
445 		    vmw_resources_clean(vbo, page_offset,
446 					page_offset + PAGE_SIZE,
447 					&allowed_prefault)) {
448 			ret = VM_FAULT_SIGBUS;
449 			goto out_unlock;
450 		}
451 
452 		num_prefault = min(num_prefault, allowed_prefault);
453 	}
454 
455 	/*
456 	 * If we don't track dirty using the MKWRITE method, make sure
457 	 * sure the page protection is write-enabled so we don't get
458 	 * a lot of unnecessary write faults.
459 	 */
460 	if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE)
461 		prot = vma->vm_page_prot;
462 	else
463 		prot = vm_get_page_prot(vma->vm_flags);
464 
465 	ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault);
466 	if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
467 		return ret;
468 
469 out_unlock:
470 	reservation_object_unlock(bo->resv);
471 	return ret;
472 }
473