Refactor the current implementation os __xe_mmio_wait32 to use kernel poll_timeout_* helpers that scale across architecture and max timeouts while maintaining the exponential backoff looping to ensure no difference in latency experiened by callers.
Assisted-by: LLM Suggested-by: Jani Nikula <[email protected]> Signed-off-by: Alan Previn <[email protected]> --- drivers/gpu/drm/xe/xe_mmio.c | 64 +++++++++++++----------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 2674146ced76..e48b1c94a82b 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -5,8 +5,8 @@ #include "xe_mmio.h" -#include <linux/delay.h> #include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/iopoll.h> #include <linux/minmax.h> #include <linux/pci.h> @@ -324,53 +324,35 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg) return (u64)udw << 32 | ldw; } -#define __XE_MMIO_WAIT_MAX_BACKOFF_100MS (100 * USEC_PER_MSEC) +#define XE_MMIO_WAIT_MIN_US 10 +#define XE_MMIO_WAIT_MAX_DELAY_US (MAX_UDELAY_MS * 1000) +#define XE_MMIO_WAIT_MAX_SLEEP_US (100 * 1000) + static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, u32 *out_val, bool atomic, bool expect_match) { - ktime_t cur = ktime_get_raw(); - const ktime_t end = ktime_add_us(cur, timeout_us); - int ret = -ETIMEDOUT; - s64 wait = 10; + u32 max_us = atomic ? XE_MMIO_WAIT_MAX_DELAY_US : XE_MMIO_WAIT_MAX_SLEEP_US; + /* a zero timeout means "never time out" to the iopoll helpers */ + u32 left_us = timeout_us ?: 1; + u32 wait_us = XE_MMIO_WAIT_MIN_US; + u32 step_us; u32 read; - bool check; - - for (;;) { - read = xe_mmio_read32(mmio, reg); - - check = (read & mask) == val; - if (!expect_match) - check = !check; - - if (check) { - ret = 0; - break; - } - - cur = ktime_get_raw(); - if (!ktime_before(cur, end)) - break; - - if (ktime_after(ktime_add_us(cur, wait), end)) - wait = ktime_us_delta(end, cur); + int ret; + /* exponential backoff: each step polls at, and lasts for, twice the previous interval */ + do { + step_us = min(wait_us, left_us); if (atomic) - udelay(min_t(s64, wait, (MAX_UDELAY_MS * 1000))); + ret = poll_timeout_us_atomic(read = xe_mmio_read32(mmio, reg), + ((read & mask) == val) == expect_match, + step_us, step_us, false); else - usleep_range(wait, wait << 1); - wait = min_t(s64, wait << 1, __XE_MMIO_WAIT_MAX_BACKOFF_100MS); - } - - if (ret != 0) { - read = xe_mmio_read32(mmio, reg); - - check = (read & mask) == val; - if (!expect_match) - check = !check; - - if (check) - ret = 0; - } + ret = poll_timeout_us(read = xe_mmio_read32(mmio, reg), + ((read & mask) == val) == expect_match, + step_us, step_us, false); + left_us -= step_us; + wait_us = min(wait_us << 1, max_us); + } while (ret && left_us); if (out_val) *out_val = read; base-commit: 81fce6ce260af07e3f7a1211b6fe813941cbd17b -- 2.43.0
