Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2022 Intel Corporation
  4 */
  5
  6#include "xe_bo_evict.h"
  7
  8#include "xe_bo.h"
  9#include "xe_device.h"
 10#include "xe_ggtt.h"
 11#include "xe_tile.h"
 12
 13/**
 14 * xe_bo_evict_all - evict all BOs from VRAM
 15 *
 16 * @xe: xe device
 17 *
 18 * Evict non-pinned user BOs first (via GPU), evict pinned external BOs next
 19 * (via GPU), wait for evictions, and finally evict pinned kernel BOs via CPU.
 20 * All eviction magic done via TTM calls.
 21 *
 22 * Evict == move VRAM BOs to temporary (typically system) memory.
 23 *
 24 * This function should be called before the device goes into a suspend state
 25 * where the VRAM loses power.
 26 */
 27int xe_bo_evict_all(struct xe_device *xe)
 28{
 29	struct ttm_device *bdev = &xe->ttm;
 30	struct xe_bo *bo;
 31	struct xe_tile *tile;
 32	struct list_head still_in_list;
 33	u32 mem_type;
 34	u8 id;
 35	int ret;
 36
 37	if (!IS_DGFX(xe))
 38		return 0;
 39
 40	/* User memory */
 41	for (mem_type = XE_PL_VRAM0; mem_type <= XE_PL_VRAM1; ++mem_type) {
 42		struct ttm_resource_manager *man =
 43			ttm_manager_type(bdev, mem_type);
 44
 45		if (man) {
 46			ret = ttm_resource_manager_evict_all(bdev, man);
 47			if (ret)
 48				return ret;
 49		}
 50	}
 51
 52	/* Pinned user memory in VRAM */
 53	INIT_LIST_HEAD(&still_in_list);
 54	spin_lock(&xe->pinned.lock);
 55	for (;;) {
 56		bo = list_first_entry_or_null(&xe->pinned.external_vram,
 57					      typeof(*bo), pinned_link);
 58		if (!bo)
 59			break;
 60		xe_bo_get(bo);
 61		list_move_tail(&bo->pinned_link, &still_in_list);
 62		spin_unlock(&xe->pinned.lock);
 63
 64		xe_bo_lock(bo, false);
 65		ret = xe_bo_evict_pinned(bo);
 66		xe_bo_unlock(bo);
 67		xe_bo_put(bo);
 68		if (ret) {
 69			spin_lock(&xe->pinned.lock);
 70			list_splice_tail(&still_in_list,
 71					 &xe->pinned.external_vram);
 72			spin_unlock(&xe->pinned.lock);
 73			return ret;
 74		}
 75
 76		spin_lock(&xe->pinned.lock);
 77	}
 78	list_splice_tail(&still_in_list, &xe->pinned.external_vram);
 79	spin_unlock(&xe->pinned.lock);
 80
 81	/*
 82	 * Wait for all user BO to be evicted as those evictions depend on the
 83	 * memory moved below.
 84	 */
 85	for_each_tile(tile, xe, id)
 86		xe_tile_migrate_wait(tile);
 87
 88	spin_lock(&xe->pinned.lock);
 89	for (;;) {
 90		bo = list_first_entry_or_null(&xe->pinned.kernel_bo_present,
 91					      typeof(*bo), pinned_link);
 92		if (!bo)
 93			break;
 94		xe_bo_get(bo);
 95		list_move_tail(&bo->pinned_link, &xe->pinned.evicted);
 96		spin_unlock(&xe->pinned.lock);
 97
 98		xe_bo_lock(bo, false);
 99		ret = xe_bo_evict_pinned(bo);
100		xe_bo_unlock(bo);
101		xe_bo_put(bo);
102		if (ret)
103			return ret;
104
105		spin_lock(&xe->pinned.lock);
106	}
107	spin_unlock(&xe->pinned.lock);
108
109	return 0;
110}
111
112/**
113 * xe_bo_restore_kernel - restore kernel BOs to VRAM
114 *
115 * @xe: xe device
116 *
117 * Move kernel BOs from temporary (typically system) memory to VRAM via CPU. All
118 * moves done via TTM calls.
119 *
120 * This function should be called early, before trying to init the GT, on device
121 * resume.
122 */
123int xe_bo_restore_kernel(struct xe_device *xe)
124{
125	struct xe_bo *bo;
126	int ret;
127
128	if (!IS_DGFX(xe))
129		return 0;
130
131	spin_lock(&xe->pinned.lock);
132	for (;;) {
133		bo = list_first_entry_or_null(&xe->pinned.evicted,
134					      typeof(*bo), pinned_link);
135		if (!bo)
136			break;
137		xe_bo_get(bo);
138		list_move_tail(&bo->pinned_link, &xe->pinned.kernel_bo_present);
139		spin_unlock(&xe->pinned.lock);
140
141		xe_bo_lock(bo, false);
142		ret = xe_bo_restore_pinned(bo);
143		xe_bo_unlock(bo);
144		if (ret) {
145			xe_bo_put(bo);
146			return ret;
147		}
148
149		if (bo->flags & XE_BO_CREATE_GGTT_BIT) {
150			struct xe_tile *tile = bo->tile;
151
152			mutex_lock(&tile->mem.ggtt->lock);
153			xe_ggtt_map_bo(tile->mem.ggtt, bo);
154			mutex_unlock(&tile->mem.ggtt->lock);
155		}
156
157		/*
158		 * We expect validate to trigger a move VRAM and our move code
159		 * should setup the iosys map.
160		 */
161		xe_assert(xe, !iosys_map_is_null(&bo->vmap));
162		xe_assert(xe, xe_bo_is_vram(bo));
163
164		xe_bo_put(bo);
165
166		spin_lock(&xe->pinned.lock);
167	}
168	spin_unlock(&xe->pinned.lock);
169
170	return 0;
171}
172
173/**
174 * xe_bo_restore_user - restore pinned user BOs to VRAM
175 *
176 * @xe: xe device
177 *
178 * Move pinned user BOs from temporary (typically system) memory to VRAM via
179 * CPU. All moves done via TTM calls.
180 *
181 * This function should be called late, after GT init, on device resume.
182 */
183int xe_bo_restore_user(struct xe_device *xe)
184{
185	struct xe_bo *bo;
186	struct xe_tile *tile;
187	struct list_head still_in_list;
188	u8 id;
189	int ret;
190
191	if (!IS_DGFX(xe))
192		return 0;
193
194	/* Pinned user memory in VRAM should be validated on resume */
195	INIT_LIST_HEAD(&still_in_list);
196	spin_lock(&xe->pinned.lock);
197	for (;;) {
198		bo = list_first_entry_or_null(&xe->pinned.external_vram,
199					      typeof(*bo), pinned_link);
200		if (!bo)
201			break;
202		list_move_tail(&bo->pinned_link, &still_in_list);
203		xe_bo_get(bo);
204		spin_unlock(&xe->pinned.lock);
205
206		xe_bo_lock(bo, false);
207		ret = xe_bo_restore_pinned(bo);
208		xe_bo_unlock(bo);
209		xe_bo_put(bo);
210		if (ret) {
211			spin_lock(&xe->pinned.lock);
212			list_splice_tail(&still_in_list,
213					 &xe->pinned.external_vram);
214			spin_unlock(&xe->pinned.lock);
215			return ret;
216		}
217
218		spin_lock(&xe->pinned.lock);
219	}
220	list_splice_tail(&still_in_list, &xe->pinned.external_vram);
221	spin_unlock(&xe->pinned.lock);
222
223	/* Wait for validate to complete */
224	for_each_tile(tile, xe, id)
225		xe_tile_migrate_wait(tile);
226
227	return 0;
228}