xref: /dragonfly/sys/dev/drm/ttm/ttm_bo.c (revision 932d855e)
15718399fSFrançois Tigeot /**************************************************************************
25718399fSFrançois Tigeot  *
35718399fSFrançois Tigeot  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
45718399fSFrançois Tigeot  * All Rights Reserved.
55718399fSFrançois Tigeot  *
65718399fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
75718399fSFrançois Tigeot  * copy of this software and associated documentation files (the
85718399fSFrançois Tigeot  * "Software"), to deal in the Software without restriction, including
95718399fSFrançois Tigeot  * without limitation the rights to use, copy, modify, merge, publish,
105718399fSFrançois Tigeot  * distribute, sub license, and/or sell copies of the Software, and to
115718399fSFrançois Tigeot  * permit persons to whom the Software is furnished to do so, subject to
125718399fSFrançois Tigeot  * the following conditions:
135718399fSFrançois Tigeot  *
145718399fSFrançois Tigeot  * The above copyright notice and this permission notice (including the
155718399fSFrançois Tigeot  * next paragraph) shall be included in all copies or substantial portions
165718399fSFrançois Tigeot  * of the Software.
175718399fSFrançois Tigeot  *
185718399fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
195718399fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
205718399fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
215718399fSFrançois Tigeot  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
225718399fSFrançois Tigeot  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
235718399fSFrançois Tigeot  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
245718399fSFrançois Tigeot  * USE OR OTHER DEALINGS IN THE SOFTWARE.
255718399fSFrançois Tigeot  *
265718399fSFrançois Tigeot  **************************************************************************/
275718399fSFrançois Tigeot /*
285718399fSFrançois Tigeot  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
295718399fSFrançois Tigeot  */
305718399fSFrançois Tigeot 
31c19c6249SFrançois Tigeot #define pr_fmt(fmt) "[TTM] " fmt
32c19c6249SFrançois Tigeot 
33216f7a2cSFrançois Tigeot #include <drm/ttm/ttm_module.h>
34216f7a2cSFrançois Tigeot #include <drm/ttm/ttm_bo_driver.h>
35216f7a2cSFrançois Tigeot #include <drm/ttm/ttm_placement.h>
363a2096e8SFrançois Tigeot #include <linux/jiffies.h>
373a2096e8SFrançois Tigeot #include <linux/slab.h>
383a2096e8SFrançois Tigeot #include <linux/sched.h>
393a2096e8SFrançois Tigeot #include <linux/mm.h>
403a2096e8SFrançois Tigeot #include <linux/file.h>
413a2096e8SFrançois Tigeot #include <linux/module.h>
42c19c6249SFrançois Tigeot #include <linux/atomic.h>
431cfef1a5SFrançois Tigeot #include <linux/reservation.h>
445718399fSFrançois Tigeot 
45a34b4168SMatthew Dillon #define TTM_ASSERT_LOCKED(param)
46a34b4168SMatthew Dillon #define TTM_DEBUG(fmt, arg...)
475718399fSFrançois Tigeot #define TTM_BO_HASH_ORDER 13
485718399fSFrançois Tigeot 
493a2096e8SFrançois Tigeot static void ttm_bo_global_kobj_release(struct kobject *kobj);
503a2096e8SFrançois Tigeot 
513a2096e8SFrançois Tigeot static struct attribute ttm_bo_count = {
523a2096e8SFrançois Tigeot 	.name = "bo_count",
533a2096e8SFrançois Tigeot 	.mode = S_IRUGO
543a2096e8SFrançois Tigeot };
555718399fSFrançois Tigeot 
56*932d855eSSergey Zigachev /* default destructor */
ttm_bo_default_destroy(struct ttm_buffer_object * bo)57*932d855eSSergey Zigachev static void ttm_bo_default_destroy(struct ttm_buffer_object *bo)
58*932d855eSSergey Zigachev {
59*932d855eSSergey Zigachev 	kfree(bo);
60*932d855eSSergey Zigachev }
61*932d855eSSergey Zigachev 
ttm_mem_type_from_place(const struct ttm_place * place,uint32_t * mem_type)62591d5043SFrançois Tigeot static inline int ttm_mem_type_from_place(const struct ttm_place *place,
63591d5043SFrançois Tigeot 					  uint32_t *mem_type)
645718399fSFrançois Tigeot {
651dedbd3bSFrançois Tigeot 	int pos;
665718399fSFrançois Tigeot 
671dedbd3bSFrançois Tigeot 	pos = ffs(place->flags & TTM_PL_MASK_MEM);
681dedbd3bSFrançois Tigeot 	if (unlikely(!pos))
695718399fSFrançois Tigeot 		return -EINVAL;
701dedbd3bSFrançois Tigeot 
711dedbd3bSFrançois Tigeot 	*mem_type = pos - 1;
721dedbd3bSFrançois Tigeot 	return 0;
735718399fSFrançois Tigeot }
745718399fSFrançois Tigeot 
ttm_mem_type_debug(struct ttm_bo_device * bdev,int mem_type)755718399fSFrançois Tigeot static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type)
765718399fSFrançois Tigeot {
775718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
783f2dd94aSFrançois Tigeot 	struct drm_printer p = drm_debug_printer(TTM_PFX);
795718399fSFrançois Tigeot 
800bece63dSImre Vadasz 	pr_err("    has_type: %d\n", man->has_type);
810bece63dSImre Vadasz 	pr_err("    use_type: %d\n", man->use_type);
820bece63dSImre Vadasz 	pr_err("    flags: 0x%08X\n", man->flags);
830bece63dSImre Vadasz 	pr_err("    gpu_offset: 0x%08lX\n", man->gpu_offset);
84a34b4168SMatthew Dillon 	pr_err("    size: %ju\n", man->size);
850bece63dSImre Vadasz 	pr_err("    available_caching: 0x%08X\n", man->available_caching);
860bece63dSImre Vadasz 	pr_err("    default_caching: 0x%08X\n", man->default_caching);
875718399fSFrançois Tigeot 	if (mem_type != TTM_PL_SYSTEM)
883f2dd94aSFrançois Tigeot 		(*man->func->debug)(man, &p);
895718399fSFrançois Tigeot }
905718399fSFrançois Tigeot 
ttm_bo_mem_space_debug(struct ttm_buffer_object * bo,struct ttm_placement * placement)915718399fSFrançois Tigeot static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
925718399fSFrançois Tigeot 					struct ttm_placement *placement)
935718399fSFrançois Tigeot {
945718399fSFrançois Tigeot 	int i, ret, mem_type;
955718399fSFrançois Tigeot 
960bece63dSImre Vadasz 	pr_err("No space for %p (%lu pages, %luK, %luM)\n",
975718399fSFrançois Tigeot 	       bo, bo->mem.num_pages, bo->mem.size >> 10,
985718399fSFrançois Tigeot 	       bo->mem.size >> 20);
995718399fSFrançois Tigeot 	for (i = 0; i < placement->num_placement; i++) {
100591d5043SFrançois Tigeot 		ret = ttm_mem_type_from_place(&placement->placement[i],
1015718399fSFrançois Tigeot 						&mem_type);
1025718399fSFrançois Tigeot 		if (ret)
1035718399fSFrançois Tigeot 			return;
1040bece63dSImre Vadasz 		pr_err("  placement[%d]=0x%08X (%d)\n",
105591d5043SFrançois Tigeot 		       i, placement->placement[i].flags, mem_type);
1065718399fSFrançois Tigeot 		ttm_mem_type_debug(bo->bdev, mem_type);
1075718399fSFrançois Tigeot 	}
1085718399fSFrançois Tigeot }
1095718399fSFrançois Tigeot 
ttm_bo_global_show(struct kobject * kobj,struct attribute * attr,char * buffer)1103a2096e8SFrançois Tigeot static ssize_t ttm_bo_global_show(struct kobject *kobj,
1113a2096e8SFrançois Tigeot 				  struct attribute *attr,
1125718399fSFrançois Tigeot 				  char *buffer)
1135718399fSFrançois Tigeot {
1143a2096e8SFrançois Tigeot 	struct ttm_bo_global *glob =
1153a2096e8SFrançois Tigeot 		container_of(kobj, struct ttm_bo_global, kobj);
1165718399fSFrançois Tigeot 
1173f2dd94aSFrançois Tigeot 	return snprintf(buffer, PAGE_SIZE, "%d\n",
1183f2dd94aSFrançois Tigeot 				atomic_read(&glob->bo_count));
1195718399fSFrançois Tigeot }
1203a2096e8SFrançois Tigeot 
1213a2096e8SFrançois Tigeot static struct attribute *ttm_bo_global_attrs[] = {
1223a2096e8SFrançois Tigeot 	&ttm_bo_count,
1233a2096e8SFrançois Tigeot 	NULL
1243a2096e8SFrançois Tigeot };
1253a2096e8SFrançois Tigeot 
1263a2096e8SFrançois Tigeot static const struct sysfs_ops ttm_bo_global_ops = {
1273a2096e8SFrançois Tigeot 	.show = &ttm_bo_global_show
1283a2096e8SFrançois Tigeot };
1293a2096e8SFrançois Tigeot 
1303a2096e8SFrançois Tigeot static struct kobj_type ttm_bo_glob_kobj_type  = {
1313a2096e8SFrançois Tigeot 	.release = &ttm_bo_global_kobj_release,
1323a2096e8SFrançois Tigeot 	.sysfs_ops = &ttm_bo_global_ops,
1333a2096e8SFrançois Tigeot 	.default_attrs = ttm_bo_global_attrs
1343a2096e8SFrançois Tigeot };
1355718399fSFrançois Tigeot 
136a34b4168SMatthew Dillon 
ttm_bo_type_flags(unsigned type)1375718399fSFrançois Tigeot static inline uint32_t ttm_bo_type_flags(unsigned type)
1385718399fSFrançois Tigeot {
1395718399fSFrançois Tigeot 	return 1 << (type);
1405718399fSFrançois Tigeot }
1415718399fSFrançois Tigeot 
ttm_bo_release_list(struct kref * list_kref)142e3b244c9SFrançois Tigeot static void ttm_bo_release_list(struct kref *list_kref)
1435718399fSFrançois Tigeot {
144e3b244c9SFrançois Tigeot 	struct ttm_buffer_object *bo =
145e3b244c9SFrançois Tigeot 	    container_of(list_kref, struct ttm_buffer_object, list_kref);
1465718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
1475718399fSFrançois Tigeot 	size_t acc_size = bo->acc_size;
1485718399fSFrançois Tigeot 
149a85cb24fSFrançois Tigeot 	BUG_ON(kref_read(&bo->list_kref));
150a85cb24fSFrançois Tigeot 	BUG_ON(kref_read(&bo->kref));
151e3b244c9SFrançois Tigeot 	BUG_ON(atomic_read(&bo->cpu_writers));
152e3b244c9SFrançois Tigeot 	BUG_ON(bo->mem.mm_node != NULL);
153e3b244c9SFrançois Tigeot 	BUG_ON(!list_empty(&bo->lru));
154e3b244c9SFrançois Tigeot 	BUG_ON(!list_empty(&bo->ddestroy));
1555718399fSFrançois Tigeot 	ttm_tt_destroy(bo->ttm);
156*932d855eSSergey Zigachev 	atomic_dec(&bo->bdev->glob->bo_count);
1576559babbSFrançois Tigeot 	dma_fence_put(bo->moving);
1583c3b358eSFrançois Tigeot 	reservation_object_fini(&bo->ttm_resv);
15943e748b9SFrançois Tigeot 	mutex_destroy(&bo->wu_mutex);
1605718399fSFrançois Tigeot 	bo->destroy(bo);
1615718399fSFrançois Tigeot 	ttm_mem_global_free(bdev->glob->mem_glob, acc_size);
1625718399fSFrançois Tigeot }
1635718399fSFrançois Tigeot 
ttm_bo_add_to_lru(struct ttm_buffer_object * bo)1645718399fSFrançois Tigeot void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
1655718399fSFrançois Tigeot {
1665718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
167a85cb24fSFrançois Tigeot 	struct ttm_mem_type_manager *man;
1685718399fSFrançois Tigeot 
169189951a7SFrançois Tigeot 	lockdep_assert_held(&bo->resv->lock.base);
1705718399fSFrançois Tigeot 
1715718399fSFrançois Tigeot 	if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
1725718399fSFrançois Tigeot 
1739505a98fSFrançois Tigeot #ifdef __DragonFly__
1749505a98fSFrançois Tigeot 		if (WARN_ON(!list_empty(&bo->lru)))
1759505a98fSFrançois Tigeot 			return;
1769505a98fSFrançois Tigeot #endif
1775718399fSFrançois Tigeot 
178a85cb24fSFrançois Tigeot 		man = &bdev->man[bo->mem.mem_type];
179a85cb24fSFrançois Tigeot 		list_add_tail(&bo->lru, &man->lru[bo->priority]);
180e3b244c9SFrançois Tigeot 		kref_get(&bo->list_kref);
1815718399fSFrançois Tigeot 
1823f2dd94aSFrançois Tigeot 		if (bo->ttm && !(bo->ttm->page_flags &
1833f2dd94aSFrançois Tigeot 				 (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SWAPPED))) {
184a85cb24fSFrançois Tigeot 			list_add_tail(&bo->swap,
185*932d855eSSergey Zigachev 				      &bdev->glob->swap_lru[bo->priority]);
186e3b244c9SFrançois Tigeot 			kref_get(&bo->list_kref);
1875718399fSFrançois Tigeot 		}
1885718399fSFrançois Tigeot 	}
1895718399fSFrançois Tigeot }
1906a001295SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_add_to_lru);
1915718399fSFrançois Tigeot 
ttm_bo_ref_bug(struct kref * list_kref)192e3b244c9SFrançois Tigeot static void ttm_bo_ref_bug(struct kref *list_kref)
193e3b244c9SFrançois Tigeot {
194e3b244c9SFrançois Tigeot 	BUG();
195e3b244c9SFrançois Tigeot }
196e3b244c9SFrançois Tigeot 
ttm_bo_del_from_lru(struct ttm_buffer_object * bo)197a85cb24fSFrançois Tigeot void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
1985718399fSFrançois Tigeot {
199a85cb24fSFrançois Tigeot 	if (!list_empty(&bo->swap)) {
200a85cb24fSFrançois Tigeot 		list_del_init(&bo->swap);
201a85cb24fSFrançois Tigeot 		kref_put(&bo->list_kref, ttm_bo_ref_bug);
202a85cb24fSFrançois Tigeot 	}
203a85cb24fSFrançois Tigeot 	if (!list_empty(&bo->lru)) {
204a85cb24fSFrançois Tigeot 		list_del_init(&bo->lru);
205a85cb24fSFrançois Tigeot 		kref_put(&bo->list_kref, ttm_bo_ref_bug);
206a85cb24fSFrançois Tigeot 	}
207a85cb24fSFrançois Tigeot 
208a85cb24fSFrançois Tigeot 	/*
209a85cb24fSFrançois Tigeot 	 * TODO: Add a driver hook to delete from
210a85cb24fSFrançois Tigeot 	 * driver-specific LRU's here.
211a85cb24fSFrançois Tigeot 	 */
2125718399fSFrançois Tigeot }
2135718399fSFrançois Tigeot 
ttm_bo_del_sub_from_lru(struct ttm_buffer_object * bo)2146a001295SFrançois Tigeot void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo)
2155718399fSFrançois Tigeot {
216*932d855eSSergey Zigachev 	struct ttm_bo_global *glob = bo->bdev->glob;
217*932d855eSSergey Zigachev 
218*932d855eSSergey Zigachev 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
219a85cb24fSFrançois Tigeot 	ttm_bo_del_from_lru(bo);
220*932d855eSSergey Zigachev 	lockmgr(&glob->lru_lock, LK_RELEASE);
221c19c6249SFrançois Tigeot }
2226a001295SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_del_sub_from_lru);
2234cd92098Szrj 
ttm_bo_move_to_lru_tail(struct ttm_buffer_object * bo)224d78d3a22SFrançois Tigeot void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
225d78d3a22SFrançois Tigeot {
226d78d3a22SFrançois Tigeot 	lockdep_assert_held(&bo->resv->lock.base);
227d78d3a22SFrançois Tigeot 
228a85cb24fSFrançois Tigeot 	ttm_bo_del_from_lru(bo);
229d78d3a22SFrançois Tigeot 	ttm_bo_add_to_lru(bo);
230d78d3a22SFrançois Tigeot }
231d78d3a22SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
232d78d3a22SFrançois Tigeot 
ttm_bo_handle_move_mem(struct ttm_buffer_object * bo,struct ttm_mem_reg * mem,bool evict,struct ttm_operation_ctx * ctx)2335718399fSFrançois Tigeot static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
234*932d855eSSergey Zigachev 				  struct ttm_mem_reg *mem, bool evict,
235*932d855eSSergey Zigachev 				  struct ttm_operation_ctx *ctx)
2365718399fSFrançois Tigeot {
2375718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
2385718399fSFrançois Tigeot 	bool old_is_pci = ttm_mem_reg_is_pci(bdev, &bo->mem);
2395718399fSFrançois Tigeot 	bool new_is_pci = ttm_mem_reg_is_pci(bdev, mem);
2405718399fSFrançois Tigeot 	struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type];
2415718399fSFrançois Tigeot 	struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type];
2425718399fSFrançois Tigeot 	int ret = 0;
2435718399fSFrançois Tigeot 
2445718399fSFrançois Tigeot 	if (old_is_pci || new_is_pci ||
2455718399fSFrançois Tigeot 	    ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) {
2465718399fSFrançois Tigeot 		ret = ttm_mem_io_lock(old_man, true);
2475718399fSFrançois Tigeot 		if (unlikely(ret != 0))
2485718399fSFrançois Tigeot 			goto out_err;
2495718399fSFrançois Tigeot 		ttm_bo_unmap_virtual_locked(bo);
2505718399fSFrançois Tigeot 		ttm_mem_io_unlock(old_man);
2515718399fSFrançois Tigeot 	}
2525718399fSFrançois Tigeot 
2535718399fSFrançois Tigeot 	/*
2545718399fSFrançois Tigeot 	 * Create and bind a ttm if required.
2555718399fSFrançois Tigeot 	 */
2565718399fSFrançois Tigeot 
2575718399fSFrançois Tigeot 	if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
2585718399fSFrançois Tigeot 		if (bo->ttm == NULL) {
2595718399fSFrançois Tigeot 			bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
260*932d855eSSergey Zigachev 			ret = ttm_tt_create(bo, zero);
2615718399fSFrançois Tigeot 			if (ret)
2625718399fSFrançois Tigeot 				goto out_err;
2635718399fSFrançois Tigeot 		}
2645718399fSFrançois Tigeot 
2655718399fSFrançois Tigeot 		ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
2665718399fSFrançois Tigeot 		if (ret)
2675718399fSFrançois Tigeot 			goto out_err;
2685718399fSFrançois Tigeot 
2695718399fSFrançois Tigeot 		if (mem->mem_type != TTM_PL_SYSTEM) {
270*932d855eSSergey Zigachev 			ret = ttm_tt_bind(bo->ttm, mem, ctx);
2715718399fSFrançois Tigeot 			if (ret)
2725718399fSFrançois Tigeot 				goto out_err;
2735718399fSFrançois Tigeot 		}
2745718399fSFrançois Tigeot 
2755718399fSFrançois Tigeot 		if (bo->mem.mem_type == TTM_PL_SYSTEM) {
2765718399fSFrançois Tigeot 			if (bdev->driver->move_notify)
277a85cb24fSFrançois Tigeot 				bdev->driver->move_notify(bo, evict, mem);
2785718399fSFrançois Tigeot 			bo->mem = *mem;
2795718399fSFrançois Tigeot 			mem->mm_node = NULL;
2805718399fSFrançois Tigeot 			goto moved;
2815718399fSFrançois Tigeot 		}
2825718399fSFrançois Tigeot 	}
2835718399fSFrançois Tigeot 
2845718399fSFrançois Tigeot 	if (bdev->driver->move_notify)
285a85cb24fSFrançois Tigeot 		bdev->driver->move_notify(bo, evict, mem);
2865718399fSFrançois Tigeot 
2875718399fSFrançois Tigeot 	if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
2885718399fSFrançois Tigeot 	    !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
289*932d855eSSergey Zigachev 		ret = ttm_bo_move_ttm(bo, ctx, mem);
2905718399fSFrançois Tigeot 	else if (bdev->driver->move)
291*932d855eSSergey Zigachev 		ret = bdev->driver->move(bo, evict, ctx, mem);
2925718399fSFrançois Tigeot 	else
293*932d855eSSergey Zigachev 		ret = ttm_bo_move_memcpy(bo, ctx, mem);
2945718399fSFrançois Tigeot 
2955718399fSFrançois Tigeot 	if (ret) {
2965718399fSFrançois Tigeot 		if (bdev->driver->move_notify) {
297*932d855eSSergey Zigachev 			swap(*mem, bo->mem);
298a85cb24fSFrançois Tigeot 			bdev->driver->move_notify(bo, false, mem);
299*932d855eSSergey Zigachev 			swap(*mem, bo->mem);
3005718399fSFrançois Tigeot 		}
3015718399fSFrançois Tigeot 
3025718399fSFrançois Tigeot 		goto out_err;
3035718399fSFrançois Tigeot 	}
3045718399fSFrançois Tigeot 
3055718399fSFrançois Tigeot moved:
3065718399fSFrançois Tigeot 	if (bo->evicted) {
30743e748b9SFrançois Tigeot 		if (bdev->driver->invalidate_caches) {
3085718399fSFrançois Tigeot 			ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
3095718399fSFrançois Tigeot 			if (ret)
3100bece63dSImre Vadasz 				pr_err("Can not flush read caches\n");
31143e748b9SFrançois Tigeot 		}
3125718399fSFrançois Tigeot 		bo->evicted = false;
3135718399fSFrançois Tigeot 	}
3145718399fSFrançois Tigeot 
315*932d855eSSergey Zigachev 	if (bo->mem.mm_node)
3165718399fSFrançois Tigeot 		bo->offset = (bo->mem.start << PAGE_SHIFT) +
3175718399fSFrançois Tigeot 		    bdev->man[bo->mem.mem_type].gpu_offset;
318*932d855eSSergey Zigachev 	else
3195718399fSFrançois Tigeot 		bo->offset = 0;
3205718399fSFrançois Tigeot 
321*932d855eSSergey Zigachev 	ctx->bytes_moved += bo->num_pages << PAGE_SHIFT;
3225718399fSFrançois Tigeot 	return 0;
3235718399fSFrançois Tigeot 
3245718399fSFrançois Tigeot out_err:
3255718399fSFrançois Tigeot 	new_man = &bdev->man[bo->mem.mem_type];
3261dedbd3bSFrançois Tigeot 	if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) {
3275718399fSFrançois Tigeot 		ttm_tt_destroy(bo->ttm);
3285718399fSFrançois Tigeot 		bo->ttm = NULL;
3295718399fSFrançois Tigeot 	}
3305718399fSFrançois Tigeot 
3315718399fSFrançois Tigeot 	return ret;
3325718399fSFrançois Tigeot }
3335718399fSFrançois Tigeot 
3345718399fSFrançois Tigeot /**
3355718399fSFrançois Tigeot  * Call bo::reserved.
3365718399fSFrançois Tigeot  * Will release GPU memory type usage on destruction.
3375718399fSFrançois Tigeot  * This is the place to put in driver specific hooks to release
3385718399fSFrançois Tigeot  * driver private resources.
3395718399fSFrançois Tigeot  * Will release the bo::reserved lock.
3405718399fSFrançois Tigeot  */
3415718399fSFrançois Tigeot 
ttm_bo_cleanup_memtype_use(struct ttm_buffer_object * bo)3425718399fSFrançois Tigeot static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
3435718399fSFrançois Tigeot {
3445718399fSFrançois Tigeot 	if (bo->bdev->driver->move_notify)
345a85cb24fSFrançois Tigeot 		bo->bdev->driver->move_notify(bo, false, NULL);
3465718399fSFrançois Tigeot 
3475718399fSFrançois Tigeot 	ttm_tt_destroy(bo->ttm);
3485718399fSFrançois Tigeot 	bo->ttm = NULL;
3495718399fSFrançois Tigeot 	ttm_bo_mem_put(bo, &bo->mem);
3505718399fSFrançois Tigeot }
3515718399fSFrançois Tigeot 
ttm_bo_individualize_resv(struct ttm_buffer_object * bo)3523f2dd94aSFrançois Tigeot static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo)
3533f2dd94aSFrançois Tigeot {
3543f2dd94aSFrançois Tigeot 	int r;
3553f2dd94aSFrançois Tigeot 
3563f2dd94aSFrançois Tigeot 	if (bo->resv == &bo->ttm_resv)
3573f2dd94aSFrançois Tigeot 		return 0;
3583f2dd94aSFrançois Tigeot 
3593f2dd94aSFrançois Tigeot 	BUG_ON(!reservation_object_trylock(&bo->ttm_resv));
3603f2dd94aSFrançois Tigeot 
3613f2dd94aSFrançois Tigeot 	r = reservation_object_copy_fences(&bo->ttm_resv, bo->resv);
3623f2dd94aSFrançois Tigeot 	if (r)
3633f2dd94aSFrançois Tigeot 		reservation_object_unlock(&bo->ttm_resv);
3643f2dd94aSFrançois Tigeot 
3653f2dd94aSFrançois Tigeot 	return r;
3663f2dd94aSFrançois Tigeot }
3673f2dd94aSFrançois Tigeot 
ttm_bo_flush_all_fences(struct ttm_buffer_object * bo)3681cfef1a5SFrançois Tigeot static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
3691cfef1a5SFrançois Tigeot {
3701cfef1a5SFrançois Tigeot 	struct reservation_object_list *fobj;
3716559babbSFrançois Tigeot 	struct dma_fence *fence;
3721cfef1a5SFrançois Tigeot 	int i;
3731cfef1a5SFrançois Tigeot 
3743f2dd94aSFrançois Tigeot 	fobj = reservation_object_get_list(&bo->ttm_resv);
3753f2dd94aSFrançois Tigeot 	fence = reservation_object_get_excl(&bo->ttm_resv);
3761cfef1a5SFrançois Tigeot 	if (fence && !fence->ops->signaled)
3776559babbSFrançois Tigeot 		dma_fence_enable_sw_signaling(fence);
3781cfef1a5SFrançois Tigeot 
3791cfef1a5SFrançois Tigeot 	for (i = 0; fobj && i < fobj->shared_count; ++i) {
3801cfef1a5SFrançois Tigeot 		fence = rcu_dereference_protected(fobj->shared[i],
3811cfef1a5SFrançois Tigeot 					reservation_object_held(bo->resv));
3821cfef1a5SFrançois Tigeot 
3831cfef1a5SFrançois Tigeot 		if (!fence->ops->signaled)
3846559babbSFrançois Tigeot 			dma_fence_enable_sw_signaling(fence);
3851cfef1a5SFrançois Tigeot 	}
3861cfef1a5SFrançois Tigeot }
3871cfef1a5SFrançois Tigeot 
ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object * bo)3885718399fSFrançois Tigeot static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
3895718399fSFrançois Tigeot {
3905718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
391*932d855eSSergey Zigachev 	struct ttm_bo_global *glob = bdev->glob;
3925718399fSFrançois Tigeot 	int ret;
3935718399fSFrançois Tigeot 
3943f2dd94aSFrançois Tigeot 	ret = ttm_bo_individualize_resv(bo);
3953f2dd94aSFrançois Tigeot 	if (ret) {
3963f2dd94aSFrançois Tigeot 		/* Last resort, if we fail to allocate memory for the
3973f2dd94aSFrançois Tigeot 		 * fences block for the BO to become idle
3983f2dd94aSFrançois Tigeot 		 */
3993f2dd94aSFrançois Tigeot 		reservation_object_wait_timeout_rcu(bo->resv, true, false,
4003f2dd94aSFrançois Tigeot 						    30 * HZ);
4013f2dd94aSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
4023f2dd94aSFrançois Tigeot 		goto error;
4033f2dd94aSFrançois Tigeot 	}
4043f2dd94aSFrançois Tigeot 
4055718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
406d78d3a22SFrançois Tigeot 	ret = __ttm_bo_reserve(bo, false, true, NULL);
4071cfef1a5SFrançois Tigeot 	if (!ret) {
4083f2dd94aSFrançois Tigeot 		if (reservation_object_test_signaled_rcu(&bo->ttm_resv, true)) {
409a85cb24fSFrançois Tigeot 			ttm_bo_del_from_lru(bo);
4105718399fSFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_RELEASE);
4113f2dd94aSFrançois Tigeot 			if (bo->resv != &bo->ttm_resv)
4123f2dd94aSFrançois Tigeot 				reservation_object_unlock(&bo->ttm_resv);
4135718399fSFrançois Tigeot 
4143f2dd94aSFrançois Tigeot 			ttm_bo_cleanup_memtype_use(bo);
415*932d855eSSergey Zigachev 			__ttm_bo_unreserve(bo);
4165718399fSFrançois Tigeot 			return;
4173f2dd94aSFrançois Tigeot 		}
4183f2dd94aSFrançois Tigeot 
4191cfef1a5SFrançois Tigeot 		ttm_bo_flush_all_fences(bo);
42043e748b9SFrançois Tigeot 
42143e748b9SFrançois Tigeot 		/*
42243e748b9SFrançois Tigeot 		 * Make NO_EVICT bos immediately available to
42343e748b9SFrançois Tigeot 		 * shrinkers, now that they are queued for
42443e748b9SFrançois Tigeot 		 * destruction.
42543e748b9SFrançois Tigeot 		 */
42643e748b9SFrançois Tigeot 		if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT) {
42743e748b9SFrançois Tigeot 			bo->mem.placement &= ~TTM_PL_FLAG_NO_EVICT;
42843e748b9SFrançois Tigeot 			ttm_bo_add_to_lru(bo);
42943e748b9SFrançois Tigeot 		}
43043e748b9SFrançois Tigeot 
43143e748b9SFrançois Tigeot 		__ttm_bo_unreserve(bo);
43243e748b9SFrançois Tigeot 	}
4333f2dd94aSFrançois Tigeot 	if (bo->resv != &bo->ttm_resv)
4343f2dd94aSFrançois Tigeot 		reservation_object_unlock(&bo->ttm_resv);
4355718399fSFrançois Tigeot 
4363f2dd94aSFrançois Tigeot error:
437e3b244c9SFrançois Tigeot 	kref_get(&bo->list_kref);
4385718399fSFrançois Tigeot 	list_add_tail(&bo->ddestroy, &bdev->ddestroy);
4395718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
4405718399fSFrançois Tigeot 
44189a75b27SFrançois Tigeot 	schedule_delayed_work(&bdev->wq,
442a34b4168SMatthew Dillon 			      ((HZ / 100) < 1) ? 1 : HZ / 100);
4435718399fSFrançois Tigeot }
4445718399fSFrançois Tigeot 
4455718399fSFrançois Tigeot /**
446*932d855eSSergey Zigachev  * function ttm_bo_cleanup_refs
4475718399fSFrançois Tigeot  * If bo idle, remove from delayed- and lru lists, and unref.
4485718399fSFrançois Tigeot  * If not idle, do nothing.
4495718399fSFrançois Tigeot  *
4505718399fSFrançois Tigeot  * Must be called with lru_lock and reservation held, this function
451*932d855eSSergey Zigachev  * will drop the lru lock and optionally the reservation lock before returning.
4525718399fSFrançois Tigeot  *
4535718399fSFrançois Tigeot  * @interruptible         Any sleeps should occur interruptibly.
4545718399fSFrançois Tigeot  * @no_wait_gpu           Never wait for gpu. Return -EBUSY instead.
455*932d855eSSergey Zigachev  * @unlock_resv           Unlock the reservation lock as well.
4565718399fSFrançois Tigeot  */
4575718399fSFrançois Tigeot 
ttm_bo_cleanup_refs(struct ttm_buffer_object * bo,bool interruptible,bool no_wait_gpu,bool unlock_resv)458*932d855eSSergey Zigachev static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
459*932d855eSSergey Zigachev 			       bool interruptible, bool no_wait_gpu,
460*932d855eSSergey Zigachev 			       bool unlock_resv)
4615718399fSFrançois Tigeot {
462*932d855eSSergey Zigachev 	struct ttm_bo_global *glob = bo->bdev->glob;
4633f2dd94aSFrançois Tigeot 	struct reservation_object *resv;
4645718399fSFrançois Tigeot 	int ret;
4655718399fSFrançois Tigeot 
4663f2dd94aSFrançois Tigeot 	if (unlikely(list_empty(&bo->ddestroy)))
4673f2dd94aSFrançois Tigeot 		resv = bo->resv;
4683f2dd94aSFrançois Tigeot 	else
4693f2dd94aSFrançois Tigeot 		resv = &bo->ttm_resv;
4703f2dd94aSFrançois Tigeot 
4713f2dd94aSFrançois Tigeot 	if (reservation_object_test_signaled_rcu(resv, true))
4723f2dd94aSFrançois Tigeot 		ret = 0;
4733f2dd94aSFrançois Tigeot 	else
4743f2dd94aSFrançois Tigeot 		ret = -EBUSY;
4755718399fSFrançois Tigeot 
4765718399fSFrançois Tigeot 	if (ret && !no_wait_gpu) {
4771cfef1a5SFrançois Tigeot 		long lret;
478*932d855eSSergey Zigachev 
479*932d855eSSergey Zigachev 		if (unlock_resv)
4801cfef1a5SFrançois Tigeot 			ww_mutex_unlock(&bo->resv->lock);
4815718399fSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_RELEASE);
4825718399fSFrançois Tigeot 
4833f2dd94aSFrançois Tigeot 		lret = reservation_object_wait_timeout_rcu(resv, true,
4841cfef1a5SFrançois Tigeot 							   interruptible,
4851cfef1a5SFrançois Tigeot 							   30 * HZ);
4865718399fSFrançois Tigeot 
4871cfef1a5SFrançois Tigeot 		if (lret < 0)
4881cfef1a5SFrançois Tigeot 			return lret;
4891cfef1a5SFrançois Tigeot 		else if (lret == 0)
4901cfef1a5SFrançois Tigeot 			return -EBUSY;
4915718399fSFrançois Tigeot 
4925718399fSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
493*932d855eSSergey Zigachev 		if (unlock_resv && __ttm_bo_reserve(bo, false, true, NULL)) {
4945718399fSFrançois Tigeot 			/*
4955718399fSFrançois Tigeot 			 * We raced, and lost, someone else holds the reservation now,
4965718399fSFrançois Tigeot 			 * and is probably busy in ttm_bo_cleanup_memtype_use.
4975718399fSFrançois Tigeot 			 *
4985718399fSFrançois Tigeot 			 * Even if it's not the case, because we finished waiting any
4995718399fSFrançois Tigeot 			 * delayed destruction would succeed, so just return success
5005718399fSFrançois Tigeot 			 * here.
5015718399fSFrançois Tigeot 			 */
5025718399fSFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_RELEASE);
5035718399fSFrançois Tigeot 			return 0;
5045718399fSFrançois Tigeot 		}
505*932d855eSSergey Zigachev 		ret = 0;
5061cfef1a5SFrançois Tigeot 	}
5075718399fSFrançois Tigeot 
5085718399fSFrançois Tigeot 	if (ret || unlikely(list_empty(&bo->ddestroy))) {
509*932d855eSSergey Zigachev 		if (unlock_resv)
51043e748b9SFrançois Tigeot 			__ttm_bo_unreserve(bo);
5115718399fSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_RELEASE);
5125718399fSFrançois Tigeot 		return ret;
5135718399fSFrançois Tigeot 	}
5145718399fSFrançois Tigeot 
515a85cb24fSFrançois Tigeot 	ttm_bo_del_from_lru(bo);
5165718399fSFrançois Tigeot 	list_del_init(&bo->ddestroy);
517a85cb24fSFrançois Tigeot 	kref_put(&bo->list_kref, ttm_bo_ref_bug);
5185718399fSFrançois Tigeot 
5195718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
5205718399fSFrançois Tigeot 	ttm_bo_cleanup_memtype_use(bo);
5215718399fSFrançois Tigeot 
522*932d855eSSergey Zigachev 	if (unlock_resv)
523*932d855eSSergey Zigachev 		__ttm_bo_unreserve(bo);
524*932d855eSSergey Zigachev 
5255718399fSFrançois Tigeot 	return 0;
5265718399fSFrançois Tigeot }
5275718399fSFrançois Tigeot 
5285718399fSFrançois Tigeot /**
5295718399fSFrançois Tigeot  * Traverse the delayed list, and call ttm_bo_cleanup_refs on all
5305718399fSFrançois Tigeot  * encountered buffers.
5315718399fSFrançois Tigeot  */
ttm_bo_delayed_delete(struct ttm_bo_device * bdev,bool remove_all)532*932d855eSSergey Zigachev static bool ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
5335718399fSFrançois Tigeot {
5345718399fSFrançois Tigeot 	struct ttm_bo_global *glob = bdev->glob;
535*932d855eSSergey Zigachev 	struct list_head removed;
536*932d855eSSergey Zigachev 	bool empty;
537*932d855eSSergey Zigachev 
538*932d855eSSergey Zigachev 	INIT_LIST_HEAD(&removed);
5395718399fSFrançois Tigeot 
5405718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
541*932d855eSSergey Zigachev 	while (!list_empty(&bdev->ddestroy)) {
542*932d855eSSergey Zigachev 		struct ttm_buffer_object *bo;
5435718399fSFrançois Tigeot 
544*932d855eSSergey Zigachev 		bo = list_first_entry(&bdev->ddestroy, struct ttm_buffer_object,
545*932d855eSSergey Zigachev 				      ddestroy);
546*932d855eSSergey Zigachev 		kref_get(&bo->list_kref);
547*932d855eSSergey Zigachev 		list_move_tail(&bo->ddestroy, &removed);
5485718399fSFrançois Tigeot 
549*932d855eSSergey Zigachev 		if (remove_all || bo->resv != &bo->ttm_resv) {
550b34e1496SFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_RELEASE);
551*932d855eSSergey Zigachev 			reservation_object_lock(bo->resv, NULL);
5525718399fSFrançois Tigeot 
5535718399fSFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
554*932d855eSSergey Zigachev 			ttm_bo_cleanup_refs(bo, false, !remove_all, true);
555*932d855eSSergey Zigachev 
556*932d855eSSergey Zigachev 		} else if (reservation_object_trylock(bo->resv)) {
557*932d855eSSergey Zigachev 			ttm_bo_cleanup_refs(bo, false, !remove_all, true);
558*932d855eSSergey Zigachev 		} else {
559*932d855eSSergey Zigachev 			lockmgr(&glob->lru_lock, LK_RELEASE);
5605718399fSFrançois Tigeot 		}
5615718399fSFrançois Tigeot 
562*932d855eSSergey Zigachev 		kref_put(&bo->list_kref, ttm_bo_release_list);
563*932d855eSSergey Zigachev 		lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
564*932d855eSSergey Zigachev 	}
565*932d855eSSergey Zigachev 	list_splice_tail(&removed, &bdev->ddestroy);
566*932d855eSSergey Zigachev 	empty = list_empty(&bdev->ddestroy);
5675718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
568*932d855eSSergey Zigachev 
569*932d855eSSergey Zigachev 	return empty;
5705718399fSFrançois Tigeot }
5715718399fSFrançois Tigeot 
ttm_bo_delayed_workqueue(struct work_struct * work)57289a75b27SFrançois Tigeot static void ttm_bo_delayed_workqueue(struct work_struct *work)
5735718399fSFrançois Tigeot {
57489a75b27SFrançois Tigeot 	struct ttm_bo_device *bdev =
57589a75b27SFrançois Tigeot 	    container_of(work, struct ttm_bo_device, wq.work);
5765718399fSFrançois Tigeot 
577*932d855eSSergey Zigachev 	if (!ttm_bo_delayed_delete(bdev, false))
57889a75b27SFrançois Tigeot 		schedule_delayed_work(&bdev->wq,
579a34b4168SMatthew Dillon 				      ((HZ / 100) < 1) ? 1 : HZ / 100);
5805718399fSFrançois Tigeot }
5815718399fSFrançois Tigeot 
ttm_bo_release(struct kref * kref)582e3b244c9SFrançois Tigeot static void ttm_bo_release(struct kref *kref)
5835718399fSFrançois Tigeot {
584e3b244c9SFrançois Tigeot 	struct ttm_buffer_object *bo =
585e3b244c9SFrançois Tigeot 	    container_of(kref, struct ttm_buffer_object, kref);
5865718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
5875718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
5885718399fSFrançois Tigeot 
589a34b4168SMatthew Dillon 	drm_vma_offset_remove(&bdev->vma_manager, &bo->vma_node);
5905718399fSFrançois Tigeot 	ttm_mem_io_lock(man, false);
5915718399fSFrançois Tigeot 	ttm_mem_io_free_vm(bo);
5925718399fSFrançois Tigeot 	ttm_mem_io_unlock(man);
5935718399fSFrançois Tigeot 	ttm_bo_cleanup_refs_or_queue(bo);
594e3b244c9SFrançois Tigeot 	kref_put(&bo->list_kref, ttm_bo_release_list);
5955718399fSFrançois Tigeot }
5965718399fSFrançois Tigeot 
ttm_bo_put(struct ttm_buffer_object * bo)597*932d855eSSergey Zigachev void ttm_bo_put(struct ttm_buffer_object *bo)
598*932d855eSSergey Zigachev {
599*932d855eSSergey Zigachev 	kref_put(&bo->kref, ttm_bo_release);
600*932d855eSSergey Zigachev }
601*932d855eSSergey Zigachev EXPORT_SYMBOL(ttm_bo_put);
602*932d855eSSergey Zigachev 
ttm_bo_unref(struct ttm_buffer_object ** p_bo)6035718399fSFrançois Tigeot void ttm_bo_unref(struct ttm_buffer_object **p_bo)
6045718399fSFrançois Tigeot {
6055718399fSFrançois Tigeot 	struct ttm_buffer_object *bo = *p_bo;
6065718399fSFrançois Tigeot 
6075718399fSFrançois Tigeot 	*p_bo = NULL;
608*932d855eSSergey Zigachev 	ttm_bo_put(bo);
6095718399fSFrançois Tigeot }
610c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_unref);
6115718399fSFrançois Tigeot 
ttm_bo_lock_delayed_workqueue(struct ttm_bo_device * bdev)6125718399fSFrançois Tigeot int ttm_bo_lock_delayed_workqueue(struct ttm_bo_device *bdev)
6135718399fSFrançois Tigeot {
61489a75b27SFrançois Tigeot 	return cancel_delayed_work_sync(&bdev->wq);
6155718399fSFrançois Tigeot }
616c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_lock_delayed_workqueue);
6175718399fSFrançois Tigeot 
ttm_bo_unlock_delayed_workqueue(struct ttm_bo_device * bdev,int resched)6185718399fSFrançois Tigeot void ttm_bo_unlock_delayed_workqueue(struct ttm_bo_device *bdev, int resched)
6195718399fSFrançois Tigeot {
62089a75b27SFrançois Tigeot 	if (resched)
62189a75b27SFrançois Tigeot 		schedule_delayed_work(&bdev->wq,
622a34b4168SMatthew Dillon 				      ((HZ / 100) < 1) ? 1 : HZ / 100);
6235718399fSFrançois Tigeot }
624c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_unlock_delayed_workqueue);
6255718399fSFrançois Tigeot 
ttm_bo_evict(struct ttm_buffer_object * bo,struct ttm_operation_ctx * ctx)626*932d855eSSergey Zigachev static int ttm_bo_evict(struct ttm_buffer_object *bo,
627*932d855eSSergey Zigachev 			struct ttm_operation_ctx *ctx)
6285718399fSFrançois Tigeot {
6295718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
6305718399fSFrançois Tigeot 	struct ttm_mem_reg evict_mem;
6315718399fSFrançois Tigeot 	struct ttm_placement placement;
6325718399fSFrançois Tigeot 	int ret = 0;
6335718399fSFrançois Tigeot 
634189951a7SFrançois Tigeot 	lockdep_assert_held(&bo->resv->lock.base);
6355718399fSFrançois Tigeot 
636*932d855eSSergey Zigachev 	placement.num_placement = 0;
637*932d855eSSergey Zigachev 	placement.num_busy_placement = 0;
638*932d855eSSergey Zigachev 	bdev->driver->evict_flags(bo, &placement);
639*932d855eSSergey Zigachev 
640*932d855eSSergey Zigachev 	if (!placement.num_placement && !placement.num_busy_placement) {
641*932d855eSSergey Zigachev 		ret = ttm_bo_pipeline_gutting(bo);
642*932d855eSSergey Zigachev 		if (ret)
643*932d855eSSergey Zigachev 			return ret;
644*932d855eSSergey Zigachev 
645*932d855eSSergey Zigachev 		return ttm_tt_create(bo, false);
646*932d855eSSergey Zigachev 	}
647*932d855eSSergey Zigachev 
6485718399fSFrançois Tigeot 	evict_mem = bo->mem;
6495718399fSFrançois Tigeot 	evict_mem.mm_node = NULL;
6505718399fSFrançois Tigeot 	evict_mem.bus.io_reserved_vm = false;
6515718399fSFrançois Tigeot 	evict_mem.bus.io_reserved_count = 0;
6525718399fSFrançois Tigeot 
653*932d855eSSergey Zigachev 	ret = ttm_bo_mem_space(bo, &placement, &evict_mem, ctx);
6545718399fSFrançois Tigeot 	if (ret) {
655797013cfSFrançois Tigeot 		if (ret != -ERESTARTSYS) {
656797013cfSFrançois Tigeot 			pr_err("Failed to find memory space for buffer 0x%p eviction\n",
6575718399fSFrançois Tigeot 			       bo);
6585718399fSFrançois Tigeot 			ttm_bo_mem_space_debug(bo, &placement);
6595718399fSFrançois Tigeot 		}
6605718399fSFrançois Tigeot 		goto out;
6615718399fSFrançois Tigeot 	}
6625718399fSFrançois Tigeot 
663*932d855eSSergey Zigachev 	ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, ctx);
6641dedbd3bSFrançois Tigeot 	if (unlikely(ret)) {
665797013cfSFrançois Tigeot 		if (ret != -ERESTARTSYS)
666797013cfSFrançois Tigeot 			pr_err("Buffer eviction failed\n");
6675718399fSFrançois Tigeot 		ttm_bo_mem_put(bo, &evict_mem);
6685718399fSFrançois Tigeot 		goto out;
6695718399fSFrançois Tigeot 	}
6705718399fSFrançois Tigeot 	bo->evicted = true;
6715718399fSFrançois Tigeot out:
6725718399fSFrançois Tigeot 	return ret;
6735718399fSFrançois Tigeot }
6745718399fSFrançois Tigeot 
ttm_bo_eviction_valuable(struct ttm_buffer_object * bo,const struct ttm_place * place)6754be47400SFrançois Tigeot bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
6764be47400SFrançois Tigeot 			      const struct ttm_place *place)
6774be47400SFrançois Tigeot {
6784be47400SFrançois Tigeot 	/* Don't evict this BO if it's outside of the
6794be47400SFrançois Tigeot 	 * requested placement range
6804be47400SFrançois Tigeot 	 */
681*932d855eSSergey Zigachev 	if (place->fpfn >= (bo->mem.start + bo->mem.num_pages) ||
6824be47400SFrançois Tigeot 	    (place->lpfn && place->lpfn <= bo->mem.start))
6834be47400SFrançois Tigeot 		return false;
6844be47400SFrançois Tigeot 
6854be47400SFrançois Tigeot 	return true;
6864be47400SFrançois Tigeot }
6874be47400SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_eviction_valuable);
6884be47400SFrançois Tigeot 
689*932d855eSSergey Zigachev /**
690*932d855eSSergey Zigachev  * Check the target bo is allowable to be evicted or swapout, including cases:
691*932d855eSSergey Zigachev  *
692*932d855eSSergey Zigachev  * a. if share same reservation object with ctx->resv, have assumption
693*932d855eSSergey Zigachev  * reservation objects should already be locked, so not lock again and
694*932d855eSSergey Zigachev  * return true directly when either the opreation allow_reserved_eviction
695*932d855eSSergey Zigachev  * or the target bo already is in delayed free list;
696*932d855eSSergey Zigachev  *
697*932d855eSSergey Zigachev  * b. Otherwise, trylock it.
698*932d855eSSergey Zigachev  */
ttm_bo_evict_swapout_allowable(struct ttm_buffer_object * bo,struct ttm_operation_ctx * ctx,bool * locked)699*932d855eSSergey Zigachev static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
700*932d855eSSergey Zigachev 			struct ttm_operation_ctx *ctx, bool *locked)
701*932d855eSSergey Zigachev {
702*932d855eSSergey Zigachev 	bool ret = false;
703*932d855eSSergey Zigachev 
704*932d855eSSergey Zigachev 	*locked = false;
705*932d855eSSergey Zigachev 	if (bo->resv == ctx->resv) {
706*932d855eSSergey Zigachev 		lockdep_assert_held(&bo->resv->lock.base);
707*932d855eSSergey Zigachev 		if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
708*932d855eSSergey Zigachev 		    || !list_empty(&bo->ddestroy))
709*932d855eSSergey Zigachev 			ret = true;
710*932d855eSSergey Zigachev 	} else {
711*932d855eSSergey Zigachev 		*locked = ww_mutex_trylock(&bo->resv->lock);
712*932d855eSSergey Zigachev 		ret = *locked;
713*932d855eSSergey Zigachev 	}
714*932d855eSSergey Zigachev 
715*932d855eSSergey Zigachev 	return ret;
716*932d855eSSergey Zigachev }
717*932d855eSSergey Zigachev 
ttm_mem_evict_first(struct ttm_bo_device * bdev,uint32_t mem_type,const struct ttm_place * place,struct ttm_operation_ctx * ctx)7185718399fSFrançois Tigeot static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
7195718399fSFrançois Tigeot 			       uint32_t mem_type,
7201cfef1a5SFrançois Tigeot 			       const struct ttm_place *place,
721*932d855eSSergey Zigachev 			       struct ttm_operation_ctx *ctx)
7225718399fSFrançois Tigeot {
7235718399fSFrançois Tigeot 	struct ttm_bo_global *glob = bdev->glob;
7245718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
725*932d855eSSergey Zigachev 	struct ttm_buffer_object *bo = NULL;
726*932d855eSSergey Zigachev 	bool locked = false;
727a85cb24fSFrançois Tigeot 	unsigned i;
728*932d855eSSergey Zigachev 	int ret = -EBUSY;
7295718399fSFrançois Tigeot 
7305718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
731a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
732a85cb24fSFrançois Tigeot 		list_for_each_entry(bo, &man->lru[i], lru) {
733*932d855eSSergey Zigachev 			if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked))
7344be47400SFrançois Tigeot 				continue;
7354be47400SFrançois Tigeot 
736a85cb24fSFrançois Tigeot 			if (place && !bdev->driver->eviction_valuable(bo,
737a85cb24fSFrançois Tigeot 								      place)) {
738*932d855eSSergey Zigachev 				if (locked)
7391cfef1a5SFrançois Tigeot 					__ttm_bo_unreserve(bo);
7401cfef1a5SFrançois Tigeot 				continue;
7411cfef1a5SFrançois Tigeot 			}
7425718399fSFrançois Tigeot 			break;
7435718399fSFrançois Tigeot 		}
7445718399fSFrançois Tigeot 
745*932d855eSSergey Zigachev 		/* If the inner loop terminated early, we have our candidate */
746*932d855eSSergey Zigachev 		if (&bo->lru != &man->lru[i])
747a85cb24fSFrançois Tigeot 			break;
748*932d855eSSergey Zigachev 
749*932d855eSSergey Zigachev 		bo = NULL;
750a85cb24fSFrançois Tigeot 	}
751a85cb24fSFrançois Tigeot 
752*932d855eSSergey Zigachev 	if (!bo) {
7535718399fSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_RELEASE);
754*932d855eSSergey Zigachev 		return -EBUSY;
7555718399fSFrançois Tigeot 	}
7565718399fSFrançois Tigeot 
757e3b244c9SFrançois Tigeot 	kref_get(&bo->list_kref);
7585718399fSFrançois Tigeot 
7595718399fSFrançois Tigeot 	if (!list_empty(&bo->ddestroy)) {
760*932d855eSSergey Zigachev 		ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
761*932d855eSSergey Zigachev 					  ctx->no_wait_gpu, locked);
762e3b244c9SFrançois Tigeot 		kref_put(&bo->list_kref, ttm_bo_release_list);
7635718399fSFrançois Tigeot 		return ret;
7645718399fSFrançois Tigeot 	}
7655718399fSFrançois Tigeot 
766a85cb24fSFrançois Tigeot 	ttm_bo_del_from_lru(bo);
7675718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
7685718399fSFrançois Tigeot 
769*932d855eSSergey Zigachev 	ret = ttm_bo_evict(bo, ctx);
770*932d855eSSergey Zigachev 	if (locked) {
7715718399fSFrançois Tigeot 		ttm_bo_unreserve(bo);
772*932d855eSSergey Zigachev 	} else {
773*932d855eSSergey Zigachev 		lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
774*932d855eSSergey Zigachev 		ttm_bo_add_to_lru(bo);
775*932d855eSSergey Zigachev 		lockmgr(&glob->lru_lock, LK_RELEASE);
776*932d855eSSergey Zigachev 	}
7775718399fSFrançois Tigeot 
778e3b244c9SFrançois Tigeot 	kref_put(&bo->list_kref, ttm_bo_release_list);
7795718399fSFrançois Tigeot 	return ret;
7805718399fSFrançois Tigeot }
7815718399fSFrançois Tigeot 
ttm_bo_mem_put(struct ttm_buffer_object * bo,struct ttm_mem_reg * mem)7825718399fSFrançois Tigeot void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
7835718399fSFrançois Tigeot {
7845718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
7855718399fSFrançois Tigeot 
7865718399fSFrançois Tigeot 	if (mem->mm_node)
7875718399fSFrançois Tigeot 		(*man->func->put_node)(man, mem);
7885718399fSFrançois Tigeot }
789c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_mem_put);
7905718399fSFrançois Tigeot 
7915718399fSFrançois Tigeot /**
7921dedbd3bSFrançois Tigeot  * Add the last move fence to the BO and reserve a new shared slot.
7931dedbd3bSFrançois Tigeot  */
ttm_bo_add_move_fence(struct ttm_buffer_object * bo,struct ttm_mem_type_manager * man,struct ttm_mem_reg * mem)7941dedbd3bSFrançois Tigeot static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
7951dedbd3bSFrançois Tigeot 				 struct ttm_mem_type_manager *man,
7961dedbd3bSFrançois Tigeot 				 struct ttm_mem_reg *mem)
7971dedbd3bSFrançois Tigeot {
7986559babbSFrançois Tigeot 	struct dma_fence *fence;
7991dedbd3bSFrançois Tigeot 	int ret;
8001dedbd3bSFrançois Tigeot 
801ec5b6af4SFrançois Tigeot 	lockmgr(&man->move_lock, LK_EXCLUSIVE);
8026559babbSFrançois Tigeot 	fence = dma_fence_get(man->move);
803ec5b6af4SFrançois Tigeot 	lockmgr(&man->move_lock, LK_RELEASE);
8041dedbd3bSFrançois Tigeot 
8051dedbd3bSFrançois Tigeot 	if (fence) {
8061dedbd3bSFrançois Tigeot 		reservation_object_add_shared_fence(bo->resv, fence);
8071dedbd3bSFrançois Tigeot 
8081dedbd3bSFrançois Tigeot 		ret = reservation_object_reserve_shared(bo->resv);
8091dedbd3bSFrançois Tigeot 		if (unlikely(ret))
8101dedbd3bSFrançois Tigeot 			return ret;
8111dedbd3bSFrançois Tigeot 
8126559babbSFrançois Tigeot 		dma_fence_put(bo->moving);
8131dedbd3bSFrançois Tigeot 		bo->moving = fence;
8141dedbd3bSFrançois Tigeot 	}
8151dedbd3bSFrançois Tigeot 
8161dedbd3bSFrançois Tigeot 	return 0;
8171dedbd3bSFrançois Tigeot }
8181dedbd3bSFrançois Tigeot 
8191dedbd3bSFrançois Tigeot /**
8205718399fSFrançois Tigeot  * Repeatedly evict memory from the LRU for @mem_type until we create enough
8215718399fSFrançois Tigeot  * space, or we've evicted everything and there isn't enough space.
8225718399fSFrançois Tigeot  */
ttm_bo_mem_force_space(struct ttm_buffer_object * bo,uint32_t mem_type,const struct ttm_place * place,struct ttm_mem_reg * mem,struct ttm_operation_ctx * ctx)8235718399fSFrançois Tigeot static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
8245718399fSFrançois Tigeot 					uint32_t mem_type,
8251cfef1a5SFrançois Tigeot 					const struct ttm_place *place,
8265718399fSFrançois Tigeot 					struct ttm_mem_reg *mem,
827*932d855eSSergey Zigachev 					struct ttm_operation_ctx *ctx)
8285718399fSFrançois Tigeot {
8295718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
8305718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
8315718399fSFrançois Tigeot 	int ret;
8325718399fSFrançois Tigeot 
8335718399fSFrançois Tigeot 	do {
8341cfef1a5SFrançois Tigeot 		ret = (*man->func->get_node)(man, bo, place, mem);
8355718399fSFrançois Tigeot 		if (unlikely(ret != 0))
8365718399fSFrançois Tigeot 			return ret;
8375718399fSFrançois Tigeot 		if (mem->mm_node)
8385718399fSFrançois Tigeot 			break;
839*932d855eSSergey Zigachev 		ret = ttm_mem_evict_first(bdev, mem_type, place, ctx);
8405718399fSFrançois Tigeot 		if (unlikely(ret != 0))
8415718399fSFrançois Tigeot 			return ret;
8425718399fSFrançois Tigeot 	} while (1);
8435718399fSFrançois Tigeot 	mem->mem_type = mem_type;
8441dedbd3bSFrançois Tigeot 	return ttm_bo_add_move_fence(bo, man, mem);
8455718399fSFrançois Tigeot }
8465718399fSFrançois Tigeot 
ttm_bo_select_caching(struct ttm_mem_type_manager * man,uint32_t cur_placement,uint32_t proposed_placement)8475718399fSFrançois Tigeot static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
8485718399fSFrançois Tigeot 				      uint32_t cur_placement,
8495718399fSFrançois Tigeot 				      uint32_t proposed_placement)
8505718399fSFrançois Tigeot {
8515718399fSFrançois Tigeot 	uint32_t caching = proposed_placement & TTM_PL_MASK_CACHING;
8525718399fSFrançois Tigeot 	uint32_t result = proposed_placement & ~TTM_PL_MASK_CACHING;
8535718399fSFrançois Tigeot 
8545718399fSFrançois Tigeot 	/**
8555718399fSFrançois Tigeot 	 * Keep current caching if possible.
8565718399fSFrançois Tigeot 	 */
8575718399fSFrançois Tigeot 
8585718399fSFrançois Tigeot 	if ((cur_placement & caching) != 0)
8595718399fSFrançois Tigeot 		result |= (cur_placement & caching);
8605718399fSFrançois Tigeot 	else if ((man->default_caching & caching) != 0)
8615718399fSFrançois Tigeot 		result |= man->default_caching;
8625718399fSFrançois Tigeot 	else if ((TTM_PL_FLAG_CACHED & caching) != 0)
8635718399fSFrançois Tigeot 		result |= TTM_PL_FLAG_CACHED;
8645718399fSFrançois Tigeot 	else if ((TTM_PL_FLAG_WC & caching) != 0)
8655718399fSFrançois Tigeot 		result |= TTM_PL_FLAG_WC;
8665718399fSFrançois Tigeot 	else if ((TTM_PL_FLAG_UNCACHED & caching) != 0)
8675718399fSFrançois Tigeot 		result |= TTM_PL_FLAG_UNCACHED;
8685718399fSFrançois Tigeot 
8695718399fSFrançois Tigeot 	return result;
8705718399fSFrançois Tigeot }
8715718399fSFrançois Tigeot 
ttm_bo_mt_compatible(struct ttm_mem_type_manager * man,uint32_t mem_type,const struct ttm_place * place,uint32_t * masked_placement)8725718399fSFrançois Tigeot static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
8735718399fSFrançois Tigeot 				 uint32_t mem_type,
874591d5043SFrançois Tigeot 				 const struct ttm_place *place,
8755718399fSFrançois Tigeot 				 uint32_t *masked_placement)
8765718399fSFrançois Tigeot {
8775718399fSFrançois Tigeot 	uint32_t cur_flags = ttm_bo_type_flags(mem_type);
8785718399fSFrançois Tigeot 
879591d5043SFrançois Tigeot 	if ((cur_flags & place->flags & TTM_PL_MASK_MEM) == 0)
8805718399fSFrançois Tigeot 		return false;
8815718399fSFrançois Tigeot 
882591d5043SFrançois Tigeot 	if ((place->flags & man->available_caching) == 0)
8835718399fSFrançois Tigeot 		return false;
8845718399fSFrançois Tigeot 
885591d5043SFrançois Tigeot 	cur_flags |= (place->flags & man->available_caching);
8865718399fSFrançois Tigeot 
8875718399fSFrançois Tigeot 	*masked_placement = cur_flags;
8885718399fSFrançois Tigeot 	return true;
8895718399fSFrançois Tigeot }
8905718399fSFrançois Tigeot 
8915718399fSFrançois Tigeot /**
8925718399fSFrançois Tigeot  * Creates space for memory region @mem according to its type.
8935718399fSFrançois Tigeot  *
8945718399fSFrançois Tigeot  * This function first searches for free space in compatible memory types in
8955718399fSFrançois Tigeot  * the priority order defined by the driver.  If free space isn't found, then
8965718399fSFrançois Tigeot  * ttm_bo_mem_force_space is attempted in priority order to evict and find
8975718399fSFrançois Tigeot  * space.
8985718399fSFrançois Tigeot  */
ttm_bo_mem_space(struct ttm_buffer_object * bo,struct ttm_placement * placement,struct ttm_mem_reg * mem,struct ttm_operation_ctx * ctx)8995718399fSFrançois Tigeot int ttm_bo_mem_space(struct ttm_buffer_object *bo,
9005718399fSFrançois Tigeot 			struct ttm_placement *placement,
9015718399fSFrançois Tigeot 			struct ttm_mem_reg *mem,
902*932d855eSSergey Zigachev 			struct ttm_operation_ctx *ctx)
9035718399fSFrançois Tigeot {
9045718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
9055718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man;
9065718399fSFrançois Tigeot 	uint32_t mem_type = TTM_PL_SYSTEM;
9075718399fSFrançois Tigeot 	uint32_t cur_flags = 0;
9085718399fSFrançois Tigeot 	bool type_found = false;
9095718399fSFrançois Tigeot 	bool type_ok = false;
9105718399fSFrançois Tigeot 	bool has_erestartsys = false;
9115718399fSFrançois Tigeot 	int i, ret;
9125718399fSFrançois Tigeot 
9131dedbd3bSFrançois Tigeot 	ret = reservation_object_reserve_shared(bo->resv);
9141dedbd3bSFrançois Tigeot 	if (unlikely(ret))
9151dedbd3bSFrançois Tigeot 		return ret;
9161dedbd3bSFrançois Tigeot 
9175718399fSFrançois Tigeot 	mem->mm_node = NULL;
9185718399fSFrançois Tigeot 	for (i = 0; i < placement->num_placement; ++i) {
9191cfef1a5SFrançois Tigeot 		const struct ttm_place *place = &placement->placement[i];
9201cfef1a5SFrançois Tigeot 
9211cfef1a5SFrançois Tigeot 		ret = ttm_mem_type_from_place(place, &mem_type);
9225718399fSFrançois Tigeot 		if (ret)
9235718399fSFrançois Tigeot 			return ret;
9245718399fSFrançois Tigeot 		man = &bdev->man[mem_type];
925c59a5c48SFrançois Tigeot 		if (!man->has_type || !man->use_type)
926c59a5c48SFrançois Tigeot 			continue;
9275718399fSFrançois Tigeot 
9281cfef1a5SFrançois Tigeot 		type_ok = ttm_bo_mt_compatible(man, mem_type, place,
9295718399fSFrançois Tigeot 						&cur_flags);
9305718399fSFrançois Tigeot 
9315718399fSFrançois Tigeot 		if (!type_ok)
9325718399fSFrançois Tigeot 			continue;
9335718399fSFrançois Tigeot 
934c59a5c48SFrançois Tigeot 		type_found = true;
9355718399fSFrançois Tigeot 		cur_flags = ttm_bo_select_caching(man, bo->mem.placement,
9365718399fSFrançois Tigeot 						  cur_flags);
9375718399fSFrançois Tigeot 		/*
9385718399fSFrançois Tigeot 		 * Use the access and other non-mapping-related flag bits from
9395718399fSFrançois Tigeot 		 * the memory placement flags to the current flags
9405718399fSFrançois Tigeot 		 */
9411cfef1a5SFrançois Tigeot 		ttm_flag_masked(&cur_flags, place->flags,
9425718399fSFrançois Tigeot 				~TTM_PL_MASK_MEMTYPE);
9435718399fSFrançois Tigeot 
9445718399fSFrançois Tigeot 		if (mem_type == TTM_PL_SYSTEM)
9455718399fSFrançois Tigeot 			break;
9465718399fSFrançois Tigeot 
9471cfef1a5SFrançois Tigeot 		ret = (*man->func->get_node)(man, bo, place, mem);
9485718399fSFrançois Tigeot 		if (unlikely(ret))
9495718399fSFrançois Tigeot 			return ret;
950c59a5c48SFrançois Tigeot 
9511dedbd3bSFrançois Tigeot 		if (mem->mm_node) {
9521dedbd3bSFrançois Tigeot 			ret = ttm_bo_add_move_fence(bo, man, mem);
9531dedbd3bSFrançois Tigeot 			if (unlikely(ret)) {
9541dedbd3bSFrançois Tigeot 				(*man->func->put_node)(man, mem);
9551dedbd3bSFrançois Tigeot 				return ret;
9561dedbd3bSFrançois Tigeot 			}
9575718399fSFrançois Tigeot 			break;
9585718399fSFrançois Tigeot 		}
9591dedbd3bSFrançois Tigeot 	}
9605718399fSFrançois Tigeot 
9615718399fSFrançois Tigeot 	if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || mem->mm_node) {
9625718399fSFrançois Tigeot 		mem->mem_type = mem_type;
9635718399fSFrançois Tigeot 		mem->placement = cur_flags;
9645718399fSFrançois Tigeot 		return 0;
9655718399fSFrançois Tigeot 	}
9665718399fSFrançois Tigeot 
9675718399fSFrançois Tigeot 	for (i = 0; i < placement->num_busy_placement; ++i) {
9681cfef1a5SFrançois Tigeot 		const struct ttm_place *place = &placement->busy_placement[i];
9691cfef1a5SFrançois Tigeot 
9701cfef1a5SFrançois Tigeot 		ret = ttm_mem_type_from_place(place, &mem_type);
9715718399fSFrançois Tigeot 		if (ret)
9725718399fSFrançois Tigeot 			return ret;
9735718399fSFrançois Tigeot 		man = &bdev->man[mem_type];
974c59a5c48SFrançois Tigeot 		if (!man->has_type || !man->use_type)
9755718399fSFrançois Tigeot 			continue;
9761cfef1a5SFrançois Tigeot 		if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags))
9775718399fSFrançois Tigeot 			continue;
9785718399fSFrançois Tigeot 
979c59a5c48SFrançois Tigeot 		type_found = true;
9805718399fSFrançois Tigeot 		cur_flags = ttm_bo_select_caching(man, bo->mem.placement,
9815718399fSFrançois Tigeot 						  cur_flags);
9825718399fSFrançois Tigeot 		/*
9835718399fSFrançois Tigeot 		 * Use the access and other non-mapping-related flag bits from
9845718399fSFrançois Tigeot 		 * the memory placement flags to the current flags
9855718399fSFrançois Tigeot 		 */
9861cfef1a5SFrançois Tigeot 		ttm_flag_masked(&cur_flags, place->flags,
9875718399fSFrançois Tigeot 				~TTM_PL_MASK_MEMTYPE);
9885718399fSFrançois Tigeot 
9895718399fSFrançois Tigeot 		if (mem_type == TTM_PL_SYSTEM) {
9905718399fSFrançois Tigeot 			mem->mem_type = mem_type;
9915718399fSFrançois Tigeot 			mem->placement = cur_flags;
9925718399fSFrançois Tigeot 			mem->mm_node = NULL;
9935718399fSFrançois Tigeot 			return 0;
9945718399fSFrançois Tigeot 		}
9955718399fSFrançois Tigeot 
996*932d855eSSergey Zigachev 		ret = ttm_bo_mem_force_space(bo, mem_type, place, mem, ctx);
9975718399fSFrançois Tigeot 		if (ret == 0 && mem->mm_node) {
9985718399fSFrançois Tigeot 			mem->placement = cur_flags;
9995718399fSFrançois Tigeot 			return 0;
10005718399fSFrançois Tigeot 		}
1001797013cfSFrançois Tigeot 		if (ret == -ERESTARTSYS)
10025718399fSFrançois Tigeot 			has_erestartsys = true;
10035718399fSFrançois Tigeot 	}
1004c59a5c48SFrançois Tigeot 
1005c59a5c48SFrançois Tigeot 	if (!type_found) {
1006a85cb24fSFrançois Tigeot 		pr_err(TTM_PFX "No compatible memory type found\n");
1007c59a5c48SFrançois Tigeot 		return -EINVAL;
1008c59a5c48SFrançois Tigeot 	}
1009c59a5c48SFrançois Tigeot 
1010c59a5c48SFrançois Tigeot 	return (has_erestartsys) ? -ERESTARTSYS : -ENOMEM;
10115718399fSFrançois Tigeot }
1012c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_mem_space);
10135718399fSFrançois Tigeot 
ttm_bo_move_buffer(struct ttm_buffer_object * bo,struct ttm_placement * placement,struct ttm_operation_ctx * ctx)1014c6f73aabSFrançois Tigeot static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
10155718399fSFrançois Tigeot 			      struct ttm_placement *placement,
1016*932d855eSSergey Zigachev 			      struct ttm_operation_ctx *ctx)
10175718399fSFrançois Tigeot {
10185718399fSFrançois Tigeot 	int ret = 0;
10195718399fSFrançois Tigeot 	struct ttm_mem_reg mem;
10205718399fSFrançois Tigeot 
1021189951a7SFrançois Tigeot 	lockdep_assert_held(&bo->resv->lock.base);
10225718399fSFrançois Tigeot 
10235718399fSFrançois Tigeot 	mem.num_pages = bo->num_pages;
10245718399fSFrançois Tigeot 	mem.size = mem.num_pages << PAGE_SHIFT;
10255718399fSFrançois Tigeot 	mem.page_alignment = bo->mem.page_alignment;
10265718399fSFrançois Tigeot 	mem.bus.io_reserved_vm = false;
10275718399fSFrançois Tigeot 	mem.bus.io_reserved_count = 0;
10285718399fSFrançois Tigeot 	/*
10295718399fSFrançois Tigeot 	 * Determine where to move the buffer.
10305718399fSFrançois Tigeot 	 */
1031*932d855eSSergey Zigachev 	ret = ttm_bo_mem_space(bo, placement, &mem, ctx);
10325718399fSFrançois Tigeot 	if (ret)
10335718399fSFrançois Tigeot 		goto out_unlock;
1034*932d855eSSergey Zigachev 	ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx);
10355718399fSFrançois Tigeot out_unlock:
10365718399fSFrançois Tigeot 	if (ret && mem.mm_node)
10375718399fSFrançois Tigeot 		ttm_bo_mem_put(bo, &mem);
10385718399fSFrançois Tigeot 	return ret;
10395718399fSFrançois Tigeot }
10405718399fSFrançois Tigeot 
ttm_bo_places_compat(const struct ttm_place * places,unsigned num_placement,struct ttm_mem_reg * mem,uint32_t * new_flags)1041a85cb24fSFrançois Tigeot static bool ttm_bo_places_compat(const struct ttm_place *places,
1042a85cb24fSFrançois Tigeot 				 unsigned num_placement,
1043a85cb24fSFrançois Tigeot 				 struct ttm_mem_reg *mem,
1044a85cb24fSFrançois Tigeot 				 uint32_t *new_flags)
1045a85cb24fSFrançois Tigeot {
1046a85cb24fSFrançois Tigeot 	unsigned i;
1047a85cb24fSFrançois Tigeot 
1048a85cb24fSFrançois Tigeot 	for (i = 0; i < num_placement; i++) {
1049a85cb24fSFrançois Tigeot 		const struct ttm_place *heap = &places[i];
1050a85cb24fSFrançois Tigeot 
1051a85cb24fSFrançois Tigeot 		if (mem->mm_node && (mem->start < heap->fpfn ||
1052a85cb24fSFrançois Tigeot 		     (heap->lpfn != 0 && (mem->start + mem->num_pages) > heap->lpfn)))
1053a85cb24fSFrançois Tigeot 			continue;
1054a85cb24fSFrançois Tigeot 
1055a85cb24fSFrançois Tigeot 		*new_flags = heap->flags;
1056a85cb24fSFrançois Tigeot 		if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
1057a85cb24fSFrançois Tigeot 		    (*new_flags & mem->placement & TTM_PL_MASK_MEM) &&
1058a85cb24fSFrançois Tigeot 		    (!(*new_flags & TTM_PL_FLAG_CONTIGUOUS) ||
1059a85cb24fSFrançois Tigeot 		     (mem->placement & TTM_PL_FLAG_CONTIGUOUS)))
1060a85cb24fSFrançois Tigeot 			return true;
1061a85cb24fSFrançois Tigeot 	}
1062a85cb24fSFrançois Tigeot 	return false;
1063a85cb24fSFrançois Tigeot }
1064a85cb24fSFrançois Tigeot 
ttm_bo_mem_compat(struct ttm_placement * placement,struct ttm_mem_reg * mem,uint32_t * new_flags)1065c59a5c48SFrançois Tigeot bool ttm_bo_mem_compat(struct ttm_placement *placement,
10661cfef1a5SFrançois Tigeot 		       struct ttm_mem_reg *mem,
10671cfef1a5SFrançois Tigeot 		       uint32_t *new_flags)
10685718399fSFrançois Tigeot {
1069a85cb24fSFrançois Tigeot 	if (ttm_bo_places_compat(placement->placement, placement->num_placement,
1070a85cb24fSFrançois Tigeot 				 mem, new_flags))
10711cfef1a5SFrançois Tigeot 		return true;
10721cfef1a5SFrançois Tigeot 
1073a85cb24fSFrançois Tigeot 	if ((placement->busy_placement != placement->placement ||
1074a85cb24fSFrançois Tigeot 	     placement->num_busy_placement > placement->num_placement) &&
1075a85cb24fSFrançois Tigeot 	    ttm_bo_places_compat(placement->busy_placement,
1076a85cb24fSFrançois Tigeot 				 placement->num_busy_placement,
1077a85cb24fSFrançois Tigeot 				 mem, new_flags))
10781cfef1a5SFrançois Tigeot 		return true;
10791cfef1a5SFrançois Tigeot 
10801cfef1a5SFrançois Tigeot 	return false;
10815718399fSFrançois Tigeot }
1082d78d3a22SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_mem_compat);
10835718399fSFrançois Tigeot 
ttm_bo_validate(struct ttm_buffer_object * bo,struct ttm_placement * placement,struct ttm_operation_ctx * ctx)10845718399fSFrançois Tigeot int ttm_bo_validate(struct ttm_buffer_object *bo,
10855718399fSFrançois Tigeot 		    struct ttm_placement *placement,
1086*932d855eSSergey Zigachev 		    struct ttm_operation_ctx *ctx)
10875718399fSFrançois Tigeot {
10885718399fSFrançois Tigeot 	int ret;
10891cfef1a5SFrançois Tigeot 	uint32_t new_flags;
10905718399fSFrançois Tigeot 
1091189951a7SFrançois Tigeot 	lockdep_assert_held(&bo->resv->lock.base);
10925718399fSFrançois Tigeot 	/*
10935718399fSFrançois Tigeot 	 * Check whether we need to move buffer.
10945718399fSFrançois Tigeot 	 */
10951cfef1a5SFrançois Tigeot 	if (!ttm_bo_mem_compat(placement, &bo->mem, &new_flags)) {
1096*932d855eSSergey Zigachev 		ret = ttm_bo_move_buffer(bo, placement, ctx);
10975718399fSFrançois Tigeot 		if (ret)
10985718399fSFrançois Tigeot 			return ret;
10995718399fSFrançois Tigeot 	} else {
11005718399fSFrançois Tigeot 		/*
11015718399fSFrançois Tigeot 		 * Use the access and other non-mapping-related flag bits from
11025718399fSFrançois Tigeot 		 * the compatible memory placement flags to the active flags
11035718399fSFrançois Tigeot 		 */
11041cfef1a5SFrançois Tigeot 		ttm_flag_masked(&bo->mem.placement, new_flags,
11055718399fSFrançois Tigeot 				~TTM_PL_MASK_MEMTYPE);
11065718399fSFrançois Tigeot 	}
11075718399fSFrançois Tigeot 	/*
11085718399fSFrançois Tigeot 	 * We might need to add a TTM.
11095718399fSFrançois Tigeot 	 */
11105718399fSFrançois Tigeot 	if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
1111*932d855eSSergey Zigachev 		ret = ttm_tt_create(bo, true);
11125718399fSFrançois Tigeot 		if (ret)
11135718399fSFrançois Tigeot 			return ret;
11145718399fSFrançois Tigeot 	}
11155718399fSFrançois Tigeot 	return 0;
11165718399fSFrançois Tigeot }
1117c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_validate);
11185718399fSFrançois Tigeot 
ttm_bo_init_reserved(struct ttm_bo_device * bdev,struct ttm_buffer_object * bo,unsigned long size,enum ttm_bo_type type,struct ttm_placement * placement,uint32_t page_alignment,struct ttm_operation_ctx * ctx,size_t acc_size,struct sg_table * sg,struct reservation_object * resv,void (* destroy)(struct ttm_buffer_object *))1119a85cb24fSFrançois Tigeot int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
11205718399fSFrançois Tigeot 			 struct ttm_buffer_object *bo,
11215718399fSFrançois Tigeot 			 unsigned long size,
11225718399fSFrançois Tigeot 			 enum ttm_bo_type type,
11235718399fSFrançois Tigeot 			 struct ttm_placement *placement,
11245718399fSFrançois Tigeot 			 uint32_t page_alignment,
1125*932d855eSSergey Zigachev 			 struct ttm_operation_ctx *ctx,
11265718399fSFrançois Tigeot 			 size_t acc_size,
11275718399fSFrançois Tigeot 			 struct sg_table *sg,
11281cfef1a5SFrançois Tigeot 			 struct reservation_object *resv,
11295718399fSFrançois Tigeot 			 void (*destroy) (struct ttm_buffer_object *))
11305718399fSFrançois Tigeot {
11315718399fSFrançois Tigeot 	int ret = 0;
11325718399fSFrançois Tigeot 	unsigned long num_pages;
11335718399fSFrançois Tigeot 	struct ttm_mem_global *mem_glob = bdev->glob->mem_glob;
11343c3b358eSFrançois Tigeot 	bool locked;
11355718399fSFrançois Tigeot 
1136*932d855eSSergey Zigachev 	ret = ttm_mem_global_alloc(mem_glob, acc_size, ctx);
11375718399fSFrançois Tigeot 	if (ret) {
11380bece63dSImre Vadasz 		pr_err("Out of kernel memory\n");
11395718399fSFrançois Tigeot 		if (destroy)
11405718399fSFrançois Tigeot 			(*destroy)(bo);
11415718399fSFrançois Tigeot 		else
1142158486a6SFrançois Tigeot 			kfree(bo);
11435718399fSFrançois Tigeot 		return -ENOMEM;
11445718399fSFrançois Tigeot 	}
11455718399fSFrançois Tigeot 
11465718399fSFrançois Tigeot 	num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
11475718399fSFrançois Tigeot 	if (num_pages == 0) {
11480bece63dSImre Vadasz 		pr_err("Illegal buffer object size\n");
11495718399fSFrançois Tigeot 		if (destroy)
11505718399fSFrançois Tigeot 			(*destroy)(bo);
11515718399fSFrançois Tigeot 		else
1152158486a6SFrançois Tigeot 			kfree(bo);
11535718399fSFrançois Tigeot 		ttm_mem_global_free(mem_glob, acc_size);
11545718399fSFrançois Tigeot 		return -EINVAL;
11555718399fSFrançois Tigeot 	}
1156*932d855eSSergey Zigachev 	bo->destroy = destroy ? destroy : ttm_bo_default_destroy;
11575718399fSFrançois Tigeot 
1158e3b244c9SFrançois Tigeot 	kref_init(&bo->kref);
1159e3b244c9SFrançois Tigeot 	kref_init(&bo->list_kref);
11605718399fSFrançois Tigeot 	atomic_set(&bo->cpu_writers, 0);
11615718399fSFrançois Tigeot 	INIT_LIST_HEAD(&bo->lru);
11625718399fSFrançois Tigeot 	INIT_LIST_HEAD(&bo->ddestroy);
11635718399fSFrançois Tigeot 	INIT_LIST_HEAD(&bo->swap);
11645718399fSFrançois Tigeot 	INIT_LIST_HEAD(&bo->io_reserve_lru);
116543e748b9SFrançois Tigeot 	lockinit(&bo->wu_mutex, "ttmbwm", 0, LK_CANRECURSE);
11665718399fSFrançois Tigeot 	bo->bdev = bdev;
11675718399fSFrançois Tigeot 	bo->type = type;
11685718399fSFrançois Tigeot 	bo->num_pages = num_pages;
11695718399fSFrançois Tigeot 	bo->mem.size = num_pages << PAGE_SHIFT;
11705718399fSFrançois Tigeot 	bo->mem.mem_type = TTM_PL_SYSTEM;
11715718399fSFrançois Tigeot 	bo->mem.num_pages = bo->num_pages;
11725718399fSFrançois Tigeot 	bo->mem.mm_node = NULL;
11735718399fSFrançois Tigeot 	bo->mem.page_alignment = page_alignment;
11745718399fSFrançois Tigeot 	bo->mem.bus.io_reserved_vm = false;
11755718399fSFrançois Tigeot 	bo->mem.bus.io_reserved_count = 0;
11761dedbd3bSFrançois Tigeot 	bo->moving = NULL;
11775718399fSFrançois Tigeot 	bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
11785718399fSFrançois Tigeot 	bo->acc_size = acc_size;
11795718399fSFrançois Tigeot 	bo->sg = sg;
11801cfef1a5SFrançois Tigeot 	if (resv) {
11811cfef1a5SFrançois Tigeot 		bo->resv = resv;
11821cfef1a5SFrançois Tigeot 		lockdep_assert_held(&bo->resv->lock.base);
11831cfef1a5SFrançois Tigeot 	} else {
11843c3b358eSFrançois Tigeot 		bo->resv = &bo->ttm_resv;
11851cfef1a5SFrançois Tigeot 	}
11863f2dd94aSFrançois Tigeot 	reservation_object_init(&bo->ttm_resv);
1187*932d855eSSergey Zigachev 	atomic_inc(&bo->bdev->glob->bo_count);
1188a34b4168SMatthew Dillon 	drm_vma_node_reset(&bo->vma_node);
1189a85cb24fSFrançois Tigeot 	bo->priority = 0;
11905718399fSFrançois Tigeot 
11915718399fSFrançois Tigeot 	/*
11925718399fSFrançois Tigeot 	 * For ttm_bo_type_device buffers, allocate
11935718399fSFrançois Tigeot 	 * address space from the device.
11945718399fSFrançois Tigeot 	 */
11951cfef1a5SFrançois Tigeot 	if (bo->type == ttm_bo_type_device ||
11961cfef1a5SFrançois Tigeot 	    bo->type == ttm_bo_type_sg)
119743e748b9SFrançois Tigeot 		ret = drm_vma_offset_add(&bdev->vma_manager, &bo->vma_node,
119843e748b9SFrançois Tigeot 					 bo->mem.num_pages);
11995718399fSFrançois Tigeot 
12001cfef1a5SFrançois Tigeot 	/* passed reservation objects should already be locked,
12011cfef1a5SFrançois Tigeot 	 * since otherwise lockdep will be angered in radeon.
12021cfef1a5SFrançois Tigeot 	 */
12031cfef1a5SFrançois Tigeot 	if (!resv) {
12043c3b358eSFrançois Tigeot 		locked = ww_mutex_trylock(&bo->resv->lock);
12053c3b358eSFrançois Tigeot 		WARN_ON(!locked);
12061cfef1a5SFrançois Tigeot 	}
120729bffcd3SFrançois Tigeot 
12083c3b358eSFrançois Tigeot 	if (likely(!ret))
1209*932d855eSSergey Zigachev 		ret = ttm_bo_validate(bo, placement, ctx);
12105718399fSFrançois Tigeot 
1211a85cb24fSFrançois Tigeot 	if (unlikely(ret)) {
1212a85cb24fSFrançois Tigeot 		if (!resv)
12135718399fSFrançois Tigeot 			ttm_bo_unreserve(bo);
12143c3b358eSFrançois Tigeot 
1215*932d855eSSergey Zigachev 		ttm_bo_put(bo);
1216a85cb24fSFrançois Tigeot 		return ret;
1217a85cb24fSFrançois Tigeot 	}
1218a85cb24fSFrançois Tigeot 
1219a85cb24fSFrançois Tigeot 	if (resv && !(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
1220*932d855eSSergey Zigachev 		lockmgr(&bdev->glob->lru_lock, LK_EXCLUSIVE);
1221d78d3a22SFrançois Tigeot 		ttm_bo_add_to_lru(bo);
1222*932d855eSSergey Zigachev 		lockmgr(&bdev->glob->lru_lock, LK_RELEASE);
1223d78d3a22SFrançois Tigeot 	}
1224d78d3a22SFrançois Tigeot 
12255718399fSFrançois Tigeot 	return ret;
12265718399fSFrançois Tigeot }
1227a85cb24fSFrançois Tigeot EXPORT_SYMBOL(ttm_bo_init_reserved);
1228a85cb24fSFrançois Tigeot 
ttm_bo_init(struct ttm_bo_device * bdev,struct ttm_buffer_object * bo,unsigned long size,enum ttm_bo_type type,struct ttm_placement * placement,uint32_t page_alignment,bool interruptible,size_t acc_size,struct sg_table * sg,struct reservation_object * resv,void (* destroy)(struct ttm_buffer_object *))1229a85cb24fSFrançois Tigeot int ttm_bo_init(struct ttm_bo_device *bdev,
1230a85cb24fSFrançois Tigeot 		struct ttm_buffer_object *bo,
1231a85cb24fSFrançois Tigeot 		unsigned long size,
1232a85cb24fSFrançois Tigeot 		enum ttm_bo_type type,
1233a85cb24fSFrançois Tigeot 		struct ttm_placement *placement,
1234a85cb24fSFrançois Tigeot 		uint32_t page_alignment,
1235a85cb24fSFrançois Tigeot 		bool interruptible,
1236a85cb24fSFrançois Tigeot 		size_t acc_size,
1237a85cb24fSFrançois Tigeot 		struct sg_table *sg,
1238a85cb24fSFrançois Tigeot 		struct reservation_object *resv,
1239a85cb24fSFrançois Tigeot 		void (*destroy) (struct ttm_buffer_object *))
1240a85cb24fSFrançois Tigeot {
1241*932d855eSSergey Zigachev 	struct ttm_operation_ctx ctx = { interruptible, false };
1242a85cb24fSFrançois Tigeot 	int ret;
1243a85cb24fSFrançois Tigeot 
1244a85cb24fSFrançois Tigeot 	ret = ttm_bo_init_reserved(bdev, bo, size, type, placement,
1245*932d855eSSergey Zigachev 				   page_alignment, &ctx, acc_size,
1246a85cb24fSFrançois Tigeot 				   sg, resv, destroy);
1247a85cb24fSFrançois Tigeot 	if (ret)
1248a85cb24fSFrançois Tigeot 		return ret;
1249a85cb24fSFrançois Tigeot 
1250a85cb24fSFrançois Tigeot 	if (!resv)
1251a85cb24fSFrançois Tigeot 		ttm_bo_unreserve(bo);
1252a85cb24fSFrançois Tigeot 
1253a85cb24fSFrançois Tigeot 	return 0;
1254a85cb24fSFrançois Tigeot }
1255c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_init);
12565718399fSFrançois Tigeot 
ttm_bo_acc_size(struct ttm_bo_device * bdev,unsigned long bo_size,unsigned struct_size)12575718399fSFrançois Tigeot size_t ttm_bo_acc_size(struct ttm_bo_device *bdev,
12585718399fSFrançois Tigeot 		       unsigned long bo_size,
12595718399fSFrançois Tigeot 		       unsigned struct_size)
12605718399fSFrançois Tigeot {
12615718399fSFrançois Tigeot 	unsigned npages = (PAGE_ALIGN(bo_size)) >> PAGE_SHIFT;
12625718399fSFrançois Tigeot 	size_t size = 0;
12635718399fSFrançois Tigeot 
12645718399fSFrançois Tigeot 	size += ttm_round_pot(struct_size);
1265d78d3a22SFrançois Tigeot 	size += ttm_round_pot(npages * sizeof(void *));
12665718399fSFrançois Tigeot 	size += ttm_round_pot(sizeof(struct ttm_tt));
12675718399fSFrançois Tigeot 	return size;
12685718399fSFrançois Tigeot }
1269c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_acc_size);
12705718399fSFrançois Tigeot 
ttm_bo_dma_acc_size(struct ttm_bo_device * bdev,unsigned long bo_size,unsigned struct_size)12715718399fSFrançois Tigeot size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev,
12725718399fSFrançois Tigeot 			   unsigned long bo_size,
12735718399fSFrançois Tigeot 			   unsigned struct_size)
12745718399fSFrançois Tigeot {
12755718399fSFrançois Tigeot 	unsigned npages = (PAGE_ALIGN(bo_size)) >> PAGE_SHIFT;
12765718399fSFrançois Tigeot 	size_t size = 0;
12775718399fSFrançois Tigeot 
12785718399fSFrançois Tigeot 	size += ttm_round_pot(struct_size);
1279d78d3a22SFrançois Tigeot 	size += ttm_round_pot(npages * (2*sizeof(void *) + sizeof(dma_addr_t)));
12805718399fSFrançois Tigeot 	size += ttm_round_pot(sizeof(struct ttm_dma_tt));
12815718399fSFrançois Tigeot 	return size;
12825718399fSFrançois Tigeot }
1283c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_dma_acc_size);
12845718399fSFrançois Tigeot 
ttm_bo_create(struct ttm_bo_device * bdev,unsigned long size,enum ttm_bo_type type,struct ttm_placement * placement,uint32_t page_alignment,bool interruptible,struct ttm_buffer_object ** p_bo)12855718399fSFrançois Tigeot int ttm_bo_create(struct ttm_bo_device *bdev,
12865718399fSFrançois Tigeot 			unsigned long size,
12875718399fSFrançois Tigeot 			enum ttm_bo_type type,
12885718399fSFrançois Tigeot 			struct ttm_placement *placement,
12895718399fSFrançois Tigeot 			uint32_t page_alignment,
12905718399fSFrançois Tigeot 			bool interruptible,
12915718399fSFrançois Tigeot 			struct ttm_buffer_object **p_bo)
12925718399fSFrançois Tigeot {
12935718399fSFrançois Tigeot 	struct ttm_buffer_object *bo;
12945718399fSFrançois Tigeot 	size_t acc_size;
12955718399fSFrançois Tigeot 	int ret;
12965718399fSFrançois Tigeot 
1297175896dfSzrj 	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
1298c19c6249SFrançois Tigeot 	if (unlikely(bo == NULL))
1299c19c6249SFrançois Tigeot 		return -ENOMEM;
1300c19c6249SFrançois Tigeot 
13015718399fSFrançois Tigeot 	acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object));
13025718399fSFrançois Tigeot 	ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment,
1303*932d855eSSergey Zigachev 			  interruptible, acc_size,
13041cfef1a5SFrançois Tigeot 			  NULL, NULL, NULL);
13055718399fSFrançois Tigeot 	if (likely(ret == 0))
13065718399fSFrançois Tigeot 		*p_bo = bo;
13075718399fSFrançois Tigeot 
13085718399fSFrançois Tigeot 	return ret;
13095718399fSFrançois Tigeot }
1310c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_create);
13115718399fSFrançois Tigeot 
ttm_bo_force_list_clean(struct ttm_bo_device * bdev,unsigned mem_type)13125718399fSFrançois Tigeot static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
1313a85cb24fSFrançois Tigeot 				   unsigned mem_type)
13145718399fSFrançois Tigeot {
1315*932d855eSSergey Zigachev 	struct ttm_operation_ctx ctx = {
1316*932d855eSSergey Zigachev 		.interruptible = false,
1317*932d855eSSergey Zigachev 		.no_wait_gpu = false,
1318*932d855eSSergey Zigachev 		.flags = TTM_OPT_FLAG_FORCE_ALLOC
1319*932d855eSSergey Zigachev 	};
13205718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
13215718399fSFrançois Tigeot 	struct ttm_bo_global *glob = bdev->glob;
13226559babbSFrançois Tigeot 	struct dma_fence *fence;
13235718399fSFrançois Tigeot 	int ret;
1324a85cb24fSFrançois Tigeot 	unsigned i;
13255718399fSFrançois Tigeot 
13265718399fSFrançois Tigeot 	/*
13275718399fSFrançois Tigeot 	 * Can't use standard list traversal since we're unlocking.
13285718399fSFrançois Tigeot 	 */
13295718399fSFrançois Tigeot 
13305718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
1331a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
1332a85cb24fSFrançois Tigeot 		while (!list_empty(&man->lru[i])) {
13335718399fSFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_RELEASE);
1334*932d855eSSergey Zigachev 			ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx);
1335a85cb24fSFrançois Tigeot 			if (ret)
13365718399fSFrançois Tigeot 				return ret;
13375718399fSFrançois Tigeot 			lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
13385718399fSFrançois Tigeot 		}
1339a85cb24fSFrançois Tigeot 	}
13405718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
13411dedbd3bSFrançois Tigeot 
1342ec5b6af4SFrançois Tigeot 	lockmgr(&man->move_lock, LK_EXCLUSIVE);
13436559babbSFrançois Tigeot 	fence = dma_fence_get(man->move);
1344ec5b6af4SFrançois Tigeot 	lockmgr(&man->move_lock, LK_RELEASE);
13451dedbd3bSFrançois Tigeot 
13461dedbd3bSFrançois Tigeot 	if (fence) {
13476559babbSFrançois Tigeot 		ret = dma_fence_wait(fence, false);
13486559babbSFrançois Tigeot 		dma_fence_put(fence);
1349a85cb24fSFrançois Tigeot 		if (ret)
13501dedbd3bSFrançois Tigeot 			return ret;
13511dedbd3bSFrançois Tigeot 	}
13521dedbd3bSFrançois Tigeot 
13535718399fSFrançois Tigeot 	return 0;
13545718399fSFrançois Tigeot }
13555718399fSFrançois Tigeot 
ttm_bo_clean_mm(struct ttm_bo_device * bdev,unsigned mem_type)13565718399fSFrançois Tigeot int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
13575718399fSFrançois Tigeot {
13585718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man;
13595718399fSFrançois Tigeot 	int ret = -EINVAL;
13605718399fSFrançois Tigeot 
13615718399fSFrançois Tigeot 	if (mem_type >= TTM_NUM_MEM_TYPES) {
13620bece63dSImre Vadasz 		pr_err("Illegal memory type %d\n", mem_type);
13635718399fSFrançois Tigeot 		return ret;
13645718399fSFrançois Tigeot 	}
13655718399fSFrançois Tigeot 	man = &bdev->man[mem_type];
13665718399fSFrançois Tigeot 
13675718399fSFrançois Tigeot 	if (!man->has_type) {
13680bece63dSImre Vadasz 		pr_err("Trying to take down uninitialized memory manager type %u\n",
13695718399fSFrançois Tigeot 		       mem_type);
13705718399fSFrançois Tigeot 		return ret;
13715718399fSFrançois Tigeot 	}
13725718399fSFrançois Tigeot 
13735718399fSFrançois Tigeot 	man->use_type = false;
13745718399fSFrançois Tigeot 	man->has_type = false;
13755718399fSFrançois Tigeot 
13765718399fSFrançois Tigeot 	ret = 0;
13775718399fSFrançois Tigeot 	if (mem_type > 0) {
1378a85cb24fSFrançois Tigeot 		ret = ttm_bo_force_list_clean(bdev, mem_type);
1379a85cb24fSFrançois Tigeot 		if (ret) {
1380a85cb24fSFrançois Tigeot 			pr_err("Cleanup eviction failed\n");
1381a85cb24fSFrançois Tigeot 			return ret;
1382a85cb24fSFrançois Tigeot 		}
13835718399fSFrançois Tigeot 
13845718399fSFrançois Tigeot 		ret = (*man->func->takedown)(man);
13855718399fSFrançois Tigeot 	}
13865718399fSFrançois Tigeot 
1387a85cb24fSFrançois Tigeot 	dma_fence_put(man->move);
1388a85cb24fSFrançois Tigeot 	man->move = NULL;
1389a85cb24fSFrançois Tigeot 
13905718399fSFrançois Tigeot 	return ret;
13915718399fSFrançois Tigeot }
1392c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_clean_mm);
13935718399fSFrançois Tigeot 
ttm_bo_evict_mm(struct ttm_bo_device * bdev,unsigned mem_type)13945718399fSFrançois Tigeot int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type)
13955718399fSFrançois Tigeot {
13965718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
13975718399fSFrançois Tigeot 
13985718399fSFrançois Tigeot 	if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) {
13990bece63dSImre Vadasz 		pr_err("Illegal memory manager memory type %u\n", mem_type);
14005718399fSFrançois Tigeot 		return -EINVAL;
14015718399fSFrançois Tigeot 	}
14025718399fSFrançois Tigeot 
14035718399fSFrançois Tigeot 	if (!man->has_type) {
14040bece63dSImre Vadasz 		pr_err("Memory type %u has not been initialized\n", mem_type);
14055718399fSFrançois Tigeot 		return 0;
14065718399fSFrançois Tigeot 	}
14075718399fSFrançois Tigeot 
1408a85cb24fSFrançois Tigeot 	return ttm_bo_force_list_clean(bdev, mem_type);
14095718399fSFrançois Tigeot }
1410c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_evict_mm);
14115718399fSFrançois Tigeot 
ttm_bo_init_mm(struct ttm_bo_device * bdev,unsigned type,unsigned long p_size)14125718399fSFrançois Tigeot int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
14135718399fSFrançois Tigeot 			unsigned long p_size)
14145718399fSFrançois Tigeot {
1415a85cb24fSFrançois Tigeot 	int ret;
14165718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man;
1417a85cb24fSFrançois Tigeot 	unsigned i;
14185718399fSFrançois Tigeot 
1419c19c6249SFrançois Tigeot 	BUG_ON(type >= TTM_NUM_MEM_TYPES);
14205718399fSFrançois Tigeot 	man = &bdev->man[type];
1421c19c6249SFrançois Tigeot 	BUG_ON(man->has_type);
14225718399fSFrançois Tigeot 	man->io_reserve_fastpath = true;
14235718399fSFrançois Tigeot 	man->use_io_reserve_lru = false;
1424a34b4168SMatthew Dillon 	lockinit(&man->io_reserve_mutex, "ttmior", 0, 0);
14259a49c39cSFrançois Tigeot 	lockinit(&man->move_lock, "ttmml", 0, 0);
14265718399fSFrançois Tigeot 	INIT_LIST_HEAD(&man->io_reserve_lru);
14275718399fSFrançois Tigeot 
14285718399fSFrançois Tigeot 	ret = bdev->driver->init_mem_type(bdev, type, man);
14295718399fSFrançois Tigeot 	if (ret)
14305718399fSFrançois Tigeot 		return ret;
14315718399fSFrançois Tigeot 	man->bdev = bdev;
14325718399fSFrançois Tigeot 
14335718399fSFrançois Tigeot 	if (type != TTM_PL_SYSTEM) {
14345718399fSFrançois Tigeot 		ret = (*man->func->init)(man, p_size);
14355718399fSFrançois Tigeot 		if (ret)
14365718399fSFrançois Tigeot 			return ret;
14375718399fSFrançois Tigeot 	}
14385718399fSFrançois Tigeot 	man->has_type = true;
14395718399fSFrançois Tigeot 	man->use_type = true;
14405718399fSFrançois Tigeot 	man->size = p_size;
14415718399fSFrançois Tigeot 
1442a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
1443a85cb24fSFrançois Tigeot 		INIT_LIST_HEAD(&man->lru[i]);
14441dedbd3bSFrançois Tigeot 	man->move = NULL;
14455718399fSFrançois Tigeot 
14465718399fSFrançois Tigeot 	return 0;
14475718399fSFrançois Tigeot }
1448c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_init_mm);
14495718399fSFrançois Tigeot 
ttm_bo_global_kobj_release(struct kobject * kobj)14503a2096e8SFrançois Tigeot static void ttm_bo_global_kobj_release(struct kobject *kobj)
14515718399fSFrançois Tigeot {
14523a2096e8SFrançois Tigeot 	struct ttm_bo_global *glob =
14533a2096e8SFrançois Tigeot 		container_of(kobj, struct ttm_bo_global, kobj);
14543a2096e8SFrançois Tigeot 
1455e5c1d8f1SFrançois Tigeot 	__free_page(glob->dummy_read_page);
14565718399fSFrançois Tigeot }
14575718399fSFrançois Tigeot 
ttm_bo_global_release(struct drm_global_reference * ref)14585718399fSFrançois Tigeot void ttm_bo_global_release(struct drm_global_reference *ref)
14595718399fSFrançois Tigeot {
14605718399fSFrançois Tigeot 	struct ttm_bo_global *glob = ref->object;
14615718399fSFrançois Tigeot 
14623a2096e8SFrançois Tigeot 	kobject_del(&glob->kobj);
14633a2096e8SFrançois Tigeot 	kobject_put(&glob->kobj);
14645718399fSFrançois Tigeot }
1465c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_global_release);
14665718399fSFrançois Tigeot 
ttm_bo_global_init(struct drm_global_reference * ref)14675718399fSFrançois Tigeot int ttm_bo_global_init(struct drm_global_reference *ref)
14685718399fSFrançois Tigeot {
14695718399fSFrançois Tigeot 	struct ttm_bo_global_ref *bo_ref =
14705718399fSFrançois Tigeot 		container_of(ref, struct ttm_bo_global_ref, ref);
14715718399fSFrançois Tigeot 	struct ttm_bo_global *glob = ref->object;
14725718399fSFrançois Tigeot 	int ret;
1473a85cb24fSFrançois Tigeot 	unsigned i;
14745718399fSFrançois Tigeot 
1475a34b4168SMatthew Dillon 	lockinit(&glob->device_list_mutex, "ttmdlm", 0, 0);
1476a34b4168SMatthew Dillon 	lockinit(&glob->lru_lock, "ttmlru", 0, 0);
14775718399fSFrançois Tigeot 	glob->mem_glob = bo_ref->mem_glob;
1478*932d855eSSergey Zigachev 	glob->mem_glob->bo_glob = glob;
1479f146ed7fSFrançois Tigeot 	glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
14805718399fSFrançois Tigeot 
14815718399fSFrançois Tigeot 	if (unlikely(glob->dummy_read_page == NULL)) {
14825718399fSFrançois Tigeot 		ret = -ENOMEM;
14835718399fSFrançois Tigeot 		goto out_no_drp;
14845718399fSFrançois Tigeot 	}
14855718399fSFrançois Tigeot 
1486a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
1487a85cb24fSFrançois Tigeot 		INIT_LIST_HEAD(&glob->swap_lru[i]);
14885718399fSFrançois Tigeot 	INIT_LIST_HEAD(&glob->device_list);
14895718399fSFrançois Tigeot 	atomic_set(&glob->bo_count, 0);
14905718399fSFrançois Tigeot 
14913a2096e8SFrançois Tigeot 	ret = kobject_init_and_add(
14923a2096e8SFrançois Tigeot 		&glob->kobj, &ttm_bo_glob_kobj_type, ttm_get_kobj(), "buffer_objects");
14933a2096e8SFrançois Tigeot 	if (unlikely(ret != 0))
14943a2096e8SFrançois Tigeot 		kobject_put(&glob->kobj);
14953a2096e8SFrançois Tigeot 	return ret;
14965718399fSFrançois Tigeot out_no_drp:
1497158486a6SFrançois Tigeot 	kfree(glob);
14985718399fSFrançois Tigeot 	return ret;
14995718399fSFrançois Tigeot }
1500c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_global_init);
1501c19c6249SFrançois Tigeot 
15025718399fSFrançois Tigeot 
ttm_bo_device_release(struct ttm_bo_device * bdev)15035718399fSFrançois Tigeot int ttm_bo_device_release(struct ttm_bo_device *bdev)
15045718399fSFrançois Tigeot {
15055718399fSFrançois Tigeot 	int ret = 0;
15065718399fSFrançois Tigeot 	unsigned i = TTM_NUM_MEM_TYPES;
15075718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man;
15085718399fSFrançois Tigeot 	struct ttm_bo_global *glob = bdev->glob;
15095718399fSFrançois Tigeot 
15105718399fSFrançois Tigeot 	while (i--) {
15115718399fSFrançois Tigeot 		man = &bdev->man[i];
15125718399fSFrançois Tigeot 		if (man->has_type) {
15135718399fSFrançois Tigeot 			man->use_type = false;
15145718399fSFrançois Tigeot 			if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) {
15155718399fSFrançois Tigeot 				ret = -EBUSY;
15160bece63dSImre Vadasz 				pr_err("DRM memory manager type %d is not clean\n",
15175718399fSFrançois Tigeot 				       i);
15185718399fSFrançois Tigeot 			}
15195718399fSFrançois Tigeot 			man->has_type = false;
15205718399fSFrançois Tigeot 		}
15215718399fSFrançois Tigeot 	}
15225718399fSFrançois Tigeot 
152343e748b9SFrançois Tigeot 	mutex_lock(&glob->device_list_mutex);
15245718399fSFrançois Tigeot 	list_del(&bdev->device_list);
152543e748b9SFrançois Tigeot 	mutex_unlock(&glob->device_list_mutex);
15265718399fSFrançois Tigeot 
152789a75b27SFrançois Tigeot 	cancel_delayed_work_sync(&bdev->wq);
15285718399fSFrançois Tigeot 
1529*932d855eSSergey Zigachev 	if (ttm_bo_delayed_delete(bdev, true))
1530*932d855eSSergey Zigachev 		pr_debug("Delayed destroy list was clean\n");
15315718399fSFrançois Tigeot 
15325718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
15335718399fSFrançois Tigeot 	if (list_empty(&bdev->ddestroy))
15345718399fSFrançois Tigeot 		TTM_DEBUG("Delayed destroy list was clean\n");
1535a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
1536a85cb24fSFrançois Tigeot 		if (list_empty(&bdev->man[0].lru[0]))
1537*932d855eSSergey Zigachev 			pr_debug("Swap list %d was clean\n", i);
15385718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
15395718399fSFrançois Tigeot 
1540a34b4168SMatthew Dillon 	drm_vma_offset_manager_destroy(&bdev->vma_manager);
15415718399fSFrançois Tigeot 
15425718399fSFrançois Tigeot 	return ret;
15435718399fSFrançois Tigeot }
1544c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_device_release);
15455718399fSFrançois Tigeot 
ttm_bo_device_init(struct ttm_bo_device * bdev,struct ttm_bo_global * glob,struct ttm_bo_driver * driver,struct address_space * mapping,uint64_t file_page_offset,bool need_dma32)15465718399fSFrançois Tigeot int ttm_bo_device_init(struct ttm_bo_device *bdev,
15475718399fSFrançois Tigeot 		       struct ttm_bo_global *glob,
15485718399fSFrançois Tigeot 		       struct ttm_bo_driver *driver,
154943e748b9SFrançois Tigeot 		       struct address_space *mapping,
15505718399fSFrançois Tigeot 		       uint64_t file_page_offset,
15515718399fSFrançois Tigeot 		       bool need_dma32)
15525718399fSFrançois Tigeot {
15535718399fSFrançois Tigeot 	int ret = -EINVAL;
15545718399fSFrançois Tigeot 
15555718399fSFrançois Tigeot 	bdev->driver = driver;
15565718399fSFrançois Tigeot 
15575718399fSFrançois Tigeot 	memset(bdev->man, 0, sizeof(bdev->man));
15585718399fSFrançois Tigeot 
15595718399fSFrançois Tigeot 	/*
15605718399fSFrançois Tigeot 	 * Initialize the system memory buffer type.
15615718399fSFrançois Tigeot 	 * Other types need to be driver / IOCTL initialized.
15625718399fSFrançois Tigeot 	 */
15635718399fSFrançois Tigeot 	ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0);
15645718399fSFrançois Tigeot 	if (unlikely(ret != 0))
15655718399fSFrançois Tigeot 		goto out_no_sys;
15665718399fSFrançois Tigeot 
1567a34b4168SMatthew Dillon 	drm_vma_offset_manager_init(&bdev->vma_manager, file_page_offset,
1568a34b4168SMatthew Dillon 				    0x10000000);
156989a75b27SFrançois Tigeot 	INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
15705718399fSFrançois Tigeot 	INIT_LIST_HEAD(&bdev->ddestroy);
1571a34b4168SMatthew Dillon 	/*
1572a34b4168SMatthew Dillon 	 * XXX DRAGONFLY - dev_mapping NULL atm, find other XXX DRAGONFLY
1573a34b4168SMatthew Dillon 	 * lines and fix when it no longer is in later API change.
1574a34b4168SMatthew Dillon 	 */
157543e748b9SFrançois Tigeot 	bdev->dev_mapping = mapping;
15765718399fSFrançois Tigeot 	bdev->glob = glob;
15775718399fSFrançois Tigeot 	bdev->need_dma32 = need_dma32;
157843e748b9SFrançois Tigeot 	mutex_lock(&glob->device_list_mutex);
15795718399fSFrançois Tigeot 	list_add_tail(&bdev->device_list, &glob->device_list);
158043e748b9SFrançois Tigeot 	mutex_unlock(&glob->device_list_mutex);
15815718399fSFrançois Tigeot 
15825718399fSFrançois Tigeot 	return 0;
15835718399fSFrançois Tigeot out_no_sys:
15845718399fSFrançois Tigeot 	return ret;
15855718399fSFrançois Tigeot }
1586c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_device_init);
15875718399fSFrançois Tigeot 
15885718399fSFrançois Tigeot /*
15895718399fSFrançois Tigeot  * buffer object vm functions.
15905718399fSFrançois Tigeot  */
15915718399fSFrançois Tigeot 
ttm_mem_reg_is_pci(struct ttm_bo_device * bdev,struct ttm_mem_reg * mem)15925718399fSFrançois Tigeot bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
15935718399fSFrançois Tigeot {
15945718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
15955718399fSFrançois Tigeot 
15965718399fSFrançois Tigeot 	if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
15975718399fSFrançois Tigeot 		if (mem->mem_type == TTM_PL_SYSTEM)
15985718399fSFrançois Tigeot 			return false;
15995718399fSFrançois Tigeot 
16005718399fSFrançois Tigeot 		if (man->flags & TTM_MEMTYPE_FLAG_CMA)
16015718399fSFrançois Tigeot 			return false;
16025718399fSFrançois Tigeot 
16035718399fSFrançois Tigeot 		if (mem->placement & TTM_PL_FLAG_CACHED)
16045718399fSFrançois Tigeot 			return false;
16055718399fSFrançois Tigeot 	}
16065718399fSFrançois Tigeot 	return true;
16075718399fSFrançois Tigeot }
16085718399fSFrançois Tigeot 
160943e748b9SFrançois Tigeot #ifdef __DragonFly__
161043e748b9SFrançois Tigeot 
161143e748b9SFrançois Tigeot /*
161243e748b9SFrançois Tigeot  * XXX DRAGONFLY - device_mapping not yet implemented so
161343e748b9SFrançois Tigeot  * file_mapping is basically always NULL.  We have to properly
161443e748b9SFrançois Tigeot  * release the mmap, etc.
161543e748b9SFrançois Tigeot */
161643e748b9SFrançois Tigeot void ttm_bo_release_mmap(struct ttm_buffer_object *bo);
161743e748b9SFrançois Tigeot 
161843e748b9SFrançois Tigeot #endif
161943e748b9SFrançois Tigeot 
ttm_bo_unmap_virtual_locked(struct ttm_buffer_object * bo)16205718399fSFrançois Tigeot void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
16215718399fSFrançois Tigeot {
16223f2dd94aSFrançois Tigeot //	drm_vma_node_unmap(&bo->vma_node, bdev->dev_mapping);
16233f2dd94aSFrançois Tigeot 	ttm_bo_release_mmap(bo);
1624a34b4168SMatthew Dillon 	ttm_mem_io_free_vm(bo);
16255718399fSFrançois Tigeot }
16265718399fSFrançois Tigeot 
ttm_bo_unmap_virtual(struct ttm_buffer_object * bo)16275718399fSFrançois Tigeot void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
16285718399fSFrançois Tigeot {
16295718399fSFrançois Tigeot 	struct ttm_bo_device *bdev = bo->bdev;
16305718399fSFrançois Tigeot 	struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
16315718399fSFrançois Tigeot 
16325718399fSFrançois Tigeot 	ttm_mem_io_lock(man, false);
16335718399fSFrançois Tigeot 	ttm_bo_unmap_virtual_locked(bo);
16345718399fSFrançois Tigeot 	ttm_mem_io_unlock(man);
16355718399fSFrançois Tigeot }
16365718399fSFrançois Tigeot 
1637c19c6249SFrançois Tigeot 
1638c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_unmap_virtual);
1639c19c6249SFrançois Tigeot 
ttm_bo_wait(struct ttm_buffer_object * bo,bool interruptible,bool no_wait)16405718399fSFrançois Tigeot int ttm_bo_wait(struct ttm_buffer_object *bo,
1641d78d3a22SFrançois Tigeot 		bool interruptible, bool no_wait)
16425718399fSFrançois Tigeot {
16434be47400SFrançois Tigeot 	long timeout = 15 * HZ;
16444be47400SFrançois Tigeot 
16454be47400SFrançois Tigeot 	if (no_wait) {
16464be47400SFrançois Tigeot 		if (reservation_object_test_signaled_rcu(bo->resv, true))
16474be47400SFrançois Tigeot 			return 0;
16484be47400SFrançois Tigeot 		else
16494be47400SFrançois Tigeot 			return -EBUSY;
16504be47400SFrançois Tigeot 	}
16515718399fSFrançois Tigeot 
16521dedbd3bSFrançois Tigeot 	timeout = reservation_object_wait_timeout_rcu(bo->resv, true,
16531cfef1a5SFrançois Tigeot 						      interruptible, timeout);
16541cfef1a5SFrançois Tigeot 	if (timeout < 0)
16551cfef1a5SFrançois Tigeot 		return timeout;
16561cfef1a5SFrançois Tigeot 
16571cfef1a5SFrançois Tigeot 	if (timeout == 0)
16581cfef1a5SFrançois Tigeot 		return -EBUSY;
16591cfef1a5SFrançois Tigeot 
16601dedbd3bSFrançois Tigeot 	reservation_object_add_excl_fence(bo->resv, NULL);
16615718399fSFrançois Tigeot 	return 0;
16625718399fSFrançois Tigeot }
1663c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_wait);
16645718399fSFrançois Tigeot 
ttm_bo_synccpu_write_grab(struct ttm_buffer_object * bo,bool no_wait)16655718399fSFrançois Tigeot int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
16665718399fSFrançois Tigeot {
16675718399fSFrançois Tigeot 	int ret = 0;
16685718399fSFrançois Tigeot 
16695718399fSFrançois Tigeot 	/*
16705718399fSFrançois Tigeot 	 * Using ttm_bo_reserve makes sure the lru lists are updated.
16715718399fSFrançois Tigeot 	 */
16725718399fSFrançois Tigeot 
1673d78d3a22SFrançois Tigeot 	ret = ttm_bo_reserve(bo, true, no_wait, NULL);
16745718399fSFrançois Tigeot 	if (unlikely(ret != 0))
16755718399fSFrançois Tigeot 		return ret;
1676d78d3a22SFrançois Tigeot 	ret = ttm_bo_wait(bo, true, no_wait);
16775718399fSFrançois Tigeot 	if (likely(ret == 0))
16785718399fSFrançois Tigeot 		atomic_inc(&bo->cpu_writers);
16795718399fSFrançois Tigeot 	ttm_bo_unreserve(bo);
16805718399fSFrançois Tigeot 	return ret;
16815718399fSFrançois Tigeot }
1682c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_synccpu_write_grab);
16835718399fSFrançois Tigeot 
ttm_bo_synccpu_write_release(struct ttm_buffer_object * bo)16845718399fSFrançois Tigeot void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo)
16855718399fSFrançois Tigeot {
16865718399fSFrançois Tigeot 	atomic_dec(&bo->cpu_writers);
16875718399fSFrançois Tigeot }
1688c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_synccpu_write_release);
16895718399fSFrançois Tigeot 
16905718399fSFrançois Tigeot /**
16915718399fSFrançois Tigeot  * A buffer object shrink method that tries to swap out the first
16925718399fSFrançois Tigeot  * buffer object on the bo_global::swap_lru list.
16935718399fSFrançois Tigeot  */
ttm_bo_swapout(struct ttm_bo_global * glob,struct ttm_operation_ctx * ctx)1694*932d855eSSergey Zigachev int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
16955718399fSFrançois Tigeot {
16965718399fSFrançois Tigeot 	struct ttm_buffer_object *bo;
16975718399fSFrançois Tigeot 	int ret = -EBUSY;
1698*932d855eSSergey Zigachev 	bool locked;
1699a85cb24fSFrançois Tigeot 	unsigned i;
17005718399fSFrançois Tigeot 
17015718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_EXCLUSIVE);
1702a85cb24fSFrançois Tigeot 	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
1703a85cb24fSFrançois Tigeot 		list_for_each_entry(bo, &glob->swap_lru[i], swap) {
1704*932d855eSSergey Zigachev 			if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked)) {
1705*932d855eSSergey Zigachev 				ret = 0;
17065718399fSFrançois Tigeot 				break;
17075718399fSFrançois Tigeot 			}
1708*932d855eSSergey Zigachev 		}
1709a85cb24fSFrançois Tigeot 		if (!ret)
1710a85cb24fSFrançois Tigeot 			break;
1711a85cb24fSFrançois Tigeot 	}
17125718399fSFrançois Tigeot 
17135718399fSFrançois Tigeot 	if (ret) {
17145718399fSFrançois Tigeot 		lockmgr(&glob->lru_lock, LK_RELEASE);
17155718399fSFrançois Tigeot 		return ret;
17165718399fSFrançois Tigeot 	}
17175718399fSFrançois Tigeot 
1718e3b244c9SFrançois Tigeot 	kref_get(&bo->list_kref);
17195718399fSFrançois Tigeot 
17205718399fSFrançois Tigeot 	if (!list_empty(&bo->ddestroy)) {
1721*932d855eSSergey Zigachev 		ret = ttm_bo_cleanup_refs(bo, false, false, locked);
1722e3b244c9SFrançois Tigeot 		kref_put(&bo->list_kref, ttm_bo_release_list);
17235718399fSFrançois Tigeot 		return ret;
17245718399fSFrançois Tigeot 	}
17255718399fSFrançois Tigeot 
1726a85cb24fSFrançois Tigeot 	ttm_bo_del_from_lru(bo);
17275718399fSFrançois Tigeot 	lockmgr(&glob->lru_lock, LK_RELEASE);
17285718399fSFrançois Tigeot 
17295718399fSFrançois Tigeot 	/**
17301dedbd3bSFrançois Tigeot 	 * Move to system cached
17315718399fSFrançois Tigeot 	 */
17325718399fSFrançois Tigeot 
17334be47400SFrançois Tigeot 	if (bo->mem.mem_type != TTM_PL_SYSTEM ||
17344be47400SFrançois Tigeot 	    bo->ttm->caching_state != tt_cached) {
1735*932d855eSSergey Zigachev 		struct ttm_operation_ctx ctx = { false, false };
17365718399fSFrançois Tigeot 		struct ttm_mem_reg evict_mem;
17375718399fSFrançois Tigeot 
17385718399fSFrançois Tigeot 		evict_mem = bo->mem;
17395718399fSFrançois Tigeot 		evict_mem.mm_node = NULL;
17405718399fSFrançois Tigeot 		evict_mem.placement = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
17415718399fSFrançois Tigeot 		evict_mem.mem_type = TTM_PL_SYSTEM;
17425718399fSFrançois Tigeot 
1743*932d855eSSergey Zigachev 		ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, &ctx);
17445718399fSFrançois Tigeot 		if (unlikely(ret != 0))
17455718399fSFrançois Tigeot 			goto out;
17465718399fSFrançois Tigeot 	}
17475718399fSFrançois Tigeot 
17481dedbd3bSFrançois Tigeot 	/**
17491dedbd3bSFrançois Tigeot 	 * Make sure BO is idle.
17501dedbd3bSFrançois Tigeot 	 */
17511dedbd3bSFrançois Tigeot 
17521dedbd3bSFrançois Tigeot 	ret = ttm_bo_wait(bo, false, false);
17531dedbd3bSFrançois Tigeot 	if (unlikely(ret != 0))
17541dedbd3bSFrançois Tigeot 		goto out;
17551dedbd3bSFrançois Tigeot 
17565718399fSFrançois Tigeot 	ttm_bo_unmap_virtual(bo);
17575718399fSFrançois Tigeot 
17585718399fSFrançois Tigeot 	/**
17595718399fSFrançois Tigeot 	 * Swap out. Buffer will be swapped in again as soon as
17605718399fSFrançois Tigeot 	 * anyone tries to access a ttm page.
17615718399fSFrançois Tigeot 	 */
17625718399fSFrançois Tigeot 
17635718399fSFrançois Tigeot 	if (bo->bdev->driver->swap_notify)
17645718399fSFrançois Tigeot 		bo->bdev->driver->swap_notify(bo);
17655718399fSFrançois Tigeot 
17665718399fSFrançois Tigeot 	ret = ttm_tt_swapout(bo->ttm, bo->persistent_swap_storage);
17675718399fSFrançois Tigeot out:
17685718399fSFrançois Tigeot 
17695718399fSFrançois Tigeot 	/**
17705718399fSFrançois Tigeot 	 *
17715718399fSFrançois Tigeot 	 * Unreserve without putting on LRU to avoid swapping out an
17725718399fSFrançois Tigeot 	 * already swapped buffer.
17735718399fSFrançois Tigeot 	 */
1774*932d855eSSergey Zigachev 	if (locked)
177543e748b9SFrançois Tigeot 		__ttm_bo_unreserve(bo);
1776e3b244c9SFrançois Tigeot 	kref_put(&bo->list_kref, ttm_bo_release_list);
17775718399fSFrançois Tigeot 	return ret;
17785718399fSFrançois Tigeot }
1779*932d855eSSergey Zigachev EXPORT_SYMBOL(ttm_bo_swapout);
17805718399fSFrançois Tigeot 
ttm_bo_swapout_all(struct ttm_bo_device * bdev)17815718399fSFrançois Tigeot void ttm_bo_swapout_all(struct ttm_bo_device *bdev)
17825718399fSFrançois Tigeot {
1783*932d855eSSergey Zigachev 	struct ttm_operation_ctx ctx = {
1784*932d855eSSergey Zigachev 		.interruptible = false,
1785*932d855eSSergey Zigachev 		.no_wait_gpu = false
1786*932d855eSSergey Zigachev 	};
1787*932d855eSSergey Zigachev 
1788*932d855eSSergey Zigachev 	while (ttm_bo_swapout(bdev->glob, &ctx) == 0)
17895718399fSFrançois Tigeot 		;
17905718399fSFrançois Tigeot }
1791c19c6249SFrançois Tigeot EXPORT_SYMBOL(ttm_bo_swapout_all);
179243e748b9SFrançois Tigeot 
179343e748b9SFrançois Tigeot /**
179443e748b9SFrançois Tigeot  * ttm_bo_wait_unreserved - interruptible wait for a buffer object to become
179543e748b9SFrançois Tigeot  * unreserved
179643e748b9SFrançois Tigeot  *
179743e748b9SFrançois Tigeot  * @bo: Pointer to buffer
179843e748b9SFrançois Tigeot  */
ttm_bo_wait_unreserved(struct ttm_buffer_object * bo)179943e748b9SFrançois Tigeot int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo)
180043e748b9SFrançois Tigeot {
180143e748b9SFrançois Tigeot 	int ret;
180243e748b9SFrançois Tigeot 
180343e748b9SFrançois Tigeot 	/*
180443e748b9SFrançois Tigeot 	 * In the absense of a wait_unlocked API,
180543e748b9SFrançois Tigeot 	 * Use the bo::wu_mutex to avoid triggering livelocks due to
180643e748b9SFrançois Tigeot 	 * concurrent use of this function. Note that this use of
180743e748b9SFrançois Tigeot 	 * bo::wu_mutex can go away if we change locking order to
180843e748b9SFrançois Tigeot 	 * mmap_sem -> bo::reserve.
180943e748b9SFrançois Tigeot 	 */
181043e748b9SFrançois Tigeot 	ret = mutex_lock_interruptible(&bo->wu_mutex);
181143e748b9SFrançois Tigeot 	if (unlikely(ret != 0))
181243e748b9SFrançois Tigeot 		return -ERESTARTSYS;
181343e748b9SFrançois Tigeot 	if (!ww_mutex_is_locked(&bo->resv->lock))
181443e748b9SFrançois Tigeot 		goto out_unlock;
1815d78d3a22SFrançois Tigeot 	ret = __ttm_bo_reserve(bo, true, false, NULL);
181643e748b9SFrançois Tigeot 	if (unlikely(ret != 0))
181743e748b9SFrançois Tigeot 		goto out_unlock;
181843e748b9SFrançois Tigeot 	__ttm_bo_unreserve(bo);
181943e748b9SFrançois Tigeot 
182043e748b9SFrançois Tigeot out_unlock:
182143e748b9SFrançois Tigeot 	mutex_unlock(&bo->wu_mutex);
182243e748b9SFrançois Tigeot 	return ret;
182343e748b9SFrançois Tigeot }
1824