From 5f0ba7d722b5cc57294678e5a86256e8dcc2917d Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 6 Jan 2023 15:15:04 +0100 Subject: [PATCH] intel_fb: handle rapid config change gracefully In case of very rapid config ROM change (<300ms), the linux driver may still be in progress of applying the previous change (e.g. switching connector on/off). During this progress all tasks may become not runnable (waiting for IRQ/timeouts until hardware state settles), the newest config ROM change/signal gets dispatched, which lead to continuing the previous change request, but not to re-starting/re-applying the new config change. To avoid this situation, explicitly track whether a previous config change was finished and track if an interim config change request came in. If so, re-start the lx_user task with the newest config change. Fixes #4721 --- .../drivers/framebuffer/intel/pc/lx_i915.h | 1 + .../drivers/framebuffer/intel/pc/lx_user.c | 3 ++- .../src/drivers/framebuffer/intel/pc/main.cc | 26 +++++++++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/repos/pc/src/drivers/framebuffer/intel/pc/lx_i915.h b/repos/pc/src/drivers/framebuffer/intel/pc/lx_i915.h index 1eef0726a3..3b67e0338e 100644 --- a/repos/pc/src/drivers/framebuffer/intel/pc/lx_i915.h +++ b/repos/pc/src/drivers/framebuffer/intel/pc/lx_i915.h @@ -35,5 +35,6 @@ void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, void lx_emul_i915_iterate_modes(void *lx_data, void * genode_data); void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *); void lx_emul_i915_connector_config(char * name, struct genode_mode *); +int lx_emul_i915_config_done_and_block(void); #endif /* _LX_I915_H_ */ diff --git a/repos/pc/src/drivers/framebuffer/intel/pc/lx_user.c b/repos/pc/src/drivers/framebuffer/intel/pc/lx_user.c index bbd7fdf984..48dea81997 100644 --- a/repos/pc/src/drivers/framebuffer/intel/pc/lx_user.c +++ b/repos/pc/src/drivers/framebuffer/intel/pc/lx_user.c @@ -397,7 +397,8 @@ static int configure_connectors(void * data) retry_count = 0; - lx_emul_task_schedule(true); + if (lx_emul_i915_config_done_and_block()) + lx_emul_task_schedule(true /* block task */); } return 0; diff --git a/repos/pc/src/drivers/framebuffer/intel/pc/main.cc b/repos/pc/src/drivers/framebuffer/intel/pc/main.cc index 154a925269..91c33068e1 100644 --- a/repos/pc/src/drivers/framebuffer/intel/pc/main.cc +++ b/repos/pc/src/drivers/framebuffer/intel/pc/main.cc @@ -53,6 +53,9 @@ struct Framebuffer::Driver Signal_handler timer_handler { env.ep(), *this, &Driver::handle_timer }; + bool update_in_progress { false }; + bool new_config_rom { false }; + class Fb { private: @@ -148,6 +151,11 @@ void Framebuffer::Driver::config_update() if (!config.valid() || !lx_user_task) return; + if (update_in_progress) + new_config_rom = true; + else + update_in_progress = true; + lx_emul_task_unblock(lx_user_task); Lx_kit::env().scheduler.schedule(); } @@ -178,6 +186,8 @@ void Framebuffer::Driver::generate_report(void *lx_data) { lx_emul_i915_report(lx_data, &xml); }); + + driver(Lx_kit::env().env).report_updated(); } catch (...) { Genode::warning("Failed to generate report"); } @@ -288,8 +298,6 @@ void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, lx_emul_i915_iterate_modes(lx_data, &xml); }); - - driver(Lx_kit::env().env).report_updated(); } @@ -323,6 +331,20 @@ void lx_emul_i915_connector_config(char * name, struct genode_mode * mode) } +int lx_emul_i915_config_done_and_block(void) +{ + auto &state = driver(Lx_kit::env().env); + + bool const new_config = state.new_config_rom; + + state.update_in_progress = false; + state.new_config_rom = false; + + /* true if linux task should block, otherwise continue due to new config */ + return !new_config; +} + + void Component::construct(Genode::Env &env) { driver(env).start();