From 0c13effaa87cbe626cd83db81afbbfac86f7ef8d Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 9 Jun 2016 12:00:59 +0200 Subject: [PATCH] intel_fb: enable polling for connector changes To circumvent problems on platforms with shaky hotplug interrupt notification introduce a "poll" configuration option to the driver, which enables polling for connector changes. Fix #2004 --- .../src/drivers/framebuffer/intel/README | 9 ++++ .../framebuffer/intel/include/component.h | 44 ++++++++++++------- .../src/drivers/framebuffer/intel/lx_emul.cc | 29 ++++++++++-- .../src/drivers/framebuffer/intel/main.cc | 13 +++--- repos/dde_linux/src/include/lx_kit/irq.h | 2 + repos/dde_linux/src/lx_kit/irq.cc | 32 ++++++++------ 6 files changed, 91 insertions(+), 38 deletions(-) diff --git a/repos/dde_linux/src/drivers/framebuffer/intel/README b/repos/dde_linux/src/drivers/framebuffer/intel/README index 87b0791381..4f15246e4f 100644 --- a/repos/dde_linux/src/drivers/framebuffer/intel/README +++ b/repos/dde_linux/src/drivers/framebuffer/intel/README @@ -35,6 +35,15 @@ configuration like this: ! +If you experience problems like hotplugging of connectors does not work, you +can force the driver to poll frequently for hotplug events by defining a period +in milliseconds like this: + +! + +If you define a period of zero, the driver won't poll at all, which is the +default value. + To present all available connectors and their possible resolutions to the user the driver is able to export a corresponding report ROM. This has to be configured too, like in the following: diff --git a/repos/dde_linux/src/drivers/framebuffer/intel/include/component.h b/repos/dde_linux/src/drivers/framebuffer/intel/include/component.h index ebbbb85a4d..d3e935a522 100644 --- a/repos/dde_linux/src/drivers/framebuffer/intel/include/component.h +++ b/repos/dde_linux/src/drivers/framebuffer/intel/include/component.h @@ -15,6 +15,7 @@ #define __COMPONENT_H__ /* Genode includes */ +#include #include #include #include @@ -41,21 +42,28 @@ class Framebuffer::Driver { private: - Session_component &_session; - int _height = 0; - int _width = 0; - static constexpr unsigned _bytes_per_pixel = 2; - void *_new_fb_ds_base = nullptr; - void *_cur_fb_ds_base = nullptr; - Genode::uint64_t _cur_fb_ds_size = 0; - drm_framebuffer *_new_fb = nullptr; - drm_framebuffer *_cur_fb = nullptr; + Session_component &_session; + Timer::Connection _timer; + Genode::Signal_handler _poll_handler; + int _height = 0; + int _width = 0; + static constexpr unsigned _bytes_per_pixel = 2; + void *_new_fb_ds_base = nullptr; + void *_cur_fb_ds_base = nullptr; + Genode::uint64_t _cur_fb_ds_size = 0; + drm_framebuffer *_new_fb = nullptr; + drm_framebuffer *_cur_fb = nullptr; + unsigned long _poll_ms = false; drm_display_mode * _preferred_mode(drm_connector *connector); + void _poll(); + public: - Driver(Session_component &session) : _session(session) {} + Driver(Genode::Env & env, Session_component &session) + : _session(session), _timer(env), + _poll_handler(env.ep(), *this, &Driver::_poll) {} int width() const { return _width; } int height() const { return _height; } @@ -65,6 +73,7 @@ class Framebuffer::Driver return _width * _height * _bytes_per_pixel; } void finish_initialization(); + void set_polling(unsigned long poll); bool mode_changed(); void generate_report(); void free_framebuffer(); @@ -90,6 +99,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object bool _buffered_from_config() { return _config.xml().attribute_value("buffered", false); } + unsigned long _polling_from_config() { + return _config.xml().attribute_value("poll", 0); } + void _refresh_buffered(int x, int y, int w, int h) { using namespace Genode; @@ -114,8 +126,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object public: - Session_component(Genode::Attached_rom_dataspace &config) - : _driver(*this), _config(config), + Session_component(Genode::Env &env, + Genode::Attached_rom_dataspace &config) + : _driver(env, *this), _config(config), _timer(env), _buffered(_buffered_from_config()) {} Driver & driver() { return _driver; } @@ -127,6 +140,7 @@ class Framebuffer::Session_component : public Genode::Rpc_object _in_update = true; _buffered = _buffered_from_config(); + _driver.set_polling(_polling_from_config()); if (_driver.mode_changed() && _mode_sigh.valid()) Genode::Signal_transmitter(_mode_sigh).submit(); else @@ -191,11 +205,11 @@ struct Framebuffer::Root Session_component *_create_session(const char *args) override { return &session; } - Root(Genode::Entrypoint &ep, Genode::Allocator &alloc, + Root(Genode::Env &env, Genode::Allocator &alloc, Genode::Attached_rom_dataspace &config) : Genode::Root_component(ep, alloc), - session(config) { } + Genode::Single_client>(env.ep(), alloc), + session(env, config) { } }; #endif /* __COMPONENT_H__ */ diff --git a/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc b/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc index 010bf29d5b..dc3410b040 100644 --- a/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc +++ b/repos/dde_linux/src/drivers/framebuffer/intel/lx_emul.cc @@ -137,9 +137,34 @@ void Framebuffer::Driver::finish_initialization() { dde_c_set_driver(dde_drm_device, (void*)this); generate_report(); - mode_changed(); + _session.config_changed(); } + +#include + +void Framebuffer::Driver::_poll() +{ + Lx::Pci_dev * pci_dev = (Lx::Pci_dev*) dde_drm_device->pdev->bus; + Lx::Irq::irq().inject_irq(pci_dev->client()); +} + + +void Framebuffer::Driver::set_polling(unsigned long poll) +{ + if (poll == _poll_ms) return; + + _poll_ms = poll; + + if (_poll_ms) { + _timer.sigh(_poll_handler); + _timer.trigger_periodic(_poll_ms * 1000); + } else { + _timer.sigh(Genode::Signal_context_capability()); + } +} + + bool Framebuffer::Driver::mode_changed() { using namespace Genode; @@ -920,8 +945,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, } -#include - int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) { diff --git a/repos/dde_linux/src/drivers/framebuffer/intel/main.cc b/repos/dde_linux/src/drivers/framebuffer/intel/main.cc index cb384d7d57..1ac034b086 100644 --- a/repos/dde_linux/src/drivers/framebuffer/intel/main.cc +++ b/repos/dde_linux/src/drivers/framebuffer/intel/main.cc @@ -41,11 +41,11 @@ unsigned long jiffies; struct Main { - Genode::Entrypoint &ep; - Genode::Attached_rom_dataspace config; - Genode::Heap heap; - - Framebuffer::Root root { ep, heap, config }; + Genode::Env &env; + Genode::Entrypoint &ep { env.ep() }; + Genode::Attached_rom_dataspace config { env, "config" }; + Genode::Heap heap { env.ram(), env.rm() }; + Framebuffer::Root root { env, heap, config }; /* init singleton Lx::Timer */ Lx::Timer &timer = Lx::timer(&ep, &jiffies); @@ -60,8 +60,7 @@ struct Main Lx::Task linux { run_linux, reinterpret_cast(this), "linux", Lx::Task::PRIORITY_0, Lx::scheduler() }; - Main(Genode::Env &env) - : ep(env.ep()), config(env, "config"), heap(env.ram(), env.rm()) + Main(Genode::Env &env) : env(env) { Genode::log("--- intel framebuffer driver ---"); diff --git a/repos/dde_linux/src/include/lx_kit/irq.h b/repos/dde_linux/src/include/lx_kit/irq.h index 98b232f53a..02ccadba26 100644 --- a/repos/dde_linux/src/include/lx_kit/irq.h +++ b/repos/dde_linux/src/include/lx_kit/irq.h @@ -35,6 +35,8 @@ class Lx::Irq */ virtual void request_irq(Platform::Device &dev, irq_handler_t handler, void *dev_id, irq_handler_t thread_fn = 0) = 0; + + virtual void inject_irq(Platform::Device &dev) = 0; }; #endif /* _LX_KIT__IRQ_H_ */ diff --git a/repos/dde_linux/src/lx_kit/irq.cc b/repos/dde_linux/src/lx_kit/irq.cc index 20cc20dd9f..9aa5cc1ddd 100644 --- a/repos/dde_linux/src/lx_kit/irq.cc +++ b/repos/dde_linux/src/lx_kit/irq.cc @@ -96,18 +96,7 @@ class Lx_kit::Irq : public Lx::Irq Lx_kit::List _handler; Lx::Task _task; - Genode::Signal_rpc_member _dispatcher; - - /** - * Signal handler - */ - void _handle(unsigned) - { - _task.unblock(); - - /* kick off scheduling */ - Lx::scheduler().schedule(); - } + Genode::Signal_handler _dispatcher; static void _run_irq(void *args) { @@ -131,7 +120,7 @@ class Lx_kit::Irq : public Lx::Irq _dev(dev), _irq_sess(dev.irq(0)), _task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()), - _dispatcher(ep, *this, &Context::_handle) + _dispatcher(ep, *this, &Context::unblock) { _irq_sess.sigh(_dispatcher); @@ -139,6 +128,17 @@ class Lx_kit::Irq : public Lx::Irq _irq_sess.ack_irq(); } + /** + * Unblock this context, e.g., as result of an IRQ signal + */ + void unblock() + { + _task.unblock(); + + /* kick off scheduling */ + Lx::scheduler().schedule(); + } + /** * Handle IRQ */ @@ -214,6 +214,12 @@ class Lx_kit::Irq : public Lx::Irq Handler(dev_id, handler, thread_fn); ctx->add_handler(h); } + + void inject_irq(Platform::Device &dev) + { + Context *ctx = _find_context(dev); + if (ctx) ctx->unblock(); + } };