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
This commit is contained in:
Stefan Kalkowski 2016-06-09 12:00:59 +02:00 committed by Christian Helmuth
parent 11bead1811
commit 0c13effaa8
6 changed files with 91 additions and 38 deletions

View File

@ -35,6 +35,15 @@ configuration like this:
! <config buffered="yes"/>
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:
! <config poll="1000"/>
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:

View File

@ -15,6 +15,7 @@
#define __COMPONENT_H__
/* Genode includes */
#include <base/component.h>
#include <base/rpc_server.h>
#include <root/component.h>
#include <dataspace/capability.h>
@ -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<Driver> _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<Session>
bool _buffered_from_config() {
return _config.xml().attribute_value("buffered", false); }
unsigned long _polling_from_config() {
return _config.xml().attribute_value<unsigned long>("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<Session>
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<Session>
_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<Session_component,
Genode::Single_client>(ep, alloc),
session(config) { }
Genode::Single_client>(env.ep(), alloc),
session(env, config) { }
};
#endif /* __COMPONENT_H__ */

View File

@ -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 <lx_kit/irq.h>
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 <lx_kit/irq.h>
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{

View File

@ -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<void*>(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 ---");

View File

@ -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_ */

View File

@ -96,18 +96,7 @@ class Lx_kit::Irq : public Lx::Irq
Lx_kit::List<Handler> _handler;
Lx::Task _task;
Genode::Signal_rpc_member<Context> _dispatcher;
/**
* Signal handler
*/
void _handle(unsigned)
{
_task.unblock();
/* kick off scheduling */
Lx::scheduler().schedule();
}
Genode::Signal_handler<Context> _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();
}
};