Skip to content

Commit 3cbb651

Browse files
author
Thomas Hellström
committed
drm/xe/bo: Add a bo remove callback
On device unbind, migrate exported bos, including pagemap bos to system. This allows importers to take proper action without disruption. In particular, SVM clients on remote devices may continue as if nothing happened, and can chose a different placement. The evict_flags() placement is chosen in such a way that bos that aren't exported are purged. For pinned bos, we unmap DMA, but their pages are not freed yet since we can't be 100% sure they are not accessed. All pinned external bos (not just the VRAM ones) are put on the pinned.external list with this patch. But this only affects the xe_bo_pci_dev_remove_pinned() function since !VRAM bos are ignored by the suspend / resume functionality. As a follow-up we could look at removing the suspend / resume iteration over pinned external bos since we currently don't allow pinning external bos in VRAM, and other external bos don't need any special treatment at suspend / resume. v2: - Address review comments. (Matthew Auld). v3: - Don't introduce an external_evicted list (Matthew Auld) - Add a discussion around suspend / resume behaviour to the commit message. - Formatting fixes. v4: - Move dma-unmaps of pinned kernel bos to a dev managed callback to give subsystems using these bos a chance to clean them up. (Matthew Auld) Signed-off-by: Thomas Hellström <[email protected]> Reviewed-by: Matthew Auld <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c9db07c commit 3cbb651

File tree

6 files changed

+140
-17
lines changed

6 files changed

+140
-17
lines changed

drivers/gpu/drm/xe/xe_bo.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ static struct ttm_placement sys_placement = {
5555
.placement = &sys_placement_flags,
5656
};
5757

58+
static struct ttm_placement purge_placement;
59+
5860
static const struct ttm_place tt_placement_flags[] = {
5961
{
6062
.fpfn = 0,
@@ -281,6 +283,8 @@ int xe_bo_placement_for_flags(struct xe_device *xe, struct xe_bo *bo,
281283
static void xe_evict_flags(struct ttm_buffer_object *tbo,
282284
struct ttm_placement *placement)
283285
{
286+
struct xe_device *xe = container_of(tbo->bdev, typeof(*xe), ttm);
287+
bool device_unplugged = drm_dev_is_unplugged(&xe->drm);
284288
struct xe_bo *bo;
285289

286290
if (!xe_bo_is_xe_bo(tbo)) {
@@ -290,7 +294,7 @@ static void xe_evict_flags(struct ttm_buffer_object *tbo,
290294
return;
291295
}
292296

293-
*placement = sys_placement;
297+
*placement = device_unplugged ? purge_placement : sys_placement;
294298
return;
295299
}
296300

@@ -300,6 +304,11 @@ static void xe_evict_flags(struct ttm_buffer_object *tbo,
300304
return;
301305
}
302306

307+
if (device_unplugged && !tbo->base.dma_buf) {
308+
*placement = purge_placement;
309+
return;
310+
}
311+
303312
/*
304313
* For xe, sg bos that are evicted to system just triggers a
305314
* rebind of the sg list upon subsequent validation to XE_PL_TT.
@@ -657,11 +666,20 @@ static int xe_bo_move_dmabuf(struct ttm_buffer_object *ttm_bo,
657666
struct xe_ttm_tt *xe_tt = container_of(ttm_bo->ttm, struct xe_ttm_tt,
658667
ttm);
659668
struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev);
669+
bool device_unplugged = drm_dev_is_unplugged(&xe->drm);
660670
struct sg_table *sg;
661671

662672
xe_assert(xe, attach);
663673
xe_assert(xe, ttm_bo->ttm);
664674

675+
if (device_unplugged && new_res->mem_type == XE_PL_SYSTEM &&
676+
ttm_bo->sg) {
677+
dma_resv_wait_timeout(ttm_bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
678+
false, MAX_SCHEDULE_TIMEOUT);
679+
dma_buf_unmap_attachment(attach, ttm_bo->sg, DMA_BIDIRECTIONAL);
680+
ttm_bo->sg = NULL;
681+
}
682+
665683
if (new_res->mem_type == XE_PL_SYSTEM)
666684
goto out;
667685

@@ -1224,6 +1242,31 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
12241242
return ret;
12251243
}
12261244

1245+
int xe_bo_dma_unmap_pinned(struct xe_bo *bo)
1246+
{
1247+
struct ttm_buffer_object *ttm_bo = &bo->ttm;
1248+
struct ttm_tt *tt = ttm_bo->ttm;
1249+
1250+
if (tt) {
1251+
struct xe_ttm_tt *xe_tt = container_of(tt, typeof(*xe_tt), ttm);
1252+
1253+
if (ttm_bo->type == ttm_bo_type_sg && ttm_bo->sg) {
1254+
dma_buf_unmap_attachment(ttm_bo->base.import_attach,
1255+
ttm_bo->sg,
1256+
DMA_BIDIRECTIONAL);
1257+
ttm_bo->sg = NULL;
1258+
xe_tt->sg = NULL;
1259+
} else if (xe_tt->sg) {
1260+
dma_unmap_sgtable(xe_tt->xe->drm.dev, xe_tt->sg,
1261+
DMA_BIDIRECTIONAL, 0);
1262+
sg_free_table(xe_tt->sg);
1263+
xe_tt->sg = NULL;
1264+
}
1265+
}
1266+
1267+
return 0;
1268+
}
1269+
12271270
static unsigned long xe_ttm_io_mem_pfn(struct ttm_buffer_object *ttm_bo,
12281271
unsigned long page_offset)
12291272
{
@@ -2102,12 +2145,9 @@ int xe_bo_pin_external(struct xe_bo *bo)
21022145
if (err)
21032146
return err;
21042147

2105-
if (xe_bo_is_vram(bo)) {
2106-
spin_lock(&xe->pinned.lock);
2107-
list_add_tail(&bo->pinned_link,
2108-
&xe->pinned.external_vram);
2109-
spin_unlock(&xe->pinned.lock);
2110-
}
2148+
spin_lock(&xe->pinned.lock);
2149+
list_add_tail(&bo->pinned_link, &xe->pinned.external);
2150+
spin_unlock(&xe->pinned.lock);
21112151
}
21122152

21132153
ttm_bo_pin(&bo->ttm);

drivers/gpu/drm/xe/xe_bo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ int xe_bo_evict(struct xe_bo *bo, bool force_alloc);
276276
int xe_bo_evict_pinned(struct xe_bo *bo);
277277
int xe_bo_restore_pinned(struct xe_bo *bo);
278278

279+
int xe_bo_dma_unmap_pinned(struct xe_bo *bo);
280+
279281
extern const struct ttm_device_funcs xe_ttm_funcs;
280282
extern const char *const xe_mem_type_to_name[];
281283

drivers/gpu/drm/xe/xe_bo_evict.c

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ int xe_bo_evict_all(struct xe_device *xe)
9393
}
9494
}
9595

96-
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.external_vram,
97-
&xe->pinned.external_vram,
96+
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.external,
97+
&xe->pinned.external,
9898
xe_bo_evict_pinned);
9999

100100
/*
@@ -181,8 +181,8 @@ int xe_bo_restore_user(struct xe_device *xe)
181181
return 0;
182182

183183
/* Pinned user memory in VRAM should be validated on resume */
184-
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.external_vram,
185-
&xe->pinned.external_vram,
184+
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.external,
185+
&xe->pinned.external,
186186
xe_bo_restore_pinned);
187187

188188
/* Wait for restore to complete */
@@ -191,3 +191,79 @@ int xe_bo_restore_user(struct xe_device *xe)
191191

192192
return ret;
193193
}
194+
195+
static void xe_bo_pci_dev_remove_pinned(struct xe_device *xe)
196+
{
197+
struct xe_tile *tile;
198+
unsigned int id;
199+
200+
(void)xe_bo_apply_to_pinned(xe, &xe->pinned.external,
201+
&xe->pinned.external,
202+
xe_bo_dma_unmap_pinned);
203+
for_each_tile(tile, xe, id)
204+
xe_tile_migrate_wait(tile);
205+
}
206+
207+
/**
208+
* xe_bo_pci_dev_remove_all() - Handle bos when the pci_device is about to be removed
209+
* @xe: The xe device.
210+
*
211+
* On pci_device removal we need to drop all dma mappings and move
212+
* the data of exported bos out to system. This includes SVM bos and
213+
* exported dma-buf bos. This is done by evicting all bos, but
214+
* the evict placement in xe_evict_flags() is chosen such that all
215+
* bos except those mentioned are purged, and thus their memory
216+
* is released.
217+
*
218+
* For pinned bos, we're unmapping dma.
219+
*/
220+
void xe_bo_pci_dev_remove_all(struct xe_device *xe)
221+
{
222+
unsigned int mem_type;
223+
224+
/*
225+
* Move pagemap bos and exported dma-buf to system, and
226+
* purge everything else.
227+
*/
228+
for (mem_type = XE_PL_VRAM1; mem_type >= XE_PL_TT; --mem_type) {
229+
struct ttm_resource_manager *man =
230+
ttm_manager_type(&xe->ttm, mem_type);
231+
232+
if (man) {
233+
int ret = ttm_resource_manager_evict_all(&xe->ttm, man);
234+
235+
drm_WARN_ON(&xe->drm, ret);
236+
}
237+
}
238+
239+
xe_bo_pci_dev_remove_pinned(xe);
240+
}
241+
242+
static void xe_bo_pinned_fini(void *arg)
243+
{
244+
struct xe_device *xe = arg;
245+
246+
(void)xe_bo_apply_to_pinned(xe, &xe->pinned.kernel_bo_present,
247+
&xe->pinned.kernel_bo_present,
248+
xe_bo_dma_unmap_pinned);
249+
}
250+
251+
/**
252+
* xe_bo_pinned_init() - Initialize pinned bo tracking
253+
* @xe: The xe device.
254+
*
255+
* Initializes the lists and locks required for pinned bo
256+
* tracking and registers a callback to dma-unmap
257+
* any remaining pinned bos on pci device removal.
258+
*
259+
* Return: %0 on success, negative error code on error.
260+
*/
261+
int xe_bo_pinned_init(struct xe_device *xe)
262+
{
263+
spin_lock_init(&xe->pinned.lock);
264+
INIT_LIST_HEAD(&xe->pinned.kernel_bo_present);
265+
INIT_LIST_HEAD(&xe->pinned.external);
266+
INIT_LIST_HEAD(&xe->pinned.evicted);
267+
268+
return devm_add_action_or_reset(xe->drm.dev, xe_bo_pinned_fini, xe);
269+
}

drivers/gpu/drm/xe/xe_bo_evict.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ int xe_bo_evict_all(struct xe_device *xe);
1212
int xe_bo_restore_kernel(struct xe_device *xe);
1313
int xe_bo_restore_user(struct xe_device *xe);
1414

15+
void xe_bo_pci_dev_remove_all(struct xe_device *xe);
16+
17+
int xe_bo_pinned_init(struct xe_device *xe);
1518
#endif

drivers/gpu/drm/xe/xe_device.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "regs/xe_gt_regs.h"
2424
#include "regs/xe_regs.h"
2525
#include "xe_bo.h"
26+
#include "xe_bo_evict.h"
2627
#include "xe_debugfs.h"
2728
#include "xe_devcoredump.h"
2829
#include "xe_dma_buf.h"
@@ -467,10 +468,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
467468
xa_erase(&xe->usm.asid_to_vm, asid);
468469
}
469470

470-
spin_lock_init(&xe->pinned.lock);
471-
INIT_LIST_HEAD(&xe->pinned.kernel_bo_present);
472-
INIT_LIST_HEAD(&xe->pinned.external_vram);
473-
INIT_LIST_HEAD(&xe->pinned.evicted);
471+
err = xe_bo_pinned_init(xe);
472+
if (err)
473+
goto err;
474474

475475
xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq",
476476
WQ_MEM_RECLAIM);
@@ -939,6 +939,8 @@ void xe_device_remove(struct xe_device *xe)
939939
xe_display_unregister(xe);
940940

941941
drm_dev_unplug(&xe->drm);
942+
943+
xe_bo_pci_dev_remove_all(xe);
942944
}
943945

944946
void xe_device_shutdown(struct xe_device *xe)

drivers/gpu/drm/xe/xe_device_types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,8 @@ struct xe_device {
426426
struct list_head kernel_bo_present;
427427
/** @pinned.evicted: pinned BO that have been evicted */
428428
struct list_head evicted;
429-
/** @pinned.external_vram: pinned external BO in vram*/
430-
struct list_head external_vram;
429+
/** @pinned.external: pinned external and dma-buf. */
430+
struct list_head external;
431431
} pinned;
432432

433433
/** @ufence_wq: user fence wait queue */

0 commit comments

Comments
 (0)