// SPDX-License-Identifier: MIT /* * Copyright © 2023 Intel Corporation */ #include #include #include #include "xe_macros.h" #include "xe_range_fence.h" #define XE_RANGE_TREE_START(_node) ((_node)->start) #define XE_RANGE_TREE_LAST(_node) ((_node)->last) INTERVAL_TREE_DEFINE(struct xe_range_fence, rb, u64, __subtree_last, XE_RANGE_TREE_START, XE_RANGE_TREE_LAST, static, xe_range_fence_tree); static void xe_range_fence_signal_notify(struct dma_fence *fence, struct dma_fence_cb *cb) { struct xe_range_fence *rfence = container_of(cb, typeof(*rfence), cb); struct xe_range_fence_tree *tree = rfence->tree; llist_add(&rfence->link, &tree->list); } static bool __xe_range_fence_tree_cleanup(struct xe_range_fence_tree *tree) { struct llist_node *node = llist_del_all(&tree->list); struct xe_range_fence *rfence, *next; llist_for_each_entry_safe(rfence, next, node, link) { xe_range_fence_tree_remove(rfence, &tree->root); dma_fence_put(rfence->fence); kfree(rfence); } return !!node; } /** * xe_range_fence_insert() - range fence insert * @tree: range fence tree to insert intoi * @rfence: range fence * @ops: range fence ops * @start: start address of range fence * @last: last address of range fence * @fence: dma fence which signals range fence can be removed + freed * * Return: 0 on success, non-zero on failure */ int xe_range_fence_insert(struct xe_range_fence_tree *tree, struct xe_range_fence *rfence, const struct xe_range_fence_ops *ops, u64 start, u64 last, struct dma_fence *fence) { int err = 0; __xe_range_fence_tree_cleanup(tree); if (dma_fence_is_signaled(fence)) goto free; rfence->ops = ops; rfence->start = start; rfence->last = last; rfence->tree = tree; rfence->fence = dma_fence_get(fence); err = dma_fence_add_callback(fence, &rfence->cb, xe_range_fence_signal_notify); if (err == -ENOENT) { dma_fence_put(fence); err = 0; goto free; } else if (err == 0) { xe_range_fence_tree_insert(rfence, &tree->root); return 0; } free: if (ops->free) ops->free(rfence); return err; } static void xe_range_fence_tree_remove_all(struct xe_range_fence_tree *tree) { struct xe_range_fence *rfence; bool retry = true; rfence = xe_range_fence_tree_iter_first(&tree->root, 0, U64_MAX); while (rfence) { /* Should be ok with the minimalistic callback */ if (dma_fence_remove_callback(rfence->fence, &rfence->cb)) llist_add(&rfence->link, &tree->list); rfence = xe_range_fence_tree_iter_next(rfence, 0, U64_MAX); } while (retry) retry = __xe_range_fence_tree_cleanup(tree); } /** * xe_range_fence_tree_init() - Init range fence tree * @tree: range fence tree */ void xe_range_fence_tree_init(struct xe_range_fence_tree *tree) { memset(tree, 0, sizeof(*tree)); } /** * xe_range_fence_tree_fini() - Fini range fence tree * @tree: range fence tree */ void xe_range_fence_tree_fini(struct xe_range_fence_tree *tree) { xe_range_fence_tree_remove_all(tree); XE_WARN_ON(!RB_EMPTY_ROOT(&tree->root.rb_root)); } /** * xe_range_fence_tree_first() - range fence tree iterator first * @tree: range fence tree * @start: start address of range fence * @last: last address of range fence * * Return: first range fence found in range or NULL */ struct xe_range_fence * xe_range_fence_tree_first(struct xe_range_fence_tree *tree, u64 start, u64 last) { return xe_range_fence_tree_iter_first(&tree->root, start, last); } /** * xe_range_fence_tree_next() - range fence tree iterator next * @rfence: current range fence * @start: start address of range fence * @last: last address of range fence * * Return: next range fence found in range or NULL */ struct xe_range_fence * xe_range_fence_tree_next(struct xe_range_fence *rfence, u64 start, u64 last) { return xe_range_fence_tree_iter_next(rfence, start, last); } static void xe_range_fence_free(struct xe_range_fence *rfence) { kfree(rfence); } const struct xe_range_fence_ops xe_range_fence_kfree_ops = { .free = xe_range_fence_free, };