diff options
Diffstat (limited to 'drivers/gpu/drm/ttm/ttm_resource.c')
| -rw-r--r-- | drivers/gpu/drm/ttm/ttm_resource.c | 253 | 
1 files changed, 245 insertions, 8 deletions
| diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 9a477f0fddee..20f9adcc3235 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -30,12 +30,145 @@  #include <drm/ttm/ttm_bo_driver.h>  /** + * ttm_lru_bulk_move_init - initialize a bulk move structure + * @bulk: the structure to init + * + * For now just memset the structure to zero. + */ +void ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk) +{ +	memset(bulk, 0, sizeof(*bulk)); +} +EXPORT_SYMBOL(ttm_lru_bulk_move_init); + +/** + * ttm_lru_bulk_move_tail - bulk move range of resources to the LRU tail. + * + * @bulk: bulk move structure + * + * Bulk move BOs to the LRU tail, only valid to use when driver makes sure that + * resource order never changes. Should be called with &ttm_device.lru_lock held. + */ +void ttm_lru_bulk_move_tail(struct ttm_lru_bulk_move *bulk) +{ +	unsigned i, j; + +	for (i = 0; i < TTM_NUM_MEM_TYPES; ++i) { +		for (j = 0; j < TTM_MAX_BO_PRIORITY; ++j) { +			struct ttm_lru_bulk_move_pos *pos = &bulk->pos[i][j]; +			struct ttm_resource_manager *man; + +			if (!pos->first) +				continue; + +			lockdep_assert_held(&pos->first->bo->bdev->lru_lock); +			dma_resv_assert_held(pos->first->bo->base.resv); +			dma_resv_assert_held(pos->last->bo->base.resv); + +			man = ttm_manager_type(pos->first->bo->bdev, i); +			list_bulk_move_tail(&man->lru[j], &pos->first->lru, +					    &pos->last->lru); +		} +	} +} +EXPORT_SYMBOL(ttm_lru_bulk_move_tail); + +/* Return the bulk move pos object for this resource */ +static struct ttm_lru_bulk_move_pos * +ttm_lru_bulk_move_pos(struct ttm_lru_bulk_move *bulk, struct ttm_resource *res) +{ +	return &bulk->pos[res->mem_type][res->bo->priority]; +} + +/* Move the resource to the tail of the bulk move range */ +static void ttm_lru_bulk_move_pos_tail(struct ttm_lru_bulk_move_pos *pos, +				       struct ttm_resource *res) +{ +	if (pos->last != res) { +		list_move(&res->lru, &pos->last->lru); +		pos->last = res; +	} +} + +/* Add the resource to a bulk_move cursor */ +static void ttm_lru_bulk_move_add(struct ttm_lru_bulk_move *bulk, +				  struct ttm_resource *res) +{ +	struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res); + +	if (!pos->first) { +		pos->first = res; +		pos->last = res; +	} else { +		ttm_lru_bulk_move_pos_tail(pos, res); +	} +} + +/* Remove the resource from a bulk_move range */ +static void ttm_lru_bulk_move_del(struct ttm_lru_bulk_move *bulk, +				  struct ttm_resource *res) +{ +	struct ttm_lru_bulk_move_pos *pos = ttm_lru_bulk_move_pos(bulk, res); + +	if (unlikely(pos->first == res && pos->last == res)) { +		pos->first = NULL; +		pos->last = NULL; +	} else if (pos->first == res) { +		pos->first = list_next_entry(res, lru); +	} else if (pos->last == res) { +		pos->last = list_prev_entry(res, lru); +	} else { +		list_move(&res->lru, &pos->last->lru); +	} +} + +/* Add the resource to a bulk move if the BO is configured for it */ +void ttm_resource_add_bulk_move(struct ttm_resource *res, +				struct ttm_buffer_object *bo) +{ +	if (bo->bulk_move && !bo->pin_count) +		ttm_lru_bulk_move_add(bo->bulk_move, res); +} + +/* Remove the resource from a bulk move if the BO is configured for it */ +void ttm_resource_del_bulk_move(struct ttm_resource *res, +				struct ttm_buffer_object *bo) +{ +	if (bo->bulk_move && !bo->pin_count) +		ttm_lru_bulk_move_del(bo->bulk_move, res); +} + +/* Move a resource to the LRU or bulk tail */ +void ttm_resource_move_to_lru_tail(struct ttm_resource *res) +{ +	struct ttm_buffer_object *bo = res->bo; +	struct ttm_device *bdev = bo->bdev; + +	lockdep_assert_held(&bo->bdev->lru_lock); + +	if (bo->pin_count) { +		list_move_tail(&res->lru, &bdev->pinned); + +	} else	if (bo->bulk_move) { +		struct ttm_lru_bulk_move_pos *pos = +			ttm_lru_bulk_move_pos(bo->bulk_move, res); + +		ttm_lru_bulk_move_pos_tail(pos, res); +	} else { +		struct ttm_resource_manager *man; + +		man = ttm_manager_type(bdev, res->mem_type); +		list_move_tail(&res->lru, &man->lru[bo->priority]); +	} +} + +/**   * ttm_resource_init - resource object constructure   * @bo: buffer object this resources is allocated for   * @place: placement of the resource   * @res: the resource object to inistilize   * - * Initialize a new resource object. Counterpart of &ttm_resource_fini. + * Initialize a new resource object. Counterpart of ttm_resource_fini().   */  void ttm_resource_init(struct ttm_buffer_object *bo,                         const struct ttm_place *place, @@ -55,7 +188,11 @@ void ttm_resource_init(struct ttm_buffer_object *bo,  	man = ttm_manager_type(bo->bdev, place->mem_type);  	spin_lock(&bo->bdev->lru_lock); -	man->usage += bo->base.size; +	if (bo->pin_count) +		list_add_tail(&res->lru, &bo->bdev->pinned); +	else +		list_add_tail(&res->lru, &man->lru[bo->priority]); +	man->usage += res->num_pages << PAGE_SHIFT;  	spin_unlock(&bo->bdev->lru_lock);  }  EXPORT_SYMBOL(ttm_resource_init); @@ -66,15 +203,19 @@ EXPORT_SYMBOL(ttm_resource_init);   * @res: the resource to clean up   *   * Should be used by resource manager backends to clean up the TTM resource - * objects before freeing the underlying structure. Counterpart of - * &ttm_resource_init + * objects before freeing the underlying structure. Makes sure the resource is + * removed from the LRU before destruction. + * Counterpart of ttm_resource_init().   */  void ttm_resource_fini(struct ttm_resource_manager *man,  		       struct ttm_resource *res)  { -	spin_lock(&man->bdev->lru_lock); -	man->usage -= res->bo->base.size; -	spin_unlock(&man->bdev->lru_lock); +	struct ttm_device *bdev = man->bdev; + +	spin_lock(&bdev->lru_lock); +	list_del_init(&res->lru); +	man->usage -= res->num_pages << PAGE_SHIFT; +	spin_unlock(&bdev->lru_lock);  }  EXPORT_SYMBOL(ttm_resource_fini); @@ -84,8 +225,16 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo,  {  	struct ttm_resource_manager *man =  		ttm_manager_type(bo->bdev, place->mem_type); +	int ret; + +	ret = man->func->alloc(man, bo, place, res_ptr); +	if (ret) +		return ret; -	return man->func->alloc(man, bo, place, res_ptr); +	spin_lock(&bo->bdev->lru_lock); +	ttm_resource_add_bulk_move(*res_ptr, bo); +	spin_unlock(&bo->bdev->lru_lock); +	return 0;  }  void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res) @@ -95,6 +244,9 @@ void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)  	if (!*res)  		return; +	spin_lock(&bo->bdev->lru_lock); +	ttm_resource_del_bulk_move(*res, bo); +	spin_unlock(&bo->bdev->lru_lock);  	man = ttm_manager_type(bo->bdev, (*res)->mem_type);  	man->func->free(man, *res);  	*res = NULL; @@ -273,6 +425,57 @@ void ttm_resource_manager_debug(struct ttm_resource_manager *man,  }  EXPORT_SYMBOL(ttm_resource_manager_debug); +/** + * ttm_resource_manager_first + * + * @man: resource manager to iterate over + * @cursor: cursor to record the position + * + * Returns the first resource from the resource manager. + */ +struct ttm_resource * +ttm_resource_manager_first(struct ttm_resource_manager *man, +			   struct ttm_resource_cursor *cursor) +{ +	struct ttm_resource *res; + +	lockdep_assert_held(&man->bdev->lru_lock); + +	for (cursor->priority = 0; cursor->priority < TTM_MAX_BO_PRIORITY; +	     ++cursor->priority) +		list_for_each_entry(res, &man->lru[cursor->priority], lru) +			return res; + +	return NULL; +} + +/** + * ttm_resource_manager_next + * + * @man: resource manager to iterate over + * @cursor: cursor to record the position + * @res: the current resource pointer + * + * Returns the next resource from the resource manager. + */ +struct ttm_resource * +ttm_resource_manager_next(struct ttm_resource_manager *man, +			  struct ttm_resource_cursor *cursor, +			  struct ttm_resource *res) +{ +	lockdep_assert_held(&man->bdev->lru_lock); + +	list_for_each_entry_continue(res, &man->lru[cursor->priority], lru) +		return res; + +	for (++cursor->priority; cursor->priority < TTM_MAX_BO_PRIORITY; +	     ++cursor->priority) +		list_for_each_entry(res, &man->lru[cursor->priority], lru) +			return res; + +	return NULL; +} +  static void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter *iter,  					  struct iosys_map *dmap,  					  pgoff_t i) @@ -461,3 +664,37 @@ ttm_kmap_iter_linear_io_fini(struct ttm_kmap_iter_linear_io *iter_io,  	ttm_mem_io_free(bdev, mem);  } + +#if defined(CONFIG_DEBUG_FS) + +static int ttm_resource_manager_show(struct seq_file *m, void *unused) +{ +	struct ttm_resource_manager *man = +		(struct ttm_resource_manager *)m->private; +	struct drm_printer p = drm_seq_file_printer(m); +	ttm_resource_manager_debug(man, &p); +	return 0; +} +DEFINE_SHOW_ATTRIBUTE(ttm_resource_manager); + +#endif + +/** + * ttm_resource_manager_create_debugfs - Create debugfs entry for specified + * resource manager. + * @man: The TTM resource manager for which the debugfs stats file be creates + * @parent: debugfs directory in which the file will reside + * @name: The filename to create. + * + * This function setups up a debugfs file that can be used to look + * at debug statistics of the specified ttm_resource_manager. + */ +void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man, +					 struct dentry * parent, +					 const char *name) +{ +#if defined(CONFIG_DEBUG_FS) +	debugfs_create_file(name, 0444, parent, man, &ttm_resource_manager_fops); +#endif +} +EXPORT_SYMBOL(ttm_resource_manager_create_debugfs); | 
