aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch208
1 files changed, 208 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch
new file mode 100644
index 00000000..02cc3b87
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3156-dma-buf-add-dma_fence_chain_remove_fence.patch
@@ -0,0 +1,208 @@
+From 0e942c4a21d90c92b458829ca0ffd708fbf5dd26 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
+Date: Fri, 28 Jun 2019 09:43:38 +0200
+Subject: [PATCH 3156/4256] dma-buf: add dma_fence_chain_remove_fence
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add helpers to remove a fence from a dma_fence_chain.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+---
+ drivers/dma-buf/dma-fence-chain.c | 133 ++++++++++++++++++++++++------
+ include/linux/dma-fence-chain.h | 1 +
+ 2 files changed, 107 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c
+index c13ddc62107b..58fc68ed5df9 100644
+--- a/drivers/dma-buf/dma-fence-chain.c
++++ b/drivers/dma-buf/dma-fence-chain.c
+@@ -20,22 +20,67 @@
+ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence);
+
+ /**
+- * dma_fence_chain_get_prev - use RCU to get a reference to the previous fence
+- * @chain: chain node to get the previous node from
++ * dma_fence_chain_get - use RCU to get a reference to a fence
++ * @pfence: rcu protected fence pointer
+ *
+- * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+- * chain node.
++ * Use dma_fence_get_rcu_safe to get a reference to a fence in a chain.
+ */
+-static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)
++static struct dma_fence *dma_fence_chain_get(struct dma_fence __rcu **pfence)
+ {
+ struct dma_fence *prev;
+
+ rcu_read_lock();
+- prev = dma_fence_get_rcu_safe(&chain->prev);
++ prev = dma_fence_get_rcu_safe(pfence);
+ rcu_read_unlock();
+ return prev;
+ }
+
++/**
++ * dma_fence_chain_is_dead - check if dma_fence_chain should be unlinked
++ * @fence: fence to check
++ *
++ * If @fence is a dma_fence_chain node we check if the contained fence is
++ * signaled, otherwise we check if just this fence is signaled.
++ */
++static bool dma_fence_chain_is_dead(struct dma_fence *fence)
++{
++ struct dma_fence_chain *chain = to_dma_fence_chain(fence);
++
++ if (chain)
++ return dma_fence_is_signaled(chain->fence);
++
++ return dma_fence_is_signaled(fence);
++}
++
++/**
++ * dma_fence_chain_unlink - make an RCU safe removal of a chain node
++ * @pfence: the pointer to replace
++ * @old: the current value of that pointer
++ *
++ * Tries to replace the RCU protected value of pointer @pfence with the previous
++ * fence in the chain. The reference to the old fence is dropped no matter if
++ * the exchange was succesfully or not.
++ */
++static void dma_fence_chain_unlink(struct dma_fence __rcu **pfence,
++ struct dma_fence *old)
++{
++ struct dma_fence *replacement, *tmp;
++ struct dma_fence_chain *chain;
++
++ chain = to_dma_fence_chain(old);
++ if (chain)
++ replacement = dma_fence_chain_get(&chain->prev);
++ else
++ replacement = NULL;
++
++ tmp = cmpxchg((void **)pfence, (void *)current, (void *)replacement);
++ if (tmp == old)
++ dma_fence_put(tmp);
++ else
++ dma_fence_put(replacement);
++ dma_fence_put(old);
++}
++
+ /**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+@@ -46,8 +91,8 @@ static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)
+ */
+ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+ {
+- struct dma_fence_chain *chain, *prev_chain;
+- struct dma_fence *prev, *replacement, *tmp;
++ struct dma_fence_chain *chain;
++ struct dma_fence *prev;
+
+ chain = to_dma_fence_chain(fence);
+ if (!chain) {
+@@ -55,27 +100,12 @@ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+ return NULL;
+ }
+
+- while ((prev = dma_fence_chain_get_prev(chain))) {
+-
+- prev_chain = to_dma_fence_chain(prev);
+- if (prev_chain) {
+- if (!dma_fence_is_signaled(prev_chain->fence))
+- break;
+-
+- replacement = dma_fence_chain_get_prev(prev_chain);
+- } else {
+- if (!dma_fence_is_signaled(prev))
+- break;
++ while ((prev = dma_fence_chain_get(&chain->prev))) {
+
+- replacement = NULL;
+- }
++ if (!dma_fence_chain_is_dead(prev))
++ break;
+
+- tmp = cmpxchg((void **)&chain->prev, (void *)prev, (void *)replacement);
+- if (tmp == prev)
+- dma_fence_put(tmp);
+- else
+- dma_fence_put(replacement);
+- dma_fence_put(prev);
++ dma_fence_chain_unlink(&chain->prev, prev);
+ }
+
+ dma_fence_put(fence);
+@@ -116,6 +146,55 @@ int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)
+ }
+ EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
++/**
++ * dma_fence_chain_remove_fences - remove fences from a chain
++ * @pfence: pointer to the chain node where to start
++ * @cb: callback to decide if fence should be removed
++ * @data: data for the callback
++ *
++ * Iterate over the chain nodes until we can be sure that there are no more
++ * fences which should be removed.
++ *
++ * To remove a node we need to iterate at least twice to make sure we doesn't
++ * collide with concurrent operations.
++ */
++void dma_fence_chain_remove_fence(struct dma_fence __rcu **pfence,
++ bool (*cb)(struct dma_fence *f, void *data),
++ void *data)
++{
++ struct dma_fence_chain *chain = NULL;
++ struct dma_fence **prev, *fence;
++
++retry:
++ prev = pfence;
++ while ((fence = dma_fence_chain_get(prev))) {
++ dma_fence_put(&chain->base);
++ chain = to_dma_fence_chain(fence);
++
++ if (dma_fence_chain_is_dead(fence)) {
++ dma_fence_chain_unlink(prev, fence);
++ continue;
++ }
++
++ if (cb(chain ? chain->fence : fence, data)) {
++ dma_fence_chain_unlink(prev, fence);
++ /* Restart the search cause it can be that the previous
++ * chain is unlinked just as we try to unlink this one.
++ */
++ goto retry;
++ }
++
++ if (!chain) {
++ dma_fence_put(fence);
++ break;
++ }
++
++ prev = &chain->prev;
++ }
++ dma_fence_put(&chain->base);
++}
++EXPORT_SYMBOL(dma_fence_chain_remove_fence);
++
+ static const char *dma_fence_chain_get_driver_name(struct dma_fence *fence)
+ {
+ return "dma_fence_chain";
+diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h
+index 7466d7b8837e..694f35fb2b5e 100644
+--- a/include/linux/dma-fence-chain.h
++++ b/include/linux/dma-fence-chain.h
+@@ -107,6 +107,7 @@ dma_fence_chain_unwrap(struct dma_fence *fence)
+
+ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+ int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno);
++void dma_fence_chain_purge_ctx(struct dma_fence **pfence, uint64_t ctx);
+ void dma_fence_chain_init(struct dma_fence_chain *chain,
+ struct dma_fence *prev,
+ struct dma_fence *fence,
+--
+2.17.1
+