Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/i915/de: Implement register polling in the display code

The plan is to move all the mmio stuff into the display code itself.
As a first step implement the register polling in intel_de.c.

Currently i915 and xe implement this stuff in slightly different
ways, so there are some functional changes here. Try to go for a
reasonable middle ground between the i915 and xe implementations:
- the exponential backoff limit is the simpler approach taken
by i915 (== just clamp the max sleep duration to 1 ms)
- the fast vs. slow timeout handling is similar to i915 where
we first try the fast timeout and then again the slow timeout
if the condition still isn't satisfied. xe just adds up the
timeouts together, which is a bit weird.
- the atomic wait variant uses udelay() like xe, whereas i915
has no udelay()s in its atomic loop. As a compromise go for a
fixed 1 usec delay for short waits, instead of the somewhat
peculiar xe behaviour where it effectively just does one
iteration of the loop.
- keep the "use udelay() for < 10 usec waits" logic (which
more or less mirrors fsleep()), but include an explicit
might_sleep() even for these short waits when called from
a non-atomic intel_de_wait*() function. This should prevent
people from calling the non-atomic functions from the wrong
place.

Eventually we may want to switch over to poll_timeout*(),
but that lacks the exponential backoff, so a bit too
radical to change in one go.

v2: Initialize ret in intel_de_wait_for_register() to avoid a
warning from the compiler. This is actually a false positive
since we always have fast_timeout_us!=0 when slow_timeout_us!=0,
but the compiler can't see that

Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patch.msgid.link/20260323094304.8171-1-ville.syrjala@linux.intel.com

+91 -39
+91 -8
drivers/gpu/drm/i915/display/intel_de.c
··· 3 3 * Copyright © 2026 Intel Corporation 4 4 */ 5 5 6 + #include <linux/delay.h> 7 + 6 8 #include <drm/drm_print.h> 7 9 8 10 #include "intel_de.h" 11 + 12 + static int __intel_de_wait_for_register(struct intel_display *display, 13 + i915_reg_t reg, u32 mask, u32 value, 14 + unsigned int timeout_us, 15 + u32 (*read)(struct intel_display *display, i915_reg_t reg), 16 + u32 *out_val, bool is_atomic) 17 + { 18 + const ktime_t end = ktime_add_us(ktime_get_raw(), timeout_us); 19 + int wait_max = 1000; 20 + int wait = 10; 21 + u32 reg_value; 22 + int ret; 23 + 24 + might_sleep_if(!is_atomic); 25 + 26 + if (timeout_us <= 10) { 27 + is_atomic = true; 28 + wait = 1; 29 + } 30 + 31 + for (;;) { 32 + bool expired = ktime_after(ktime_get_raw(), end); 33 + 34 + /* guarantee the condition is evaluated after timeout expired */ 35 + barrier(); 36 + 37 + reg_value = read(display, reg); 38 + if ((reg_value & mask) == value) { 39 + ret = 0; 40 + break; 41 + } 42 + 43 + if (expired) { 44 + ret = -ETIMEDOUT; 45 + break; 46 + } 47 + 48 + if (is_atomic) 49 + udelay(wait); 50 + else 51 + usleep_range(wait, wait << 1); 52 + 53 + if (wait < wait_max) 54 + wait <<= 1; 55 + } 56 + 57 + if (out_val) 58 + *out_val = reg_value; 59 + 60 + return ret; 61 + } 62 + 63 + static int intel_de_wait_for_register(struct intel_display *display, 64 + i915_reg_t reg, u32 mask, u32 value, 65 + unsigned int fast_timeout_us, 66 + unsigned int slow_timeout_us, 67 + u32 (*read)(struct intel_display *display, i915_reg_t reg), 68 + u32 *out_value, bool is_atomic) 69 + { 70 + int ret = -EINVAL; 71 + 72 + if (fast_timeout_us) 73 + ret = __intel_de_wait_for_register(display, reg, mask, value, 74 + fast_timeout_us, read, 75 + out_value, is_atomic); 76 + 77 + if (ret && slow_timeout_us) 78 + ret = __intel_de_wait_for_register(display, reg, mask, value, 79 + slow_timeout_us, read, 80 + out_value, is_atomic); 81 + 82 + return ret; 83 + } 9 84 10 85 int intel_de_wait_us(struct intel_display *display, i915_reg_t reg, 11 86 u32 mask, u32 value, unsigned int timeout_us, ··· 90 15 91 16 intel_dmc_wl_get(display, reg); 92 17 93 - ret = __intel_wait_for_register(__to_uncore(display), reg, mask, 94 - value, timeout_us, 0, out_value); 18 + ret = intel_de_wait_for_register(display, reg, mask, value, 19 + timeout_us, 0, 20 + intel_de_read, 21 + out_value, false); 95 22 96 23 intel_dmc_wl_put(display, reg); 97 24 ··· 108 31 109 32 intel_dmc_wl_get(display, reg); 110 33 111 - ret = __intel_wait_for_register(__to_uncore(display), reg, mask, 112 - value, 2, timeout_ms, out_value); 34 + ret = intel_de_wait_for_register(display, reg, mask, value, 35 + 2, timeout_ms * 1000, 36 + intel_de_read, 37 + out_value, false); 113 38 114 39 intel_dmc_wl_put(display, reg); 115 40 ··· 122 43 u32 mask, u32 value, unsigned int timeout_ms, 123 44 u32 *out_value) 124 45 { 125 - return __intel_wait_for_register_fw(__to_uncore(display), reg, mask, 126 - value, 2, timeout_ms, out_value); 46 + return intel_de_wait_for_register(display, reg, mask, value, 47 + 2, timeout_ms * 1000, 48 + intel_de_read_fw, 49 + out_value, false); 127 50 } 128 51 129 52 int intel_de_wait_fw_us_atomic(struct intel_display *display, i915_reg_t reg, 130 53 u32 mask, u32 value, unsigned int timeout_us, 131 54 u32 *out_value) 132 55 { 133 - return __intel_wait_for_register_fw(__to_uncore(display), reg, mask, 134 - value, timeout_us, 0, out_value); 56 + return intel_de_wait_for_register(display, reg, mask, value, 57 + timeout_us, 0, 58 + intel_de_read_fw, 59 + out_value, true); 135 60 } 136 61 137 62 int intel_de_wait_for_set_us(struct intel_display *display, i915_reg_t reg,
-31
drivers/gpu/drm/xe/compat-i915-headers/intel_uncore.h
··· 98 98 return xe_mmio_rmw32(__compat_uncore_to_mmio(uncore), reg, clear, set); 99 99 } 100 100 101 - static inline int 102 - __intel_wait_for_register(struct intel_uncore *uncore, i915_reg_t i915_reg, 103 - u32 mask, u32 value, unsigned int fast_timeout_us, 104 - unsigned int slow_timeout_ms, u32 *out_value) 105 - { 106 - struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg)); 107 - bool atomic; 108 - 109 - /* 110 - * Replicate the behavior from i915 here, in which sleep is not 111 - * performed if slow_timeout_ms == 0. This is necessary because 112 - * of some paths in display code where waits are done in atomic 113 - * context. 114 - */ 115 - atomic = !slow_timeout_ms && fast_timeout_us > 0; 116 - 117 - return xe_mmio_wait32(__compat_uncore_to_mmio(uncore), reg, mask, value, 118 - fast_timeout_us + 1000 * slow_timeout_ms, 119 - out_value, atomic); 120 - } 121 - 122 - static inline int 123 - __intel_wait_for_register_fw(struct intel_uncore *uncore, i915_reg_t i915_reg, 124 - u32 mask, u32 value, unsigned int fast_timeout_us, 125 - unsigned int slow_timeout_ms, u32 *out_value) 126 - { 127 - return __intel_wait_for_register(uncore, i915_reg, mask, value, 128 - fast_timeout_us, slow_timeout_ms, 129 - out_value); 130 - } 131 - 132 101 static inline u32 intel_uncore_read_fw(struct intel_uncore *uncore, 133 102 i915_reg_t i915_reg) 134 103 {