File Index
Files and directories
Sign in
FILE

i915_wait_util.h

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/i915_wait_util.h C
  1/* SPDX-License-Identifier: MIT */
  2/* Copyright © 2025 Intel Corporation */
  3
  4#ifndef __I915_WAIT_UTIL_H__
  5#define __I915_WAIT_UTIL_H__
  6
  7#include <linux/compiler.h>
  8#include <linux/delay.h>
  9#include <linux/ktime.h>
 10#include <linux/sched/clock.h>
 11#include <linux/smp.h>
 12
 13/*
 14 * __wait_for - magic wait macro
 15 *
 16 * Macro to help avoid open coding check/wait/timeout patterns. Note that it's
 17 * important that we check the condition again after having timed out, since the
 18 * timeout could be due to preemption or similar and we've never had a chance to
 19 * check the condition before the timeout.
 20 */
 21#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \
 22	const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll * (US)); \
 23	long wait__ = (Wmin); /* recommended min for usleep is 10 us */	\
 24	int ret__;							\
 25	might_sleep();							\
 26	for (;;) {							\
 27		const bool expired__ = ktime_after(ktime_get_raw(), end__); \
 28		/* Guarantee COND check prior to timeout */		\
 29		barrier();						\
 30		OP;							\
 31		if (COND) {						\
 32			ret__ = 0;					\
 33			break;						\
 34		}							\
 35		if (expired__) {					\
 36			ret__ = -ETIMEDOUT;				\
 37			break;						\
 38		}							\
 39		usleep_range(wait__, wait__ * 2);			\
 40		if (wait__ < (Wmax))					\
 41			wait__ <<= 1;					\
 42	}								\
 43	ret__;								\
 44})
 45
 46#define _wait_for(COND, US, Wmin, Wmax)	__wait_for(, (COND), (US), (Wmin), \
 47						   (Wmax))
 48#define wait_for(COND, MS)		_wait_for((COND), (MS) * 1000, 10, 1000)
 49
 50/*
 51 * If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false.
 52 * On PREEMPT_RT the context isn't becoming atomic because it is used in an
 53 * interrupt handler or because a spinlock_t is acquired. This leads to
 54 * warnings which don't occur otherwise and therefore the check is disabled.
 55 */
 56#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) && IS_ENABLED(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT)
 57# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic())
 58#else
 59# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0)
 60#endif
 61
 62#define _wait_for_atomic(COND, US, ATOMIC) \
 63({ \
 64	int cpu, ret, timeout = (US) * 1000; \
 65	u64 base; \
 66	_WAIT_FOR_ATOMIC_CHECK(ATOMIC); \
 67	if (!(ATOMIC)) { \
 68		preempt_disable(); \
 69		cpu = smp_processor_id(); \
 70	} \
 71	base = local_clock(); \
 72	for (;;) { \
 73		u64 now = local_clock(); \
 74		if (!(ATOMIC)) \
 75			preempt_enable(); \
 76		/* Guarantee COND check prior to timeout */ \
 77		barrier(); \
 78		if (COND) { \
 79			ret = 0; \
 80			break; \
 81		} \
 82		if (now - base >= timeout) { \
 83			ret = -ETIMEDOUT; \
 84			break; \
 85		} \
 86		cpu_relax(); \
 87		if (!(ATOMIC)) { \
 88			preempt_disable(); \
 89			if (unlikely(cpu != smp_processor_id())) { \
 90				timeout -= now - base; \
 91				cpu = smp_processor_id(); \
 92				base = local_clock(); \
 93			} \
 94		} \
 95	} \
 96	ret; \
 97})
 98
 99#define wait_for_us(COND, US) \
100({ \
101	int ret__; \
102	BUILD_BUG_ON(!__builtin_constant_p(US)); \
103	if ((US) > 10) \
104		ret__ = _wait_for((COND), (US), 10, 10); \
105	else \
106		ret__ = _wait_for_atomic((COND), (US), 0); \
107	ret__; \
108})
109
110#define wait_for_atomic_us(COND, US) \
111({ \
112	BUILD_BUG_ON(!__builtin_constant_p(US)); \
113	BUILD_BUG_ON((US) > 50000); \
114	_wait_for_atomic((COND), (US), 1); \
115})
116
117#define wait_for_atomic(COND, MS) wait_for_atomic_us((COND), (MS) * 1000)
118
119#endif /* __I915_WAIT_UTIL_H__ */
~/ Read-only file preview.