Skip to content

Commit 919bb54

Browse files
committed
drm/xe: Fix missing runtime outer protection for ggtt_remove_node
Defer the ggtt node removal to a thread if runtime_pm is not active. The ggtt node removal can be called from multiple places, including places where we cannot protect with outer callers and places we are within other locks. So, try to grab the runtime reference if the device is already active, otherwise defer the removal to a separate thread from where we are sure we can wake the device up. v2: - use xe wq instead of system wq (Matt and CI) - Avoid GFP_KERNEL to be future proof since this removal can be called from outside our drivers and we don't want to block if atomic is needed. (Brost) v3: amend forgot chunk declaring xe_device. v4: Use a xe_ggtt_region to encapsulate the node and remova info, wihtout the need for any memory allocation at runtime. v5: Actually fill the delayed_removal.invalidate (Brost) v6: - Ensure that ggtt_region is not freed before work finishes (Auld) - Own wq to ensures that the queued works are flushed before ggtt_fini (Brost) v7: also free ggtt_region on early !bound return (Auld) v8: Address the null deref (CI) v9: Based on the new xe_ggtt_node for the proper care of the lifetime of the object. v10: Redo the lost v5 change. (Brost) v11: Simplify the invalidate_on_remove (Lucas) Cc: Matthew Auld <[email protected]> Cc: Paulo Zanoni <[email protected]> Cc: Francois Dugast <[email protected]> Cc: Thomas Hellström <[email protected]> Cc: Matthew Brost <[email protected]> Reviewed-by: Lucas De Marchi <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Rodrigo Vivi <[email protected]>
1 parent 34e8042 commit 919bb54

File tree

2 files changed

+73
-39
lines changed

2 files changed

+73
-39
lines changed

drivers/gpu/drm/xe/xe_ggtt.c

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ static void ggtt_fini_early(struct drm_device *drm, void *arg)
161161
{
162162
struct xe_ggtt *ggtt = arg;
163163

164+
destroy_workqueue(ggtt->wq);
164165
mutex_destroy(&ggtt->lock);
165166
drm_mm_takedown(&ggtt->mm);
166167
}
@@ -242,6 +243,8 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
242243
else
243244
ggtt->pt_ops = &xelp_pt_ops;
244245

246+
ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, 0);
247+
245248
drm_mm_init(&ggtt->mm, xe_wopcm_size(xe),
246249
ggtt->size - xe_wopcm_size(xe));
247250
mutex_init(&ggtt->lock);
@@ -276,6 +279,68 @@ static void xe_ggtt_initial_clear(struct xe_ggtt *ggtt)
276279
mutex_unlock(&ggtt->lock);
277280
}
278281

282+
static void ggtt_node_remove(struct xe_ggtt_node *node)
283+
{
284+
struct xe_ggtt *ggtt = node->ggtt;
285+
struct xe_device *xe = tile_to_xe(ggtt->tile);
286+
bool bound;
287+
int idx;
288+
289+
if (!node || !node->ggtt)
290+
return;
291+
292+
bound = drm_dev_enter(&xe->drm, &idx);
293+
294+
mutex_lock(&ggtt->lock);
295+
if (bound)
296+
xe_ggtt_clear(ggtt, node->base.start, node->base.size);
297+
drm_mm_remove_node(&node->base);
298+
node->base.size = 0;
299+
mutex_unlock(&ggtt->lock);
300+
301+
if (!bound)
302+
goto free_node;
303+
304+
if (node->invalidate_on_remove)
305+
xe_ggtt_invalidate(ggtt);
306+
307+
drm_dev_exit(idx);
308+
309+
free_node:
310+
xe_ggtt_node_fini(node);
311+
}
312+
313+
static void ggtt_node_remove_work_func(struct work_struct *work)
314+
{
315+
struct xe_ggtt_node *node = container_of(work, typeof(*node),
316+
delayed_removal_work);
317+
struct xe_device *xe = tile_to_xe(node->ggtt->tile);
318+
319+
xe_pm_runtime_get(xe);
320+
ggtt_node_remove(node);
321+
xe_pm_runtime_put(xe);
322+
}
323+
324+
/**
325+
* xe_ggtt_node_remove - Remove a &xe_ggtt_node from the GGTT
326+
* @node: the &xe_ggtt_node to be removed
327+
* @invalidate: if node needs invalidation upon removal
328+
*/
329+
void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate)
330+
{
331+
struct xe_ggtt *ggtt = node->ggtt;
332+
struct xe_device *xe = tile_to_xe(ggtt->tile);
333+
334+
node->invalidate_on_remove = invalidate;
335+
336+
if (xe_pm_runtime_get_if_active(xe)) {
337+
ggtt_node_remove(node);
338+
xe_pm_runtime_put(xe);
339+
} else {
340+
queue_work(ggtt->wq, &node->delayed_removal_work);
341+
}
342+
}
343+
279344
/**
280345
* xe_ggtt_init - Regular non-early GGTT initialization
281346
* @ggtt: the &xe_ggtt to be initialized
@@ -471,7 +536,9 @@ struct xe_ggtt_node *xe_ggtt_node_init(struct xe_ggtt *ggtt)
471536
if (!node)
472537
return ERR_PTR(-ENOMEM);
473538

539+
INIT_WORK(&node->delayed_removal_work, ggtt_node_remove_work_func);
474540
node->ggtt = ggtt;
541+
475542
return node;
476543
}
477544

@@ -488,45 +555,6 @@ void xe_ggtt_node_fini(struct xe_ggtt_node *node)
488555
kfree(node);
489556
}
490557

491-
/**
492-
* xe_ggtt_node_remove - Remove a &xe_ggtt_node from the GGTT
493-
* @node: the &xe_ggtt_node to be removed
494-
* @invalidate: if node needs invalidation upon removal
495-
*/
496-
void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate)
497-
{
498-
struct xe_ggtt *ggtt = node->ggtt;
499-
struct xe_device *xe = tile_to_xe(ggtt->tile);
500-
bool bound;
501-
int idx;
502-
503-
if (!node || !node->ggtt)
504-
return;
505-
506-
bound = drm_dev_enter(&xe->drm, &idx);
507-
if (bound)
508-
xe_pm_runtime_get_noresume(xe);
509-
510-
mutex_lock(&ggtt->lock);
511-
if (bound)
512-
xe_ggtt_clear(ggtt, node->base.start, node->base.size);
513-
drm_mm_remove_node(&node->base);
514-
node->base.size = 0;
515-
mutex_unlock(&ggtt->lock);
516-
517-
if (!bound)
518-
goto free_node;
519-
520-
if (invalidate)
521-
xe_ggtt_invalidate(ggtt);
522-
523-
xe_pm_runtime_put(xe);
524-
drm_dev_exit(idx);
525-
526-
free_node:
527-
xe_ggtt_node_fini(node);
528-
}
529-
530558
/**
531559
* xe_ggtt_node_allocated - Check if node is allocated in GGTT
532560
* @node: the &xe_ggtt_node to be inspected

drivers/gpu/drm/xe/xe_ggtt_types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct xe_ggtt {
4747
struct drm_mm mm;
4848
/** @access_count: counts GGTT writes */
4949
unsigned int access_count;
50+
/** @wq: Dedicated unordered work queue to process node removals */
51+
struct workqueue_struct *wq;
5052
};
5153

5254
/**
@@ -61,6 +63,10 @@ struct xe_ggtt_node {
6163
struct xe_ggtt *ggtt;
6264
/** @base: A drm_mm_node */
6365
struct drm_mm_node base;
66+
/** @delayed_removal_work: The work struct for the delayed removal */
67+
struct work_struct delayed_removal_work;
68+
/** @invalidate_on_remove: If it needs invalidation upon removal */
69+
bool invalidate_on_remove;
6470
};
6571

6672
/**

0 commit comments

Comments
 (0)