162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2020 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Authors: Christian König
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/iosys-map.h>
2662306a36Sopenharmony_ci#include <linux/io-mapping.h>
2762306a36Sopenharmony_ci#include <linux/scatterlist.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <drm/ttm/ttm_bo.h>
3062306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
3162306a36Sopenharmony_ci#include <drm/ttm/ttm_resource.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/**
3462306a36Sopenharmony_ci * ttm_lru_bulk_move_init - initialize a bulk move structure
3562306a36Sopenharmony_ci * @bulk: the structure to init
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * For now just memset the structure to zero.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_civoid ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	memset(bulk, 0, sizeof(*bulk));
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_lru_bulk_move_init);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * ttm_lru_bulk_move_tail - bulk move range of resources to the LRU tail.
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * @bulk: bulk move structure
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * Bulk move BOs to the LRU tail, only valid to use when driver makes sure that
5162306a36Sopenharmony_ci * resource order never changes. Should be called with &ttm_device.lru_lock held.
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_civoid ttm_lru_bulk_move_tail(struct ttm_lru_bulk_move *bulk)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	unsigned i, j;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	for (i = 0; i < TTM_NUM_MEM_TYPES; ++i) {
5862306a36Sopenharmony_ci		for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) {
5962306a36Sopenharmony_ci			struct ttm_lru_bulk_move_pos *pos = &bulk->pos[i][j];
6062306a36Sopenharmony_ci			struct ttm_resource_manager *man;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci			if (!pos->first)
6362306a36Sopenharmony_ci				continue;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci			lockdep_assert_held(&pos->first->bo->bdev->lru_lock);
6662306a36Sopenharmony_ci			dma_resv_assert_held(pos->first->bo->base.resv);
6762306a36Sopenharmony_ci			dma_resv_assert_held(pos->last->bo->base.resv);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci			man = ttm_manager_type(pos->first->bo->bdev, i);
7062306a36Sopenharmony_ci			list_bulk_move_tail(&man->lru[j], &pos->first->lru,
7162306a36Sopenharmony_ci					    &pos->last->lru);
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_lru_bulk_move_tail);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Return the bulk move pos object for this resource */
7862306a36Sopenharmony_cistatic struct ttm_lru_bulk_move_pos *
7962306a36Sopenharmony_cittm_lru_bulk_move_pos(struct ttm_lru_bulk_move *bulk, struct ttm_resource *res)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return &bulk->pos[res->mem_type][res->bo->priority];
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* Move the resource to the tail of the bulk move range */
8562306a36Sopenharmony_cistatic void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos,
8662306a36Sopenharmony_ci				       struct ttm_resource *res)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	if (pos->last != res) {
8962306a36Sopenharmony_ci		if (pos->first == res)
9062306a36Sopenharmony_ci			pos->first = list_next_entry(res, lru);
9162306a36Sopenharmony_ci		list_move(&res->lru, &pos->last->lru);
9262306a36Sopenharmony_ci		pos->last = res;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Add the resource to a bulk_move cursor */
9762306a36Sopenharmony_cistatic void ttm_lru_bulk_move_add(struct ttm_lru_bulk_move *bulk,
9862306a36Sopenharmony_ci				  struct ttm_resource *res)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (!pos->first) {
10362306a36Sopenharmony_ci		pos->first = res;
10462306a36Sopenharmony_ci		pos->last = res;
10562306a36Sopenharmony_ci	} else {
10662306a36Sopenharmony_ci		ttm_lru_bulk_move_pos_tail(pos, res);
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* Remove the resource from a bulk_move range */
11162306a36Sopenharmony_cistatic void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk,
11262306a36Sopenharmony_ci				  struct ttm_resource *res)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (unlikely(WARN_ON(!pos->first || !pos->last) ||
11762306a36Sopenharmony_ci		     (pos->first == res && pos->last == res))) {
11862306a36Sopenharmony_ci		pos->first = NULL;
11962306a36Sopenharmony_ci		pos->last = NULL;
12062306a36Sopenharmony_ci	} else if (pos->first == res) {
12162306a36Sopenharmony_ci		pos->first = list_next_entry(res, lru);
12262306a36Sopenharmony_ci	} else if (pos->last == res) {
12362306a36Sopenharmony_ci		pos->last = list_prev_entry(res, lru);
12462306a36Sopenharmony_ci	} else {
12562306a36Sopenharmony_ci		list_move(&res->lru, &pos->last->lru);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* Add the resource to a bulk move if the BO is configured for it */
13062306a36Sopenharmony_civoid ttm_resource_add_bulk_move(struct ttm_resource *res,
13162306a36Sopenharmony_ci				struct ttm_buffer_object *bo)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	if (bo->bulk_move && !bo->pin_count)
13462306a36Sopenharmony_ci		ttm_lru_bulk_move_add(bo->bulk_move, res);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* Remove the resource from a bulk move if the BO is configured for it */
13862306a36Sopenharmony_civoid ttm_resource_del_bulk_move(struct ttm_resource *res,
13962306a36Sopenharmony_ci				struct ttm_buffer_object *bo)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	if (bo->bulk_move && !bo->pin_count)
14262306a36Sopenharmony_ci		ttm_lru_bulk_move_del(bo->bulk_move, res);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Move a resource to the LRU or bulk tail */
14662306a36Sopenharmony_civoid ttm_resource_move_to_lru_tail(struct ttm_resource *res)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct ttm_buffer_object *bo = res->bo;
14962306a36Sopenharmony_ci	struct ttm_device *bdev = bo->bdev;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	lockdep_assert_held(&bo->bdev->lru_lock);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (bo->pin_count) {
15462306a36Sopenharmony_ci		list_move_tail(&res->lru, &bdev->pinned);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	} else	if (bo->bulk_move) {
15762306a36Sopenharmony_ci		struct ttm_lru_bulk_move_pos *pos =
15862306a36Sopenharmony_ci			ttm_lru_bulk_move_pos(bo->bulk_move, res);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		ttm_lru_bulk_move_pos_tail(pos, res);
16162306a36Sopenharmony_ci	} else {
16262306a36Sopenharmony_ci		struct ttm_resource_manager *man;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		man = ttm_manager_type(bdev, res->mem_type);
16562306a36Sopenharmony_ci		list_move_tail(&res->lru, &man->lru[bo->priority]);
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/**
17062306a36Sopenharmony_ci * ttm_resource_init - resource object constructure
17162306a36Sopenharmony_ci * @bo: buffer object this resources is allocated for
17262306a36Sopenharmony_ci * @place: placement of the resource
17362306a36Sopenharmony_ci * @res: the resource object to inistilize
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * Initialize a new resource object. Counterpart of ttm_resource_fini().
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_civoid ttm_resource_init(struct ttm_buffer_object *bo,
17862306a36Sopenharmony_ci                       const struct ttm_place *place,
17962306a36Sopenharmony_ci                       struct ttm_resource *res)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct ttm_resource_manager *man;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	res->start = 0;
18462306a36Sopenharmony_ci	res->size = bo->base.size;
18562306a36Sopenharmony_ci	res->mem_type = place->mem_type;
18662306a36Sopenharmony_ci	res->placement = place->flags;
18762306a36Sopenharmony_ci	res->bus.addr = NULL;
18862306a36Sopenharmony_ci	res->bus.offset = 0;
18962306a36Sopenharmony_ci	res->bus.is_iomem = false;
19062306a36Sopenharmony_ci	res->bus.caching = ttm_cached;
19162306a36Sopenharmony_ci	res->bo = bo;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	man = ttm_manager_type(bo->bdev, place->mem_type);
19462306a36Sopenharmony_ci	spin_lock(&bo->bdev->lru_lock);
19562306a36Sopenharmony_ci	if (bo->pin_count)
19662306a36Sopenharmony_ci		list_add_tail(&res->lru, &bo->bdev->pinned);
19762306a36Sopenharmony_ci	else
19862306a36Sopenharmony_ci		list_add_tail(&res->lru, &man->lru[bo->priority]);
19962306a36Sopenharmony_ci	man->usage += res->size;
20062306a36Sopenharmony_ci	spin_unlock(&bo->bdev->lru_lock);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_init);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/**
20562306a36Sopenharmony_ci * ttm_resource_fini - resource destructor
20662306a36Sopenharmony_ci * @man: the resource manager this resource belongs to
20762306a36Sopenharmony_ci * @res: the resource to clean up
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci * Should be used by resource manager backends to clean up the TTM resource
21062306a36Sopenharmony_ci * objects before freeing the underlying structure. Makes sure the resource is
21162306a36Sopenharmony_ci * removed from the LRU before destruction.
21262306a36Sopenharmony_ci * Counterpart of ttm_resource_init().
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_civoid ttm_resource_fini(struct ttm_resource_manager *man,
21562306a36Sopenharmony_ci		       struct ttm_resource *res)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct ttm_device *bdev = man->bdev;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	spin_lock(&bdev->lru_lock);
22062306a36Sopenharmony_ci	list_del_init(&res->lru);
22162306a36Sopenharmony_ci	man->usage -= res->size;
22262306a36Sopenharmony_ci	spin_unlock(&bdev->lru_lock);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_fini);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ciint ttm_resource_alloc(struct ttm_buffer_object *bo,
22762306a36Sopenharmony_ci		       const struct ttm_place *place,
22862306a36Sopenharmony_ci		       struct ttm_resource **res_ptr)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct ttm_resource_manager *man =
23162306a36Sopenharmony_ci		ttm_manager_type(bo->bdev, place->mem_type);
23262306a36Sopenharmony_ci	int ret;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	ret = man->func->alloc(man, bo, place, res_ptr);
23562306a36Sopenharmony_ci	if (ret)
23662306a36Sopenharmony_ci		return ret;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	spin_lock(&bo->bdev->lru_lock);
23962306a36Sopenharmony_ci	ttm_resource_add_bulk_move(*res_ptr, bo);
24062306a36Sopenharmony_ci	spin_unlock(&bo->bdev->lru_lock);
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_civoid ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct ttm_resource_manager *man;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (!*res)
24962306a36Sopenharmony_ci		return;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	spin_lock(&bo->bdev->lru_lock);
25262306a36Sopenharmony_ci	ttm_resource_del_bulk_move(*res, bo);
25362306a36Sopenharmony_ci	spin_unlock(&bo->bdev->lru_lock);
25462306a36Sopenharmony_ci	man = ttm_manager_type(bo->bdev, (*res)->mem_type);
25562306a36Sopenharmony_ci	man->func->free(man, *res);
25662306a36Sopenharmony_ci	*res = NULL;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_free);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/**
26162306a36Sopenharmony_ci * ttm_resource_intersects - test for intersection
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * @bdev: TTM device structure
26462306a36Sopenharmony_ci * @res: The resource to test
26562306a36Sopenharmony_ci * @place: The placement to test
26662306a36Sopenharmony_ci * @size: How many bytes the new allocation needs.
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci * Test if @res intersects with @place and @size. Used for testing if evictions
26962306a36Sopenharmony_ci * are valueable or not.
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Returns true if the res placement intersects with @place and @size.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cibool ttm_resource_intersects(struct ttm_device *bdev,
27462306a36Sopenharmony_ci			     struct ttm_resource *res,
27562306a36Sopenharmony_ci			     const struct ttm_place *place,
27662306a36Sopenharmony_ci			     size_t size)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct ttm_resource_manager *man;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (!res)
28162306a36Sopenharmony_ci		return false;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	man = ttm_manager_type(bdev, res->mem_type);
28462306a36Sopenharmony_ci	if (!place || !man->func->intersects)
28562306a36Sopenharmony_ci		return true;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return man->func->intersects(man, res, place, size);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci/**
29162306a36Sopenharmony_ci * ttm_resource_compatible - test for compatibility
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * @bdev: TTM device structure
29462306a36Sopenharmony_ci * @res: The resource to test
29562306a36Sopenharmony_ci * @place: The placement to test
29662306a36Sopenharmony_ci * @size: How many bytes the new allocation needs.
29762306a36Sopenharmony_ci *
29862306a36Sopenharmony_ci * Test if @res compatible with @place and @size.
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci * Returns true if the res placement compatible with @place and @size.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cibool ttm_resource_compatible(struct ttm_device *bdev,
30362306a36Sopenharmony_ci			     struct ttm_resource *res,
30462306a36Sopenharmony_ci			     const struct ttm_place *place,
30562306a36Sopenharmony_ci			     size_t size)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct ttm_resource_manager *man;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (!res || !place)
31062306a36Sopenharmony_ci		return false;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	man = ttm_manager_type(bdev, res->mem_type);
31362306a36Sopenharmony_ci	if (!man->func->compatible)
31462306a36Sopenharmony_ci		return true;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return man->func->compatible(man, res, place, size);
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic bool ttm_resource_places_compat(struct ttm_resource *res,
32062306a36Sopenharmony_ci				       const struct ttm_place *places,
32162306a36Sopenharmony_ci				       unsigned num_placement)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct ttm_buffer_object *bo = res->bo;
32462306a36Sopenharmony_ci	struct ttm_device *bdev = bo->bdev;
32562306a36Sopenharmony_ci	unsigned i;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (res->placement & TTM_PL_FLAG_TEMPORARY)
32862306a36Sopenharmony_ci		return false;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	for (i = 0; i < num_placement; i++) {
33162306a36Sopenharmony_ci		const struct ttm_place *heap = &places[i];
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		if (!ttm_resource_compatible(bdev, res, heap, bo->base.size))
33462306a36Sopenharmony_ci			continue;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		if ((res->mem_type == heap->mem_type) &&
33762306a36Sopenharmony_ci		    (!(heap->flags & TTM_PL_FLAG_CONTIGUOUS) ||
33862306a36Sopenharmony_ci		     (res->placement & TTM_PL_FLAG_CONTIGUOUS)))
33962306a36Sopenharmony_ci			return true;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci	return false;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci/**
34562306a36Sopenharmony_ci * ttm_resource_compat - check if resource is compatible with placement
34662306a36Sopenharmony_ci *
34762306a36Sopenharmony_ci * @res: the resource to check
34862306a36Sopenharmony_ci * @placement: the placement to check against
34962306a36Sopenharmony_ci *
35062306a36Sopenharmony_ci * Returns true if the placement is compatible.
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_cibool ttm_resource_compat(struct ttm_resource *res,
35362306a36Sopenharmony_ci			 struct ttm_placement *placement)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	if (ttm_resource_places_compat(res, placement->placement,
35662306a36Sopenharmony_ci				       placement->num_placement))
35762306a36Sopenharmony_ci		return true;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if ((placement->busy_placement != placement->placement ||
36062306a36Sopenharmony_ci	     placement->num_busy_placement > placement->num_placement) &&
36162306a36Sopenharmony_ci	    ttm_resource_places_compat(res, placement->busy_placement,
36262306a36Sopenharmony_ci				       placement->num_busy_placement))
36362306a36Sopenharmony_ci		return true;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return false;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_civoid ttm_resource_set_bo(struct ttm_resource *res,
36962306a36Sopenharmony_ci			 struct ttm_buffer_object *bo)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	spin_lock(&bo->bdev->lru_lock);
37262306a36Sopenharmony_ci	res->bo = bo;
37362306a36Sopenharmony_ci	spin_unlock(&bo->bdev->lru_lock);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/**
37762306a36Sopenharmony_ci * ttm_resource_manager_init
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * @man: memory manager object to init
38062306a36Sopenharmony_ci * @bdev: ttm device this manager belongs to
38162306a36Sopenharmony_ci * @size: size of managed resources in arbitrary units
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * Initialise core parts of a manager object.
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_civoid ttm_resource_manager_init(struct ttm_resource_manager *man,
38662306a36Sopenharmony_ci			       struct ttm_device *bdev,
38762306a36Sopenharmony_ci			       uint64_t size)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	unsigned i;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	spin_lock_init(&man->move_lock);
39262306a36Sopenharmony_ci	man->bdev = bdev;
39362306a36Sopenharmony_ci	man->size = size;
39462306a36Sopenharmony_ci	man->usage = 0;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
39762306a36Sopenharmony_ci		INIT_LIST_HEAD(&man->lru[i]);
39862306a36Sopenharmony_ci	man->move = NULL;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_manager_init);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci/*
40362306a36Sopenharmony_ci * ttm_resource_manager_evict_all
40462306a36Sopenharmony_ci *
40562306a36Sopenharmony_ci * @bdev - device to use
40662306a36Sopenharmony_ci * @man - manager to use
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * Evict all the objects out of a memory manager until it is empty.
40962306a36Sopenharmony_ci * Part of memory manager cleanup sequence.
41062306a36Sopenharmony_ci */
41162306a36Sopenharmony_ciint ttm_resource_manager_evict_all(struct ttm_device *bdev,
41262306a36Sopenharmony_ci				   struct ttm_resource_manager *man)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = {
41562306a36Sopenharmony_ci		.interruptible = false,
41662306a36Sopenharmony_ci		.no_wait_gpu = false,
41762306a36Sopenharmony_ci		.force_alloc = true
41862306a36Sopenharmony_ci	};
41962306a36Sopenharmony_ci	struct dma_fence *fence;
42062306a36Sopenharmony_ci	int ret;
42162306a36Sopenharmony_ci	unsigned i;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/*
42462306a36Sopenharmony_ci	 * Can't use standard list traversal since we're unlocking.
42562306a36Sopenharmony_ci	 */
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	spin_lock(&bdev->lru_lock);
42862306a36Sopenharmony_ci	for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
42962306a36Sopenharmony_ci		while (!list_empty(&man->lru[i])) {
43062306a36Sopenharmony_ci			spin_unlock(&bdev->lru_lock);
43162306a36Sopenharmony_ci			ret = ttm_mem_evict_first(bdev, man, NULL, &ctx,
43262306a36Sopenharmony_ci						  NULL);
43362306a36Sopenharmony_ci			if (ret)
43462306a36Sopenharmony_ci				return ret;
43562306a36Sopenharmony_ci			spin_lock(&bdev->lru_lock);
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci	spin_unlock(&bdev->lru_lock);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	spin_lock(&man->move_lock);
44162306a36Sopenharmony_ci	fence = dma_fence_get(man->move);
44262306a36Sopenharmony_ci	spin_unlock(&man->move_lock);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (fence) {
44562306a36Sopenharmony_ci		ret = dma_fence_wait(fence, false);
44662306a36Sopenharmony_ci		dma_fence_put(fence);
44762306a36Sopenharmony_ci		if (ret)
44862306a36Sopenharmony_ci			return ret;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return 0;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_manager_evict_all);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/**
45662306a36Sopenharmony_ci * ttm_resource_manager_usage
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * @man: A memory manager object.
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * Return how many resources are currently used.
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_ciuint64_t ttm_resource_manager_usage(struct ttm_resource_manager *man)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	uint64_t usage;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	spin_lock(&man->bdev->lru_lock);
46762306a36Sopenharmony_ci	usage = man->usage;
46862306a36Sopenharmony_ci	spin_unlock(&man->bdev->lru_lock);
46962306a36Sopenharmony_ci	return usage;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_manager_usage);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci/**
47462306a36Sopenharmony_ci * ttm_resource_manager_debug
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * @man: manager type to dump.
47762306a36Sopenharmony_ci * @p: printer to use for debug.
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_civoid ttm_resource_manager_debug(struct ttm_resource_manager *man,
48062306a36Sopenharmony_ci				struct drm_printer *p)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	drm_printf(p, "  use_type: %d\n", man->use_type);
48362306a36Sopenharmony_ci	drm_printf(p, "  use_tt: %d\n", man->use_tt);
48462306a36Sopenharmony_ci	drm_printf(p, "  size: %llu\n", man->size);
48562306a36Sopenharmony_ci	drm_printf(p, "  usage: %llu\n", ttm_resource_manager_usage(man));
48662306a36Sopenharmony_ci	if (man->func->debug)
48762306a36Sopenharmony_ci		man->func->debug(man, p);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_manager_debug);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/**
49262306a36Sopenharmony_ci * ttm_resource_manager_first
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * @man: resource manager to iterate over
49562306a36Sopenharmony_ci * @cursor: cursor to record the position
49662306a36Sopenharmony_ci *
49762306a36Sopenharmony_ci * Returns the first resource from the resource manager.
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_cistruct ttm_resource *
50062306a36Sopenharmony_cittm_resource_manager_first(struct ttm_resource_manager *man,
50162306a36Sopenharmony_ci			   struct ttm_resource_cursor *cursor)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct ttm_resource *res;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	lockdep_assert_held(&man->bdev->lru_lock);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	for (cursor->priority = 0; cursor->priority < TTM_MAX_BO_PRIORITY;
50862306a36Sopenharmony_ci	     ++cursor->priority)
50962306a36Sopenharmony_ci		list_for_each_entry(res, &man->lru[cursor->priority], lru)
51062306a36Sopenharmony_ci			return res;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return NULL;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci/**
51662306a36Sopenharmony_ci * ttm_resource_manager_next
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * @man: resource manager to iterate over
51962306a36Sopenharmony_ci * @cursor: cursor to record the position
52062306a36Sopenharmony_ci * @res: the current resource pointer
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * Returns the next resource from the resource manager.
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_cistruct ttm_resource *
52562306a36Sopenharmony_cittm_resource_manager_next(struct ttm_resource_manager *man,
52662306a36Sopenharmony_ci			  struct ttm_resource_cursor *cursor,
52762306a36Sopenharmony_ci			  struct ttm_resource *res)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	lockdep_assert_held(&man->bdev->lru_lock);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	list_for_each_entry_continue(res, &man->lru[cursor->priority], lru)
53262306a36Sopenharmony_ci		return res;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	for (++cursor->priority; cursor->priority < TTM_MAX_BO_PRIORITY;
53562306a36Sopenharmony_ci	     ++cursor->priority)
53662306a36Sopenharmony_ci		list_for_each_entry(res, &man->lru[cursor->priority], lru)
53762306a36Sopenharmony_ci			return res;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return NULL;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter *iter,
54362306a36Sopenharmony_ci					  struct iosys_map *dmap,
54462306a36Sopenharmony_ci					  pgoff_t i)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct ttm_kmap_iter_iomap *iter_io =
54762306a36Sopenharmony_ci		container_of(iter, typeof(*iter_io), base);
54862306a36Sopenharmony_ci	void __iomem *addr;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciretry:
55162306a36Sopenharmony_ci	while (i >= iter_io->cache.end) {
55262306a36Sopenharmony_ci		iter_io->cache.sg = iter_io->cache.sg ?
55362306a36Sopenharmony_ci			sg_next(iter_io->cache.sg) : iter_io->st->sgl;
55462306a36Sopenharmony_ci		iter_io->cache.i = iter_io->cache.end;
55562306a36Sopenharmony_ci		iter_io->cache.end += sg_dma_len(iter_io->cache.sg) >>
55662306a36Sopenharmony_ci			PAGE_SHIFT;
55762306a36Sopenharmony_ci		iter_io->cache.offs = sg_dma_address(iter_io->cache.sg) -
55862306a36Sopenharmony_ci			iter_io->start;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (i < iter_io->cache.i) {
56262306a36Sopenharmony_ci		iter_io->cache.end = 0;
56362306a36Sopenharmony_ci		iter_io->cache.sg = NULL;
56462306a36Sopenharmony_ci		goto retry;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs +
56862306a36Sopenharmony_ci				       (((resource_size_t)i - iter_io->cache.i)
56962306a36Sopenharmony_ci					<< PAGE_SHIFT));
57062306a36Sopenharmony_ci	iosys_map_set_vaddr_iomem(dmap, addr);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void ttm_kmap_iter_iomap_unmap_local(struct ttm_kmap_iter *iter,
57462306a36Sopenharmony_ci					    struct iosys_map *map)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	io_mapping_unmap_local(map->vaddr_iomem);
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic const struct ttm_kmap_iter_ops ttm_kmap_iter_io_ops = {
58062306a36Sopenharmony_ci	.map_local =  ttm_kmap_iter_iomap_map_local,
58162306a36Sopenharmony_ci	.unmap_local = ttm_kmap_iter_iomap_unmap_local,
58262306a36Sopenharmony_ci	.maps_tt = false,
58362306a36Sopenharmony_ci};
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci/**
58662306a36Sopenharmony_ci * ttm_kmap_iter_iomap_init - Initialize a struct ttm_kmap_iter_iomap
58762306a36Sopenharmony_ci * @iter_io: The struct ttm_kmap_iter_iomap to initialize.
58862306a36Sopenharmony_ci * @iomap: The struct io_mapping representing the underlying linear io_memory.
58962306a36Sopenharmony_ci * @st: sg_table into @iomap, representing the memory of the struct
59062306a36Sopenharmony_ci * ttm_resource.
59162306a36Sopenharmony_ci * @start: Offset that needs to be subtracted from @st to make
59262306a36Sopenharmony_ci * sg_dma_address(st->sgl) - @start == 0 for @iomap start.
59362306a36Sopenharmony_ci *
59462306a36Sopenharmony_ci * Return: Pointer to the embedded struct ttm_kmap_iter.
59562306a36Sopenharmony_ci */
59662306a36Sopenharmony_cistruct ttm_kmap_iter *
59762306a36Sopenharmony_cittm_kmap_iter_iomap_init(struct ttm_kmap_iter_iomap *iter_io,
59862306a36Sopenharmony_ci			 struct io_mapping *iomap,
59962306a36Sopenharmony_ci			 struct sg_table *st,
60062306a36Sopenharmony_ci			 resource_size_t start)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	iter_io->base.ops = &ttm_kmap_iter_io_ops;
60362306a36Sopenharmony_ci	iter_io->iomap = iomap;
60462306a36Sopenharmony_ci	iter_io->st = st;
60562306a36Sopenharmony_ci	iter_io->start = start;
60662306a36Sopenharmony_ci	memset(&iter_io->cache, 0, sizeof(iter_io->cache));
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return &iter_io->base;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_kmap_iter_iomap_init);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci/**
61362306a36Sopenharmony_ci * DOC: Linear io iterator
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * This code should die in the not too near future. Best would be if we could
61662306a36Sopenharmony_ci * make io-mapping use memremap for all io memory, and have memremap
61762306a36Sopenharmony_ci * implement a kmap_local functionality. We could then strip a huge amount of
61862306a36Sopenharmony_ci * code. These linear io iterators are implemented to mimic old functionality,
61962306a36Sopenharmony_ci * and they don't use kmap_local semantics at all internally. Rather ioremap or
62062306a36Sopenharmony_ci * friends, and at least on 32-bit they add global TLB flushes and points
62162306a36Sopenharmony_ci * of failure.
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void ttm_kmap_iter_linear_io_map_local(struct ttm_kmap_iter *iter,
62562306a36Sopenharmony_ci					      struct iosys_map *dmap,
62662306a36Sopenharmony_ci					      pgoff_t i)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct ttm_kmap_iter_linear_io *iter_io =
62962306a36Sopenharmony_ci		container_of(iter, typeof(*iter_io), base);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	*dmap = iter_io->dmap;
63262306a36Sopenharmony_ci	iosys_map_incr(dmap, i * PAGE_SIZE);
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic const struct ttm_kmap_iter_ops ttm_kmap_iter_linear_io_ops = {
63662306a36Sopenharmony_ci	.map_local =  ttm_kmap_iter_linear_io_map_local,
63762306a36Sopenharmony_ci	.maps_tt = false,
63862306a36Sopenharmony_ci};
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/**
64162306a36Sopenharmony_ci * ttm_kmap_iter_linear_io_init - Initialize an iterator for linear io memory
64262306a36Sopenharmony_ci * @iter_io: The iterator to initialize
64362306a36Sopenharmony_ci * @bdev: The TTM device
64462306a36Sopenharmony_ci * @mem: The ttm resource representing the iomap.
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * This function is for internal TTM use only. It sets up a memcpy kmap iterator
64762306a36Sopenharmony_ci * pointing at a linear chunk of io memory.
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * Return: A pointer to the embedded struct ttm_kmap_iter or error pointer on
65062306a36Sopenharmony_ci * failure.
65162306a36Sopenharmony_ci */
65262306a36Sopenharmony_cistruct ttm_kmap_iter *
65362306a36Sopenharmony_cittm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io,
65462306a36Sopenharmony_ci			     struct ttm_device *bdev,
65562306a36Sopenharmony_ci			     struct ttm_resource *mem)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	int ret;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	ret = ttm_mem_io_reserve(bdev, mem);
66062306a36Sopenharmony_ci	if (ret)
66162306a36Sopenharmony_ci		goto out_err;
66262306a36Sopenharmony_ci	if (!mem->bus.is_iomem) {
66362306a36Sopenharmony_ci		ret = -EINVAL;
66462306a36Sopenharmony_ci		goto out_io_free;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (mem->bus.addr) {
66862306a36Sopenharmony_ci		iosys_map_set_vaddr(&iter_io->dmap, mem->bus.addr);
66962306a36Sopenharmony_ci		iter_io->needs_unmap = false;
67062306a36Sopenharmony_ci	} else {
67162306a36Sopenharmony_ci		iter_io->needs_unmap = true;
67262306a36Sopenharmony_ci		memset(&iter_io->dmap, 0, sizeof(iter_io->dmap));
67362306a36Sopenharmony_ci		if (mem->bus.caching == ttm_write_combined)
67462306a36Sopenharmony_ci			iosys_map_set_vaddr_iomem(&iter_io->dmap,
67562306a36Sopenharmony_ci						  ioremap_wc(mem->bus.offset,
67662306a36Sopenharmony_ci							     mem->size));
67762306a36Sopenharmony_ci		else if (mem->bus.caching == ttm_cached)
67862306a36Sopenharmony_ci			iosys_map_set_vaddr(&iter_io->dmap,
67962306a36Sopenharmony_ci					    memremap(mem->bus.offset, mem->size,
68062306a36Sopenharmony_ci						     MEMREMAP_WB |
68162306a36Sopenharmony_ci						     MEMREMAP_WT |
68262306a36Sopenharmony_ci						     MEMREMAP_WC));
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		/* If uncached requested or if mapping cached or wc failed */
68562306a36Sopenharmony_ci		if (iosys_map_is_null(&iter_io->dmap))
68662306a36Sopenharmony_ci			iosys_map_set_vaddr_iomem(&iter_io->dmap,
68762306a36Sopenharmony_ci						  ioremap(mem->bus.offset,
68862306a36Sopenharmony_ci							  mem->size));
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		if (iosys_map_is_null(&iter_io->dmap)) {
69162306a36Sopenharmony_ci			ret = -ENOMEM;
69262306a36Sopenharmony_ci			goto out_io_free;
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	iter_io->base.ops = &ttm_kmap_iter_linear_io_ops;
69762306a36Sopenharmony_ci	return &iter_io->base;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ciout_io_free:
70062306a36Sopenharmony_ci	ttm_mem_io_free(bdev, mem);
70162306a36Sopenharmony_ciout_err:
70262306a36Sopenharmony_ci	return ERR_PTR(ret);
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci/**
70662306a36Sopenharmony_ci * ttm_kmap_iter_linear_io_fini - Clean up an iterator for linear io memory
70762306a36Sopenharmony_ci * @iter_io: The iterator to initialize
70862306a36Sopenharmony_ci * @bdev: The TTM device
70962306a36Sopenharmony_ci * @mem: The ttm resource representing the iomap.
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci * This function is for internal TTM use only. It cleans up a memcpy kmap
71262306a36Sopenharmony_ci * iterator initialized by ttm_kmap_iter_linear_io_init.
71362306a36Sopenharmony_ci */
71462306a36Sopenharmony_civoid
71562306a36Sopenharmony_cittm_kmap_iter_linear_io_fini(struct ttm_kmap_iter_linear_io *iter_io,
71662306a36Sopenharmony_ci			     struct ttm_device *bdev,
71762306a36Sopenharmony_ci			     struct ttm_resource *mem)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	if (iter_io->needs_unmap && iosys_map_is_set(&iter_io->dmap)) {
72062306a36Sopenharmony_ci		if (iter_io->dmap.is_iomem)
72162306a36Sopenharmony_ci			iounmap(iter_io->dmap.vaddr_iomem);
72262306a36Sopenharmony_ci		else
72362306a36Sopenharmony_ci			memunmap(iter_io->dmap.vaddr);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	ttm_mem_io_free(bdev, mem);
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic int ttm_resource_manager_show(struct seq_file *m, void *unused)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct ttm_resource_manager *man =
73462306a36Sopenharmony_ci		(struct ttm_resource_manager *)m->private;
73562306a36Sopenharmony_ci	struct drm_printer p = drm_seq_file_printer(m);
73662306a36Sopenharmony_ci	ttm_resource_manager_debug(man, &p);
73762306a36Sopenharmony_ci	return 0;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(ttm_resource_manager);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci#endif
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci/**
74462306a36Sopenharmony_ci * ttm_resource_manager_create_debugfs - Create debugfs entry for specified
74562306a36Sopenharmony_ci * resource manager.
74662306a36Sopenharmony_ci * @man: The TTM resource manager for which the debugfs stats file be creates
74762306a36Sopenharmony_ci * @parent: debugfs directory in which the file will reside
74862306a36Sopenharmony_ci * @name: The filename to create.
74962306a36Sopenharmony_ci *
75062306a36Sopenharmony_ci * This function setups up a debugfs file that can be used to look
75162306a36Sopenharmony_ci * at debug statistics of the specified ttm_resource_manager.
75262306a36Sopenharmony_ci */
75362306a36Sopenharmony_civoid ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man,
75462306a36Sopenharmony_ci					 struct dentry * parent,
75562306a36Sopenharmony_ci					 const char *name)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
75862306a36Sopenharmony_ci	debugfs_create_file(name, 0444, parent, man, &ttm_resource_manager_fops);
75962306a36Sopenharmony_ci#endif
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_resource_manager_create_debugfs);
762