mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
df9f85d858
The expected downside to commit58b4c1a07a
("drm/i915: Reduce nested prepare_remote_context() to a trylock") was that it would need to return -EAGAIN to userspace in order to resolve potential mutex inversion. Such an unsightly round trip is unnecessary if we could atomically insert a barrier into the i915_active_fence, so make it happen. Currently, we use the timeline->mutex (or some other named outer lock) to order insertion into the i915_active_fence (and so individual nodes of i915_active). Inside __i915_active_fence_set, we only need then serialise with the interrupt handler in order to claim the timeline for ourselves. However, if we remove the outer lock, we need to ensure the order is intact between not only multiple threads trying to insert themselves into the timeline, but also with the interrupt handler completing the previous occupant. We use xchg() on insert so that we have an ordered sequence of insertions (and each caller knows the previous fence on which to wait, preserving the chain of all fences in the timeline), but we then have to cmpxchg() in the interrupt handler to avoid overwriting the new occupant. The only nasty side-effect is having to temporarily strip off the RCU-annotations to apply the atomic operations, otherwise the rules are much more conventional! Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=112402 Fixes:58b4c1a07a
("drm/i915: Reduce nested prepare_remote_context() to a trylock") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20191127134527.3438410-1-chris@chris-wilson.co.uk
54 lines
1.1 KiB
C
54 lines
1.1 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright © 2019 Intel Corporation
|
|
*/
|
|
|
|
#ifndef _I915_ACTIVE_TYPES_H_
|
|
#define _I915_ACTIVE_TYPES_H_
|
|
|
|
#include <linux/atomic.h>
|
|
#include <linux/dma-fence.h>
|
|
#include <linux/llist.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
#include "i915_utils.h"
|
|
|
|
struct i915_active_fence {
|
|
struct dma_fence __rcu *fence;
|
|
struct dma_fence_cb cb;
|
|
};
|
|
|
|
struct active_node;
|
|
|
|
#define I915_ACTIVE_MAY_SLEEP BIT(0)
|
|
|
|
#define __i915_active_call __aligned(4)
|
|
#define i915_active_may_sleep(fn) ptr_pack_bits(&(fn), I915_ACTIVE_MAY_SLEEP, 2)
|
|
|
|
struct i915_active {
|
|
atomic_t count;
|
|
struct mutex mutex;
|
|
|
|
spinlock_t tree_lock;
|
|
struct active_node *cache;
|
|
struct rb_root tree;
|
|
|
|
/* Preallocated "exclusive" node */
|
|
struct i915_active_fence excl;
|
|
|
|
unsigned long flags;
|
|
#define I915_ACTIVE_RETIRE_SLEEPS BIT(0)
|
|
|
|
int (*active)(struct i915_active *ref);
|
|
void (*retire)(struct i915_active *ref);
|
|
|
|
struct work_struct work;
|
|
|
|
struct llist_head preallocated_barriers;
|
|
};
|
|
|
|
#endif /* _I915_ACTIVE_TYPES_H_ */
|