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

gpu: ipu-v3: pre: don't use fixed timeout when waiting for safe window

The timeout when waiting for the PRE safe window is rather short, as
normally we would only need to wait a few dozen usecs for the problematic
scanline region to pass and we don't want to spin too long in case
something goes wrong. This however mixes badly with preemption, as we
can easily get scheduled away from the CPU for a longer time than our
timeout, in which case we would hit a spurious timeout and wrongly skip
the PRE update.

Instead of disabling preemption across the wait loop, potentially
impacting the overall system latency, use a wait loop with a fixed
max number of iterations, so time spent away from the CPU is not
accounted against the timeout budget.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://lore.kernel.org/r/20240517104549.3648939-3-l.stach@pengutronix.de
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20240517104549.3648939-3-l.stach@pengutronix.de

authored by

Lucas Stach and committed by
Philipp Zabel
d5316cdd 4dbc7d5d

+14 -8
+14 -8
drivers/gpu/ipu-v3/ipu-pre.c
··· 5 5 6 6 #include <drm/drm_fourcc.h> 7 7 #include <linux/clk.h> 8 + #include <linux/delay.h> 8 9 #include <linux/err.h> 9 10 #include <linux/genalloc.h> 10 11 #include <linux/module.h> ··· 257 256 258 257 void ipu_pre_update(struct ipu_pre *pre, uint64_t modifier, unsigned int bufaddr) 259 258 { 260 - unsigned long timeout = jiffies + msecs_to_jiffies(5); 261 - unsigned short current_yblock; 262 - u32 val; 263 - 264 259 if (bufaddr == pre->cur.bufaddr && 265 260 modifier == pre->cur.modifier) 266 261 return; ··· 267 270 if (modifier != pre->cur.modifier) 268 271 ipu_pre_configure_modifier(pre, modifier); 269 272 270 - do { 271 - if (time_after(jiffies, timeout)) { 273 + for (int i = 0;; i++) { 274 + unsigned short current_yblock; 275 + u32 val; 276 + 277 + if (i > 500) { 272 278 dev_warn(pre->dev, "timeout waiting for PRE safe window\n"); 273 279 return; 274 280 } ··· 280 280 current_yblock = 281 281 (val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) & 282 282 IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK; 283 - } while (current_yblock == 0 || 284 - current_yblock >= pre->cur.safe_window_end); 283 + 284 + if (current_yblock != 0 && 285 + current_yblock < pre->cur.safe_window_end) 286 + break; 287 + 288 + udelay(10); 289 + cpu_relax(); 290 + } 285 291 286 292 writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE, 287 293 pre->regs + IPU_PRE_CTRL);