xref: /openbmc/linux/drivers/gpu/drm/vc4/vc4_bo.c (revision 5a244f48)
1 /*
2  *  Copyright © 2015 Broadcom
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 
9 /**
10  * DOC: VC4 GEM BO management support
11  *
12  * The VC4 GPU architecture (both scanout and rendering) has direct
13  * access to system memory with no MMU in between.  To support it, we
14  * use the GEM CMA helper functions to allocate contiguous ranges of
15  * physical memory for our BOs.
16  *
17  * Since the CMA allocator is very slow, we keep a cache of recently
18  * freed BOs around so that the kernel's allocation of objects for 3D
19  * rendering can return quickly.
20  */
21 
22 #include <linux/dma-buf.h>
23 
24 #include "vc4_drv.h"
25 #include "uapi/drm/vc4_drm.h"
26 
27 static const char * const bo_type_names[] = {
28 	"kernel",
29 	"V3D",
30 	"V3D shader",
31 	"dumb",
32 	"binner",
33 	"RCL",
34 	"BCL",
35 	"kernel BO cache",
36 };
37 
38 static bool is_user_label(int label)
39 {
40 	return label >= VC4_BO_TYPE_COUNT;
41 }
42 
43 static void vc4_bo_stats_dump(struct vc4_dev *vc4)
44 {
45 	int i;
46 
47 	for (i = 0; i < vc4->num_labels; i++) {
48 		if (!vc4->bo_labels[i].num_allocated)
49 			continue;
50 
51 		DRM_INFO("%30s: %6dkb BOs (%d)\n",
52 			 vc4->bo_labels[i].name,
53 			 vc4->bo_labels[i].size_allocated / 1024,
54 			 vc4->bo_labels[i].num_allocated);
55 	}
56 }
57 
58 #ifdef CONFIG_DEBUG_FS
59 int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
60 {
61 	struct drm_info_node *node = (struct drm_info_node *)m->private;
62 	struct drm_device *dev = node->minor->dev;
63 	struct vc4_dev *vc4 = to_vc4_dev(dev);
64 	int i;
65 
66 	mutex_lock(&vc4->bo_lock);
67 	for (i = 0; i < vc4->num_labels; i++) {
68 		if (!vc4->bo_labels[i].num_allocated)
69 			continue;
70 
71 		seq_printf(m, "%30s: %6dkb BOs (%d)\n",
72 			   vc4->bo_labels[i].name,
73 			   vc4->bo_labels[i].size_allocated / 1024,
74 			   vc4->bo_labels[i].num_allocated);
75 	}
76 	mutex_unlock(&vc4->bo_lock);
77 
78 	return 0;
79 }
80 #endif
81 
82 /* Takes ownership of *name and returns the appropriate slot for it in
83  * the bo_labels[] array, extending it as necessary.
84  *
85  * This is inefficient and could use a hash table instead of walking
86  * an array and strcmp()ing.  However, the assumption is that user
87  * labeling will be infrequent (scanout buffers and other long-lived
88  * objects, or debug driver builds), so we can live with it for now.
89  */
90 static int vc4_get_user_label(struct vc4_dev *vc4, const char *name)
91 {
92 	int i;
93 	int free_slot = -1;
94 
95 	for (i = 0; i < vc4->num_labels; i++) {
96 		if (!vc4->bo_labels[i].name) {
97 			free_slot = i;
98 		} else if (strcmp(vc4->bo_labels[i].name, name) == 0) {
99 			kfree(name);
100 			return i;
101 		}
102 	}
103 
104 	if (free_slot != -1) {
105 		WARN_ON(vc4->bo_labels[free_slot].num_allocated != 0);
106 		vc4->bo_labels[free_slot].name = name;
107 		return free_slot;
108 	} else {
109 		u32 new_label_count = vc4->num_labels + 1;
110 		struct vc4_label *new_labels =
111 			krealloc(vc4->bo_labels,
112 				 new_label_count * sizeof(*new_labels),
113 				 GFP_KERNEL);
114 
115 		if (!new_labels) {
116 			kfree(name);
117 			return -1;
118 		}
119 
120 		free_slot = vc4->num_labels;
121 		vc4->bo_labels = new_labels;
122 		vc4->num_labels = new_label_count;
123 
124 		vc4->bo_labels[free_slot].name = name;
125 		vc4->bo_labels[free_slot].num_allocated = 0;
126 		vc4->bo_labels[free_slot].size_allocated = 0;
127 
128 		return free_slot;
129 	}
130 }
131 
132 static void vc4_bo_set_label(struct drm_gem_object *gem_obj, int label)
133 {
134 	struct vc4_bo *bo = to_vc4_bo(gem_obj);
135 	struct vc4_dev *vc4 = to_vc4_dev(gem_obj->dev);
136 
137 	lockdep_assert_held(&vc4->bo_lock);
138 
139 	if (label != -1) {
140 		vc4->bo_labels[label].num_allocated++;
141 		vc4->bo_labels[label].size_allocated += gem_obj->size;
142 	}
143 
144 	vc4->bo_labels[bo->label].num_allocated--;
145 	vc4->bo_labels[bo->label].size_allocated -= gem_obj->size;
146 
147 	if (vc4->bo_labels[bo->label].num_allocated == 0 &&
148 	    is_user_label(bo->label)) {
149 		/* Free user BO label slots on last unreference.
150 		 * Slots are just where we track the stats for a given
151 		 * name, and once a name is unused we can reuse that
152 		 * slot.
153 		 */
154 		kfree(vc4->bo_labels[bo->label].name);
155 		vc4->bo_labels[bo->label].name = NULL;
156 	}
157 
158 	bo->label = label;
159 }
160 
161 static uint32_t bo_page_index(size_t size)
162 {
163 	return (size / PAGE_SIZE) - 1;
164 }
165 
166 static void vc4_bo_destroy(struct vc4_bo *bo)
167 {
168 	struct drm_gem_object *obj = &bo->base.base;
169 	struct vc4_dev *vc4 = to_vc4_dev(obj->dev);
170 
171 	lockdep_assert_held(&vc4->bo_lock);
172 
173 	vc4_bo_set_label(obj, -1);
174 
175 	if (bo->validated_shader) {
176 		kfree(bo->validated_shader->texture_samples);
177 		kfree(bo->validated_shader);
178 		bo->validated_shader = NULL;
179 	}
180 
181 	reservation_object_fini(&bo->_resv);
182 
183 	drm_gem_cma_free_object(obj);
184 }
185 
186 static void vc4_bo_remove_from_cache(struct vc4_bo *bo)
187 {
188 	struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
189 
190 	lockdep_assert_held(&vc4->bo_lock);
191 	list_del(&bo->unref_head);
192 	list_del(&bo->size_head);
193 }
194 
195 static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
196 						     size_t size)
197 {
198 	struct vc4_dev *vc4 = to_vc4_dev(dev);
199 	uint32_t page_index = bo_page_index(size);
200 
201 	if (vc4->bo_cache.size_list_size <= page_index) {
202 		uint32_t new_size = max(vc4->bo_cache.size_list_size * 2,
203 					page_index + 1);
204 		struct list_head *new_list;
205 		uint32_t i;
206 
207 		new_list = kmalloc_array(new_size, sizeof(struct list_head),
208 					 GFP_KERNEL);
209 		if (!new_list)
210 			return NULL;
211 
212 		/* Rebase the old cached BO lists to their new list
213 		 * head locations.
214 		 */
215 		for (i = 0; i < vc4->bo_cache.size_list_size; i++) {
216 			struct list_head *old_list =
217 				&vc4->bo_cache.size_list[i];
218 
219 			if (list_empty(old_list))
220 				INIT_LIST_HEAD(&new_list[i]);
221 			else
222 				list_replace(old_list, &new_list[i]);
223 		}
224 		/* And initialize the brand new BO list heads. */
225 		for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
226 			INIT_LIST_HEAD(&new_list[i]);
227 
228 		kfree(vc4->bo_cache.size_list);
229 		vc4->bo_cache.size_list = new_list;
230 		vc4->bo_cache.size_list_size = new_size;
231 	}
232 
233 	return &vc4->bo_cache.size_list[page_index];
234 }
235 
236 static void vc4_bo_cache_purge(struct drm_device *dev)
237 {
238 	struct vc4_dev *vc4 = to_vc4_dev(dev);
239 
240 	mutex_lock(&vc4->bo_lock);
241 	while (!list_empty(&vc4->bo_cache.time_list)) {
242 		struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
243 						    struct vc4_bo, unref_head);
244 		vc4_bo_remove_from_cache(bo);
245 		vc4_bo_destroy(bo);
246 	}
247 	mutex_unlock(&vc4->bo_lock);
248 }
249 
250 static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
251 					    uint32_t size,
252 					    enum vc4_kernel_bo_type type)
253 {
254 	struct vc4_dev *vc4 = to_vc4_dev(dev);
255 	uint32_t page_index = bo_page_index(size);
256 	struct vc4_bo *bo = NULL;
257 
258 	size = roundup(size, PAGE_SIZE);
259 
260 	mutex_lock(&vc4->bo_lock);
261 	if (page_index >= vc4->bo_cache.size_list_size)
262 		goto out;
263 
264 	if (list_empty(&vc4->bo_cache.size_list[page_index]))
265 		goto out;
266 
267 	bo = list_first_entry(&vc4->bo_cache.size_list[page_index],
268 			      struct vc4_bo, size_head);
269 	vc4_bo_remove_from_cache(bo);
270 	kref_init(&bo->base.base.refcount);
271 
272 out:
273 	if (bo)
274 		vc4_bo_set_label(&bo->base.base, type);
275 	mutex_unlock(&vc4->bo_lock);
276 	return bo;
277 }
278 
279 /**
280  * vc4_gem_create_object - Implementation of driver->gem_create_object.
281  * @dev: DRM device
282  * @size: Size in bytes of the memory the object will reference
283  *
284  * This lets the CMA helpers allocate object structs for us, and keep
285  * our BO stats correct.
286  */
287 struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
288 {
289 	struct vc4_dev *vc4 = to_vc4_dev(dev);
290 	struct vc4_bo *bo;
291 
292 	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
293 	if (!bo)
294 		return ERR_PTR(-ENOMEM);
295 
296 	mutex_lock(&vc4->bo_lock);
297 	bo->label = VC4_BO_TYPE_KERNEL;
298 	vc4->bo_labels[VC4_BO_TYPE_KERNEL].num_allocated++;
299 	vc4->bo_labels[VC4_BO_TYPE_KERNEL].size_allocated += size;
300 	mutex_unlock(&vc4->bo_lock);
301 	bo->resv = &bo->_resv;
302 	reservation_object_init(bo->resv);
303 
304 	return &bo->base.base;
305 }
306 
307 struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
308 			     bool allow_unzeroed, enum vc4_kernel_bo_type type)
309 {
310 	size_t size = roundup(unaligned_size, PAGE_SIZE);
311 	struct vc4_dev *vc4 = to_vc4_dev(dev);
312 	struct drm_gem_cma_object *cma_obj;
313 	struct vc4_bo *bo;
314 
315 	if (size == 0)
316 		return ERR_PTR(-EINVAL);
317 
318 	/* First, try to get a vc4_bo from the kernel BO cache. */
319 	bo = vc4_bo_get_from_cache(dev, size, type);
320 	if (bo) {
321 		if (!allow_unzeroed)
322 			memset(bo->base.vaddr, 0, bo->base.base.size);
323 		return bo;
324 	}
325 
326 	cma_obj = drm_gem_cma_create(dev, size);
327 	if (IS_ERR(cma_obj)) {
328 		/*
329 		 * If we've run out of CMA memory, kill the cache of
330 		 * CMA allocations we've got laying around and try again.
331 		 */
332 		vc4_bo_cache_purge(dev);
333 
334 		cma_obj = drm_gem_cma_create(dev, size);
335 		if (IS_ERR(cma_obj)) {
336 			DRM_ERROR("Failed to allocate from CMA:\n");
337 			vc4_bo_stats_dump(vc4);
338 			return ERR_PTR(-ENOMEM);
339 		}
340 	}
341 	bo = to_vc4_bo(&cma_obj->base);
342 
343 	mutex_lock(&vc4->bo_lock);
344 	vc4_bo_set_label(&cma_obj->base, type);
345 	mutex_unlock(&vc4->bo_lock);
346 
347 	return bo;
348 }
349 
350 int vc4_dumb_create(struct drm_file *file_priv,
351 		    struct drm_device *dev,
352 		    struct drm_mode_create_dumb *args)
353 {
354 	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
355 	struct vc4_bo *bo = NULL;
356 	int ret;
357 
358 	if (args->pitch < min_pitch)
359 		args->pitch = min_pitch;
360 
361 	if (args->size < args->pitch * args->height)
362 		args->size = args->pitch * args->height;
363 
364 	bo = vc4_bo_create(dev, args->size, false, VC4_BO_TYPE_DUMB);
365 	if (IS_ERR(bo))
366 		return PTR_ERR(bo);
367 
368 	ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
369 	drm_gem_object_put_unlocked(&bo->base.base);
370 
371 	return ret;
372 }
373 
374 static void vc4_bo_cache_free_old(struct drm_device *dev)
375 {
376 	struct vc4_dev *vc4 = to_vc4_dev(dev);
377 	unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
378 
379 	lockdep_assert_held(&vc4->bo_lock);
380 
381 	while (!list_empty(&vc4->bo_cache.time_list)) {
382 		struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
383 						    struct vc4_bo, unref_head);
384 		if (time_before(expire_time, bo->free_time)) {
385 			mod_timer(&vc4->bo_cache.time_timer,
386 				  round_jiffies_up(jiffies +
387 						   msecs_to_jiffies(1000)));
388 			return;
389 		}
390 
391 		vc4_bo_remove_from_cache(bo);
392 		vc4_bo_destroy(bo);
393 	}
394 }
395 
396 /* Called on the last userspace/kernel unreference of the BO.  Returns
397  * it to the BO cache if possible, otherwise frees it.
398  */
399 void vc4_free_object(struct drm_gem_object *gem_bo)
400 {
401 	struct drm_device *dev = gem_bo->dev;
402 	struct vc4_dev *vc4 = to_vc4_dev(dev);
403 	struct vc4_bo *bo = to_vc4_bo(gem_bo);
404 	struct list_head *cache_list;
405 
406 	mutex_lock(&vc4->bo_lock);
407 	/* If the object references someone else's memory, we can't cache it.
408 	 */
409 	if (gem_bo->import_attach) {
410 		vc4_bo_destroy(bo);
411 		goto out;
412 	}
413 
414 	/* Don't cache if it was publicly named. */
415 	if (gem_bo->name) {
416 		vc4_bo_destroy(bo);
417 		goto out;
418 	}
419 
420 	/* If this object was partially constructed but CMA allocation
421 	 * had failed, just free it.
422 	 */
423 	if (!bo->base.vaddr) {
424 		vc4_bo_destroy(bo);
425 		goto out;
426 	}
427 
428 	cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
429 	if (!cache_list) {
430 		vc4_bo_destroy(bo);
431 		goto out;
432 	}
433 
434 	if (bo->validated_shader) {
435 		kfree(bo->validated_shader->texture_samples);
436 		kfree(bo->validated_shader);
437 		bo->validated_shader = NULL;
438 	}
439 
440 	bo->t_format = false;
441 	bo->free_time = jiffies;
442 	list_add(&bo->size_head, cache_list);
443 	list_add(&bo->unref_head, &vc4->bo_cache.time_list);
444 
445 	vc4_bo_set_label(&bo->base.base, VC4_BO_TYPE_KERNEL_CACHE);
446 
447 	vc4_bo_cache_free_old(dev);
448 
449 out:
450 	mutex_unlock(&vc4->bo_lock);
451 }
452 
453 static void vc4_bo_cache_time_work(struct work_struct *work)
454 {
455 	struct vc4_dev *vc4 =
456 		container_of(work, struct vc4_dev, bo_cache.time_work);
457 	struct drm_device *dev = vc4->dev;
458 
459 	mutex_lock(&vc4->bo_lock);
460 	vc4_bo_cache_free_old(dev);
461 	mutex_unlock(&vc4->bo_lock);
462 }
463 
464 static void vc4_bo_cache_time_timer(unsigned long data)
465 {
466 	struct drm_device *dev = (struct drm_device *)data;
467 	struct vc4_dev *vc4 = to_vc4_dev(dev);
468 
469 	schedule_work(&vc4->bo_cache.time_work);
470 }
471 
472 struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj)
473 {
474 	struct vc4_bo *bo = to_vc4_bo(obj);
475 
476 	return bo->resv;
477 }
478 
479 struct dma_buf *
480 vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
481 {
482 	struct vc4_bo *bo = to_vc4_bo(obj);
483 
484 	if (bo->validated_shader) {
485 		DRM_DEBUG("Attempting to export shader BO\n");
486 		return ERR_PTR(-EINVAL);
487 	}
488 
489 	return drm_gem_prime_export(dev, obj, flags);
490 }
491 
492 int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
493 {
494 	struct drm_gem_object *gem_obj;
495 	struct vc4_bo *bo;
496 	int ret;
497 
498 	ret = drm_gem_mmap(filp, vma);
499 	if (ret)
500 		return ret;
501 
502 	gem_obj = vma->vm_private_data;
503 	bo = to_vc4_bo(gem_obj);
504 
505 	if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
506 		DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n");
507 		return -EINVAL;
508 	}
509 
510 	/*
511 	 * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
512 	 * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
513 	 * the whole buffer.
514 	 */
515 	vma->vm_flags &= ~VM_PFNMAP;
516 	vma->vm_pgoff = 0;
517 
518 	ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr,
519 			  bo->base.paddr, vma->vm_end - vma->vm_start);
520 	if (ret)
521 		drm_gem_vm_close(vma);
522 
523 	return ret;
524 }
525 
526 int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
527 {
528 	struct vc4_bo *bo = to_vc4_bo(obj);
529 
530 	if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
531 		DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n");
532 		return -EINVAL;
533 	}
534 
535 	return drm_gem_cma_prime_mmap(obj, vma);
536 }
537 
538 void *vc4_prime_vmap(struct drm_gem_object *obj)
539 {
540 	struct vc4_bo *bo = to_vc4_bo(obj);
541 
542 	if (bo->validated_shader) {
543 		DRM_DEBUG("mmaping of shader BOs not allowed.\n");
544 		return ERR_PTR(-EINVAL);
545 	}
546 
547 	return drm_gem_cma_prime_vmap(obj);
548 }
549 
550 struct drm_gem_object *
551 vc4_prime_import_sg_table(struct drm_device *dev,
552 			  struct dma_buf_attachment *attach,
553 			  struct sg_table *sgt)
554 {
555 	struct drm_gem_object *obj;
556 	struct vc4_bo *bo;
557 
558 	obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
559 	if (IS_ERR(obj))
560 		return obj;
561 
562 	bo = to_vc4_bo(obj);
563 	bo->resv = attach->dmabuf->resv;
564 
565 	return obj;
566 }
567 
568 int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
569 			struct drm_file *file_priv)
570 {
571 	struct drm_vc4_create_bo *args = data;
572 	struct vc4_bo *bo = NULL;
573 	int ret;
574 
575 	/*
576 	 * We can't allocate from the BO cache, because the BOs don't
577 	 * get zeroed, and that might leak data between users.
578 	 */
579 	bo = vc4_bo_create(dev, args->size, false, VC4_BO_TYPE_V3D);
580 	if (IS_ERR(bo))
581 		return PTR_ERR(bo);
582 
583 	ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
584 	drm_gem_object_put_unlocked(&bo->base.base);
585 
586 	return ret;
587 }
588 
589 int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
590 		      struct drm_file *file_priv)
591 {
592 	struct drm_vc4_mmap_bo *args = data;
593 	struct drm_gem_object *gem_obj;
594 
595 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
596 	if (!gem_obj) {
597 		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
598 		return -EINVAL;
599 	}
600 
601 	/* The mmap offset was set up at BO allocation time. */
602 	args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
603 
604 	drm_gem_object_put_unlocked(gem_obj);
605 	return 0;
606 }
607 
608 int
609 vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
610 			   struct drm_file *file_priv)
611 {
612 	struct drm_vc4_create_shader_bo *args = data;
613 	struct vc4_bo *bo = NULL;
614 	int ret;
615 
616 	if (args->size == 0)
617 		return -EINVAL;
618 
619 	if (args->size % sizeof(u64) != 0)
620 		return -EINVAL;
621 
622 	if (args->flags != 0) {
623 		DRM_INFO("Unknown flags set: 0x%08x\n", args->flags);
624 		return -EINVAL;
625 	}
626 
627 	if (args->pad != 0) {
628 		DRM_INFO("Pad set: 0x%08x\n", args->pad);
629 		return -EINVAL;
630 	}
631 
632 	bo = vc4_bo_create(dev, args->size, true, VC4_BO_TYPE_V3D_SHADER);
633 	if (IS_ERR(bo))
634 		return PTR_ERR(bo);
635 
636 	if (copy_from_user(bo->base.vaddr,
637 			     (void __user *)(uintptr_t)args->data,
638 			     args->size)) {
639 		ret = -EFAULT;
640 		goto fail;
641 	}
642 	/* Clear the rest of the memory from allocating from the BO
643 	 * cache.
644 	 */
645 	memset(bo->base.vaddr + args->size, 0,
646 	       bo->base.base.size - args->size);
647 
648 	bo->validated_shader = vc4_validate_shader(&bo->base);
649 	if (!bo->validated_shader) {
650 		ret = -EINVAL;
651 		goto fail;
652 	}
653 
654 	/* We have to create the handle after validation, to avoid
655 	 * races for users to do doing things like mmap the shader BO.
656 	 */
657 	ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
658 
659  fail:
660 	drm_gem_object_put_unlocked(&bo->base.base);
661 
662 	return ret;
663 }
664 
665 /**
666  * vc4_set_tiling_ioctl() - Sets the tiling modifier for a BO.
667  * @dev: DRM device
668  * @data: ioctl argument
669  * @file_priv: DRM file for this fd
670  *
671  * The tiling state of the BO decides the default modifier of an fb if
672  * no specific modifier was set by userspace, and the return value of
673  * vc4_get_tiling_ioctl() (so that userspace can treat a BO it
674  * received from dmabuf as the same tiling format as the producer
675  * used).
676  */
677 int vc4_set_tiling_ioctl(struct drm_device *dev, void *data,
678 			 struct drm_file *file_priv)
679 {
680 	struct drm_vc4_set_tiling *args = data;
681 	struct drm_gem_object *gem_obj;
682 	struct vc4_bo *bo;
683 	bool t_format;
684 
685 	if (args->flags != 0)
686 		return -EINVAL;
687 
688 	switch (args->modifier) {
689 	case DRM_FORMAT_MOD_NONE:
690 		t_format = false;
691 		break;
692 	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
693 		t_format = true;
694 		break;
695 	default:
696 		return -EINVAL;
697 	}
698 
699 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
700 	if (!gem_obj) {
701 		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
702 		return -ENOENT;
703 	}
704 	bo = to_vc4_bo(gem_obj);
705 	bo->t_format = t_format;
706 
707 	drm_gem_object_put_unlocked(gem_obj);
708 
709 	return 0;
710 }
711 
712 /**
713  * vc4_get_tiling_ioctl() - Gets the tiling modifier for a BO.
714  * @dev: DRM device
715  * @data: ioctl argument
716  * @file_priv: DRM file for this fd
717  *
718  * Returns the tiling modifier for a BO as set by vc4_set_tiling_ioctl().
719  */
720 int vc4_get_tiling_ioctl(struct drm_device *dev, void *data,
721 			 struct drm_file *file_priv)
722 {
723 	struct drm_vc4_get_tiling *args = data;
724 	struct drm_gem_object *gem_obj;
725 	struct vc4_bo *bo;
726 
727 	if (args->flags != 0 || args->modifier != 0)
728 		return -EINVAL;
729 
730 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
731 	if (!gem_obj) {
732 		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
733 		return -ENOENT;
734 	}
735 	bo = to_vc4_bo(gem_obj);
736 
737 	if (bo->t_format)
738 		args->modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;
739 	else
740 		args->modifier = DRM_FORMAT_MOD_NONE;
741 
742 	drm_gem_object_put_unlocked(gem_obj);
743 
744 	return 0;
745 }
746 
747 int vc4_bo_cache_init(struct drm_device *dev)
748 {
749 	struct vc4_dev *vc4 = to_vc4_dev(dev);
750 	int i;
751 
752 	/* Create the initial set of BO labels that the kernel will
753 	 * use.  This lets us avoid a bunch of string reallocation in
754 	 * the kernel's draw and BO allocation paths.
755 	 */
756 	vc4->bo_labels = kcalloc(VC4_BO_TYPE_COUNT, sizeof(*vc4->bo_labels),
757 				 GFP_KERNEL);
758 	if (!vc4->bo_labels)
759 		return -ENOMEM;
760 	vc4->num_labels = VC4_BO_TYPE_COUNT;
761 
762 	BUILD_BUG_ON(ARRAY_SIZE(bo_type_names) != VC4_BO_TYPE_COUNT);
763 	for (i = 0; i < VC4_BO_TYPE_COUNT; i++)
764 		vc4->bo_labels[i].name = bo_type_names[i];
765 
766 	mutex_init(&vc4->bo_lock);
767 
768 	INIT_LIST_HEAD(&vc4->bo_cache.time_list);
769 
770 	INIT_WORK(&vc4->bo_cache.time_work, vc4_bo_cache_time_work);
771 	setup_timer(&vc4->bo_cache.time_timer,
772 		    vc4_bo_cache_time_timer,
773 		    (unsigned long)dev);
774 
775 	return 0;
776 }
777 
778 void vc4_bo_cache_destroy(struct drm_device *dev)
779 {
780 	struct vc4_dev *vc4 = to_vc4_dev(dev);
781 	int i;
782 
783 	del_timer(&vc4->bo_cache.time_timer);
784 	cancel_work_sync(&vc4->bo_cache.time_work);
785 
786 	vc4_bo_cache_purge(dev);
787 
788 	for (i = 0; i < vc4->num_labels; i++) {
789 		if (vc4->bo_labels[i].num_allocated) {
790 			DRM_ERROR("Destroying BO cache with %d %s "
791 				  "BOs still allocated\n",
792 				  vc4->bo_labels[i].num_allocated,
793 				  vc4->bo_labels[i].name);
794 		}
795 
796 		if (is_user_label(i))
797 			kfree(vc4->bo_labels[i].name);
798 	}
799 	kfree(vc4->bo_labels);
800 }
801 
802 int vc4_label_bo_ioctl(struct drm_device *dev, void *data,
803 		       struct drm_file *file_priv)
804 {
805 	struct vc4_dev *vc4 = to_vc4_dev(dev);
806 	struct drm_vc4_label_bo *args = data;
807 	char *name;
808 	struct drm_gem_object *gem_obj;
809 	int ret = 0, label;
810 
811 	if (!args->len)
812 		return -EINVAL;
813 
814 	name = strndup_user(u64_to_user_ptr(args->name), args->len + 1);
815 	if (IS_ERR(name))
816 		return PTR_ERR(name);
817 
818 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
819 	if (!gem_obj) {
820 		DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
821 		kfree(name);
822 		return -ENOENT;
823 	}
824 
825 	mutex_lock(&vc4->bo_lock);
826 	label = vc4_get_user_label(vc4, name);
827 	if (label != -1)
828 		vc4_bo_set_label(gem_obj, label);
829 	else
830 		ret = -ENOMEM;
831 	mutex_unlock(&vc4->bo_lock);
832 
833 	drm_gem_object_put_unlocked(gem_obj);
834 
835 	return ret;
836 }
837