mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 00:24:51 +00:00
platform_drv(arm): robust re-configuration support
This change of the inner working of the platform driver for ARM allows clients to have permanent open sessions, as long as a policy node matches the client. If devices disappear from the policy resp. from the set of available devices (hotplug), the devices ROM of the session gets updated, and a corresponding device session gets closed. If the device remains untouched in the configuration but other devices appeared/disappeared, the device session is not affected. Ref #4330
This commit is contained in:
parent
6d231597b4
commit
132e4fe815
@ -34,21 +34,17 @@ unsigned Driver::Rpi_device::Power_domain::id()
|
||||
};
|
||||
|
||||
|
||||
bool Driver::Rpi_device::acquire(Driver::Session_component & sc)
|
||||
void Driver::Rpi_device::acquire(Driver::Session_component & sc)
|
||||
{
|
||||
bool ret = Driver::Device::acquire(sc);
|
||||
Driver::Device::acquire(sc);
|
||||
|
||||
if (ret) {
|
||||
_power_domain_list.for_each([&] (Power_domain & p) {
|
||||
auto & msg = sc.env().mbox.message<Property_message>();
|
||||
msg.append_no_response<Property_command::Set_power_state>(p.id(),
|
||||
true,
|
||||
true);
|
||||
sc.env().mbox.call<Property_message>();
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
_power_domain_list.for_each([&] (Power_domain & p) {
|
||||
auto & msg = sc.env().mbox.message<Property_message>();
|
||||
msg.append_no_response<Property_command::Set_power_state>(p.id(),
|
||||
true,
|
||||
true);
|
||||
sc.env().mbox.call<Property_message>();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ class Driver::Rpi_device : public Driver::Device
|
||||
unsigned id();
|
||||
};
|
||||
|
||||
bool acquire(Session_component &) override;
|
||||
void acquire(Session_component &) override;
|
||||
void release(Session_component &) override;
|
||||
|
||||
Rpi_device(Device::Name name, Device::Type type)
|
||||
|
@ -12,114 +12,29 @@
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <device_component.h>
|
||||
#include <session_component.h>
|
||||
|
||||
|
||||
Driver::Device::Owner::Owner(Session_component & session)
|
||||
: obj_id(reinterpret_cast<void*>(&session)) {}
|
||||
|
||||
|
||||
Driver::Device::Name Driver::Device::name() const { return _name; }
|
||||
|
||||
|
||||
Driver::Device::Type Driver::Device::type() const { return _type; }
|
||||
|
||||
|
||||
bool Driver::Device::acquire(Session_component & sc)
|
||||
{
|
||||
if (_session.valid() && _session != sc.label()) { return false; }
|
||||
|
||||
/**
|
||||
* FIXME: By now, we cannot use the connection objects for IRQ and
|
||||
* IOMEM and propagate missing resources when opening the
|
||||
* sessions, because the combination of Genode::Env and
|
||||
* Genode::Connection object transparently does quota upgrades.
|
||||
* If we like to account those costs per client, we actually
|
||||
* need to explicitely forward exceptions during session
|
||||
* requests.
|
||||
* For now, we try to measure the probable costs.
|
||||
*/
|
||||
Cap_quota_guard::Reservation caps(sc.cap_quota_guard(),
|
||||
Cap_quota{_cap_quota_required()});
|
||||
Ram_quota_guard::Reservation ram(sc.ram_quota_guard(),
|
||||
Ram_quota{_ram_quota_required()});
|
||||
|
||||
_session = sc.label();
|
||||
|
||||
caps.acknowledge();
|
||||
ram.acknowledge();
|
||||
return true;
|
||||
}
|
||||
Driver::Device::Owner Driver::Device::owner() const { return _owner; }
|
||||
|
||||
|
||||
void Driver::Device::release(Session_component & sc)
|
||||
{
|
||||
if (_session != sc.label()) { return; }
|
||||
|
||||
_io_mem_list.for_each([&] (Io_mem & io_mem) {
|
||||
if (io_mem.io_mem) {
|
||||
destroy(sc.heap(), io_mem.io_mem);
|
||||
io_mem.io_mem = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
_irq_list.for_each([&] (Irq & irq) {
|
||||
if (irq.irq) {
|
||||
destroy(sc.heap(), irq.irq);
|
||||
irq.irq = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
_session = Platform::Session::Label();;
|
||||
|
||||
sc.replenish(Cap_quota{_cap_quota_required()});
|
||||
sc.replenish(Ram_quota{_ram_quota_required()});
|
||||
}
|
||||
void Driver::Device::acquire(Session_component & sc) {
|
||||
if (!_owner.valid()) _owner = sc; }
|
||||
|
||||
|
||||
Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
|
||||
Session_component & sc)
|
||||
{
|
||||
Irq_session_capability cap;
|
||||
|
||||
if (_session != sc.label()) { return cap; }
|
||||
|
||||
unsigned i = 0;
|
||||
_irq_list.for_each([&] (Irq & irq)
|
||||
{
|
||||
if (i++ != idx) return;
|
||||
|
||||
if (!irq.irq) {
|
||||
irq.irq = new (sc.heap())
|
||||
Irq_connection(sc.env().env, irq.number);
|
||||
}
|
||||
cap = irq.irq->cap();
|
||||
});
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
|
||||
Genode::Io_mem_session_capability
|
||||
Driver::Device::io_mem(unsigned idx, Range &range, Cache cache, Session_component & sc)
|
||||
{
|
||||
Io_mem_session_capability cap;
|
||||
|
||||
if (_session != sc.label()) return cap;
|
||||
|
||||
unsigned i = 0;
|
||||
_io_mem_list.for_each([&] (Io_mem & io_mem)
|
||||
{
|
||||
if (i++ != idx) return;
|
||||
|
||||
range = Range { .start = io_mem.base & 0xfff,
|
||||
.size = io_mem.size };
|
||||
|
||||
if (!io_mem.io_mem) {
|
||||
io_mem.io_mem = new (sc.heap())
|
||||
Io_mem_connection(sc.env().env, io_mem.base, io_mem.size,
|
||||
(cache == WRITE_COMBINED));
|
||||
}
|
||||
cap = io_mem.io_mem->cap();
|
||||
});
|
||||
|
||||
return cap;
|
||||
}
|
||||
void Driver::Device::release(Session_component & sc) {
|
||||
if (_owner == sc) _owner = Owner();; }
|
||||
|
||||
|
||||
void Driver::Device::report(Xml_generator & xml, Session_component & sc)
|
||||
@ -129,8 +44,8 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
|
||||
xml.attribute("type", type());
|
||||
_io_mem_list.for_each([&] (Io_mem & io_mem) {
|
||||
xml.node("io_mem", [&] () {
|
||||
xml.attribute("phys_addr", String<16>(Hex(io_mem.base)));
|
||||
xml.attribute("size", String<16>(Hex(io_mem.size)));
|
||||
xml.attribute("phys_addr", String<16>(Hex(io_mem.range.start)));
|
||||
xml.attribute("size", String<16>(Hex(io_mem.range.size)));
|
||||
});
|
||||
});
|
||||
_irq_list.for_each([&] (Irq & irq) {
|
||||
@ -149,36 +64,12 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
|
||||
}
|
||||
|
||||
|
||||
Genode::size_t Driver::Device::_cap_quota_required()
|
||||
{
|
||||
/* one cap is needed for the device component itself */
|
||||
size_t total = 1;
|
||||
_io_mem_list.for_each([&] (Io_mem &) {
|
||||
total += Io_mem_session::CAP_QUOTA; });
|
||||
_irq_list.for_each([&] (Irq &) {
|
||||
total += Irq_session::CAP_QUOTA; });
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
Genode::size_t Driver::Device::_ram_quota_required()
|
||||
{
|
||||
size_t total = 0;
|
||||
_io_mem_list.for_each([&] (Io_mem &) {
|
||||
total += Io_mem_session::RAM_QUOTA; });
|
||||
_irq_list.for_each([&] (Irq &) {
|
||||
total += Irq_session::RAM_QUOTA; });
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
Driver::Device::Device(Name name, Type type)
|
||||
: _name(name), _type(type) { }
|
||||
|
||||
|
||||
Driver::Device::~Device()
|
||||
{
|
||||
if (_session.valid()) {
|
||||
error("Device to be destroyed, still obtained by session ",
|
||||
_session); }
|
||||
if (_owner.valid()) {
|
||||
error("Device to be destroyed, still obtained by session"); }
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_
|
||||
|
||||
#include <base/allocator.h>
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <platform_session/device.h>
|
||||
#include <util/list.h>
|
||||
#include <util/list_model.h>
|
||||
@ -41,20 +39,34 @@ class Driver::Device : private List_model<Device>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
using Name = Genode::String<64>;
|
||||
using Type = Genode::String<64>;
|
||||
using Range = Platform::Device_interface::Range;
|
||||
|
||||
struct Owner
|
||||
{
|
||||
void * obj_id;
|
||||
|
||||
Owner() : obj_id(nullptr) {}
|
||||
Owner(Session_component & session);
|
||||
|
||||
bool operator == (Owner const & o) const {
|
||||
return obj_id == o.obj_id; }
|
||||
|
||||
bool valid() const {
|
||||
return obj_id != nullptr; }
|
||||
};
|
||||
|
||||
struct Io_mem : List_model<Io_mem>::Element
|
||||
{
|
||||
addr_t base;
|
||||
size_t size;
|
||||
Io_mem_connection * io_mem { nullptr };
|
||||
Range range;
|
||||
|
||||
Io_mem(addr_t base, size_t size)
|
||||
: base(base), size(size) {}
|
||||
Io_mem(Range range) : range(range) {}
|
||||
};
|
||||
|
||||
struct Irq : List_model<Irq>::Element
|
||||
{
|
||||
unsigned number;
|
||||
Irq_connection * irq { nullptr };
|
||||
unsigned number;
|
||||
|
||||
Irq(unsigned number) : number(number) {}
|
||||
};
|
||||
@ -71,22 +83,29 @@ class Driver::Device : private List_model<Device>::Element
|
||||
: name(name), value(value) {}
|
||||
};
|
||||
|
||||
using Name = Genode::String<64>;
|
||||
using Type = Genode::String<64>;
|
||||
using Range = Platform::Device_interface::Range;
|
||||
|
||||
Device(Name name, Type type);
|
||||
virtual ~Device();
|
||||
|
||||
Name name() const;
|
||||
Type type() const;
|
||||
Name name() const;
|
||||
Type type() const;
|
||||
Owner owner() const;
|
||||
|
||||
virtual bool acquire(Session_component &);
|
||||
virtual void acquire(Session_component &);
|
||||
virtual void release(Session_component &);
|
||||
|
||||
Irq_session_capability irq(unsigned idx, Session_component &);
|
||||
Io_mem_session_capability io_mem(unsigned idx, Range &, Cache,
|
||||
Session_component &);
|
||||
template <typename FN> void for_each_irq(FN const & fn)
|
||||
{
|
||||
unsigned idx = 0;
|
||||
_irq_list.for_each([&] (Irq const & irq) {
|
||||
fn(idx++, irq.number); });
|
||||
}
|
||||
|
||||
template <typename FN> void for_each_io_mem(FN const & fn)
|
||||
{
|
||||
unsigned idx = 0;
|
||||
_io_mem_list.for_each([&] (Io_mem const & iomem) {
|
||||
fn(idx++, iomem.range); });
|
||||
}
|
||||
|
||||
void report(Xml_generator &, Session_component &);
|
||||
|
||||
@ -95,19 +114,16 @@ class Driver::Device : private List_model<Device>::Element
|
||||
virtual void _report_platform_specifics(Xml_generator &,
|
||||
Session_component &) {}
|
||||
|
||||
size_t _cap_quota_required();
|
||||
size_t _ram_quota_required();
|
||||
|
||||
friend class Driver::Device_model;
|
||||
friend class List_model<Device>;
|
||||
friend class List<Device>;
|
||||
|
||||
Name _name;
|
||||
Type _type;
|
||||
Platform::Session::Label _session {};
|
||||
List_model<Io_mem> _io_mem_list {};
|
||||
List_model<Irq> _irq_list {};
|
||||
List_model<Property> _property_list {};
|
||||
Name _name;
|
||||
Type _type;
|
||||
Owner _owner {};
|
||||
List_model<Io_mem> _io_mem_list {};
|
||||
List_model<Irq> _irq_list {};
|
||||
List_model<Property> _property_list {};
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
@ -201,18 +217,18 @@ struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update
|
||||
|
||||
Element & create_element(Genode::Xml_node node)
|
||||
{
|
||||
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
|
||||
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
|
||||
return *(new (alloc) Element(base, size));
|
||||
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
|
||||
node.attribute_value<Genode::size_t>("size", 0) };
|
||||
return *(new (alloc) Element(range));
|
||||
}
|
||||
|
||||
void update_element(Element &, Genode::Xml_node) {}
|
||||
|
||||
static bool element_matches_xml_node(Element const & iomem, Genode::Xml_node node)
|
||||
{
|
||||
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
|
||||
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
|
||||
return (base == iomem.base) && (size == iomem.size);
|
||||
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
|
||||
node.attribute_value<Genode::size_t>("size", 0) };
|
||||
return (range.start == iomem.range.start) && (range.size == iomem.range.size);
|
||||
}
|
||||
|
||||
static bool node_is_element(Genode::Xml_node node)
|
||||
|
@ -17,36 +17,47 @@
|
||||
|
||||
using Driver::Device_component;
|
||||
|
||||
|
||||
void Driver::Device_component::_release_resources()
|
||||
{
|
||||
_io_mem_registry.for_each([&] (Io_mem & iomem) {
|
||||
destroy(_session.heap(), &iomem); });
|
||||
|
||||
_irq_registry.for_each([&] (Irq & irq) {
|
||||
destroy(_session.heap(), &irq); });
|
||||
|
||||
_session.ram_quota_guard().replenish(Ram_quota{_ram_quota});
|
||||
_session.cap_quota_guard().replenish(Cap_quota{_cap_quota});
|
||||
}
|
||||
|
||||
|
||||
Driver::Device::Name Device_component::device() const { return _device; }
|
||||
|
||||
|
||||
Driver::Session_component & Device_component::session() { return _session; }
|
||||
|
||||
|
||||
bool Driver::Device_component::acquire()
|
||||
{
|
||||
bool acquired = false;
|
||||
_session.env().devices.for_each([&] (Driver::Device & device) {
|
||||
if (device.name() == _device) {
|
||||
acquired = device.acquire(_session); }});
|
||||
return acquired;
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device_component::release()
|
||||
{
|
||||
_session.env().devices.for_each([&] (Driver::Device & device) {
|
||||
if (device.name() == _device) { device.release(_session); }});
|
||||
}
|
||||
|
||||
|
||||
Genode::Io_mem_session_capability
|
||||
Device_component::io_mem(unsigned idx, Range &range, Cache cache)
|
||||
{
|
||||
Io_mem_session_capability cap;
|
||||
_session.env().devices.for_each([&] (Driver::Device & device) {
|
||||
if (device.name() == _device) {
|
||||
cap = device.io_mem(idx, range, cache, _session); }});
|
||||
|
||||
_io_mem_registry.for_each([&] (Io_mem & iomem)
|
||||
{
|
||||
if (iomem.idx != idx)
|
||||
return;
|
||||
|
||||
if (!iomem.io_mem.constructed())
|
||||
iomem.io_mem.construct(_session.env().env,
|
||||
iomem.range.start,
|
||||
iomem.range.size,
|
||||
cache == WRITE_COMBINED);
|
||||
|
||||
range = iomem.range;
|
||||
range.start &= 0xfff;
|
||||
cap = iomem.io_mem->cap();
|
||||
});
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
@ -54,22 +65,64 @@ Device_component::io_mem(unsigned idx, Range &range, Cache cache)
|
||||
Genode::Irq_session_capability Device_component::irq(unsigned idx)
|
||||
{
|
||||
Irq_session_capability cap;
|
||||
_session.env().devices.for_each([&] (Driver::Device & device) {
|
||||
if (device.name() == _device) { cap = device.irq(idx, _session); }});
|
||||
|
||||
_irq_registry.for_each([&] (Irq & irq)
|
||||
{
|
||||
if (irq.idx != idx)
|
||||
return;
|
||||
|
||||
if (!irq.irq.constructed())
|
||||
irq.irq.construct(_session.env().env, irq.number);
|
||||
|
||||
cap = irq.irq->cap();
|
||||
});
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device_component::report(Xml_generator & xml)
|
||||
Device_component::Device_component(Registry<Device_component> & registry,
|
||||
Driver::Session_component & session,
|
||||
Driver::Device & device)
|
||||
: _session(session), _device(device.name()), _reg_elem(registry, *this)
|
||||
{
|
||||
_session.env().devices.for_each([&] (Driver::Device & device) {
|
||||
if (device.name() == _device) { device.report(xml, _session); }});
|
||||
session.cap_quota_guard().withdraw(Cap_quota{1});
|
||||
_cap_quota += 1;
|
||||
|
||||
/**
|
||||
* FIXME: By now, we cannot use the connection objects for IRQ and
|
||||
* IOMEM and propagate missing resources when opening the
|
||||
* sessions, because the combination of Genode::Env and
|
||||
* Genode::Connection object transparently does quota upgrades.
|
||||
* If we like to account those costs per client, we actually
|
||||
* need to explicitely forward exceptions during session
|
||||
* requests.
|
||||
* For now, we try to measure the probable costs.
|
||||
*/
|
||||
|
||||
try {
|
||||
device.for_each_irq([&] (unsigned idx, unsigned nr)
|
||||
{
|
||||
session.ram_quota_guard().withdraw(Ram_quota{Irq_session::RAM_QUOTA});
|
||||
_ram_quota += Irq_session::RAM_QUOTA;
|
||||
session.cap_quota_guard().withdraw(Cap_quota{Irq_session::CAP_QUOTA});
|
||||
_cap_quota += Irq_session::CAP_QUOTA;
|
||||
new (session.heap()) Irq(_irq_registry, idx, nr);
|
||||
});
|
||||
|
||||
device.for_each_io_mem([&] (unsigned idx, Range range)
|
||||
{
|
||||
session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA});
|
||||
_ram_quota += Io_mem_session::RAM_QUOTA;
|
||||
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
|
||||
_cap_quota += Io_mem_session::CAP_QUOTA;
|
||||
new (session.heap()) Io_mem(_io_mem_registry, idx, range);
|
||||
});
|
||||
} catch(...) {
|
||||
_release_resources();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Device_component::Device_component(Driver::Session_component & session,
|
||||
Driver::Device::Name const device)
|
||||
: _session(session), _device(device) { }
|
||||
|
||||
|
||||
Device_component::~Device_component() { release(); }
|
||||
Device_component::~Device_component() { _release_resources(); };
|
||||
|
@ -14,9 +14,13 @@
|
||||
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
|
||||
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
|
||||
|
||||
#include <base/registry.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <platform_session/platform_session.h>
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <platform_session/device.h>
|
||||
#include <platform_session/platform_session.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
#include <env.h>
|
||||
#include <device.h>
|
||||
@ -32,18 +36,42 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
|
||||
{
|
||||
public:
|
||||
|
||||
Device_component(Session_component & session,
|
||||
Driver::Device::Name const device);
|
||||
struct Irq : Registry<Irq>::Element
|
||||
{
|
||||
unsigned idx;
|
||||
unsigned number;
|
||||
Constructible<Irq_connection> irq {};
|
||||
|
||||
Irq(Registry<Irq> & registry,
|
||||
unsigned idx,
|
||||
unsigned number)
|
||||
:
|
||||
Registry<Irq>::Element(registry, *this),
|
||||
idx(idx), number(number) {}
|
||||
};
|
||||
|
||||
struct Io_mem : Registry<Io_mem>::Element
|
||||
{
|
||||
unsigned idx;
|
||||
Range range;
|
||||
Constructible<Io_mem_connection> io_mem {};
|
||||
|
||||
Io_mem(Registry<Io_mem> & registry,
|
||||
unsigned idx,
|
||||
Range range)
|
||||
:
|
||||
Registry<Io_mem>::Element(registry, *this),
|
||||
idx(idx), range(range) {}
|
||||
};
|
||||
|
||||
Device_component(Registry<Device_component> & registry,
|
||||
Session_component & session,
|
||||
Driver::Device & device);
|
||||
~Device_component();
|
||||
|
||||
Driver::Device::Name device() const;
|
||||
Session_component & session();
|
||||
|
||||
bool acquire();
|
||||
void release();
|
||||
|
||||
void report(Xml_generator&);
|
||||
|
||||
|
||||
/************************************
|
||||
** Platform::Device RPC functions **
|
||||
@ -54,12 +82,15 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
|
||||
|
||||
private:
|
||||
|
||||
friend class Session_component;
|
||||
Session_component & _session;
|
||||
Driver::Device::Name const _device;
|
||||
size_t _cap_quota { 0 };
|
||||
size_t _ram_quota { 0 };
|
||||
Registry<Device_component>::Element _reg_elem;
|
||||
Registry<Irq> _irq_registry {};
|
||||
Registry<Io_mem> _io_mem_registry {};
|
||||
|
||||
Session_component & _session;
|
||||
Driver::Device::Name const _device;
|
||||
Capability<Platform::Device> _cap {};
|
||||
List_element<Device_component> _list_elem { this };
|
||||
void _release_resources();
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
|
@ -39,15 +39,8 @@ struct Driver::Main
|
||||
void Driver::Main::update_config()
|
||||
{
|
||||
env.config.update();
|
||||
|
||||
/**
|
||||
* We must perform the policy update before updating the devices since
|
||||
* the former may need to release devices and its corresponding Io_mem
|
||||
* and Irq connections when closing a session that is no longer supposed
|
||||
* to exist. For doing so, it must access the old device model.
|
||||
*/
|
||||
root.update_policy();
|
||||
env.devices.update(env.config.xml());
|
||||
root.update_policy();
|
||||
}
|
||||
|
||||
void Component::construct(Genode::Env &env) {
|
||||
|
@ -13,32 +13,22 @@
|
||||
|
||||
#include <root.h>
|
||||
|
||||
using Version = Driver::Session_component::Policy_version;
|
||||
|
||||
void Driver::Root::update_policy()
|
||||
{
|
||||
_sessions.for_each([&] (Session_component & sc) {
|
||||
|
||||
bool policy_changed = false;
|
||||
unsigned device_count = 0;
|
||||
|
||||
_sessions.for_each([&] (Session_component & sc)
|
||||
{
|
||||
try {
|
||||
Session_policy const policy { sc._label, _env.config.xml() };
|
||||
|
||||
policy.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
device_count++;
|
||||
if (!sc.has_device(node.attribute_value("name",
|
||||
Device::Name()))) {
|
||||
policy_changed = true; }
|
||||
});
|
||||
|
||||
if (device_count != sc.devices_count()) { policy_changed = true; }
|
||||
sc.update_policy(policy.attribute_value("info", false),
|
||||
policy.attribute_value("version", Version()));
|
||||
}
|
||||
catch (Session_policy::No_policy_defined) {
|
||||
policy_changed = true;
|
||||
error("No matching policy for '", sc._label.string(),
|
||||
"' anymore, will close the session!");
|
||||
close(sc.cap());
|
||||
}
|
||||
|
||||
if (policy_changed) { close(sc.cap()); }
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,10 +45,8 @@ Driver::Session_component * Driver::Root::_create_session(const char *args)
|
||||
Session_component(_env, _sessions, label,
|
||||
session_resources_from_args(args),
|
||||
session_diag_from_args(args),
|
||||
policy.attribute_value("info", false));
|
||||
|
||||
policy.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
sc->add(node.attribute_value("name", Driver::Device::Name())); });
|
||||
policy.attribute_value("info", false),
|
||||
policy.attribute_value("version", Version()));
|
||||
} catch (Session_policy::No_policy_defined) {
|
||||
error("Invalid session request, no matching policy for ",
|
||||
"'", label_from_args(args).string(), "'");
|
||||
|
@ -18,11 +18,93 @@
|
||||
|
||||
using Driver::Session_component;
|
||||
|
||||
|
||||
Genode::Capability<Platform::Device_interface>
|
||||
Session_component::_acquire(Device & device)
|
||||
{
|
||||
Device_component * dc = new (heap())
|
||||
Device_component(_device_registry, *this, device);
|
||||
device.acquire(*this);
|
||||
return _env.env.ep().rpc_ep().manage(dc);
|
||||
};
|
||||
|
||||
|
||||
void Session_component::_release_device(Device_component & dc)
|
||||
{
|
||||
Device::Name name = dc.device();
|
||||
_env.env.ep().rpc_ep().dissolve(&dc);
|
||||
destroy(heap(), &dc);
|
||||
|
||||
_env.devices.for_each([&] (Device & dev) {
|
||||
if (name == dev.name()) dev.release(*this); });
|
||||
}
|
||||
|
||||
|
||||
void Session_component::_free_dma_buffer(Dma_buffer & buf)
|
||||
{
|
||||
Ram_dataspace_capability cap = buf.cap;
|
||||
destroy(heap(), &buf);
|
||||
_env_ram.free(cap);
|
||||
}
|
||||
|
||||
|
||||
bool Session_component::matches(Device & dev) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
try {
|
||||
Session_policy const policy { label(), _env.config.xml() };
|
||||
policy.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
if (dev.name() == node.attribute_value("name", Device::Name()))
|
||||
ret = true;
|
||||
});
|
||||
} catch (Session_policy::No_policy_defined) { }
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
void Session_component::update_policy(bool info, Policy_version version)
|
||||
{
|
||||
_info = info;
|
||||
_version = version;
|
||||
|
||||
enum Device_state { AWAY, CHANGED, UNCHANGED };
|
||||
|
||||
_device_registry.for_each([&] (Device_component & dc) {
|
||||
Device_state state = AWAY;
|
||||
_env.devices.for_each([&] (Device & dev) {
|
||||
if (dev.name() != dc.device())
|
||||
return;
|
||||
state = (dev.owner() == _owner_id) ? UNCHANGED : CHANGED;
|
||||
});
|
||||
|
||||
if (state == UNCHANGED)
|
||||
return;
|
||||
|
||||
if (state == AWAY)
|
||||
warning("Device ", dc.device(),
|
||||
" has changed, will close device session");
|
||||
else
|
||||
warning("Device ", dc.device(),
|
||||
" unavailable, will close device session");
|
||||
_release_device(dc);
|
||||
});
|
||||
|
||||
update_devices_rom();
|
||||
};
|
||||
|
||||
|
||||
void Session_component::produce_xml(Xml_generator &xml)
|
||||
{
|
||||
if (!_info) { return; }
|
||||
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
|
||||
e->object()->report(xml); }
|
||||
if (!_info)
|
||||
return;
|
||||
|
||||
if (_version.valid())
|
||||
xml.attribute("version", _version);
|
||||
|
||||
_env.devices.for_each([&] (Device & dev) {
|
||||
if (matches(dev)) dev.report(xml, *this); });
|
||||
}
|
||||
|
||||
|
||||
@ -32,39 +114,6 @@ Genode::Heap & Session_component::heap() { return _md_alloc; }
|
||||
Driver::Env & Session_component::env() { return _env; }
|
||||
|
||||
|
||||
void Session_component::add(Device::Name const & device)
|
||||
{
|
||||
if (has_device(device)) return;
|
||||
|
||||
Device_component * new_dc =
|
||||
new (_md_alloc) Device_component(*this, device);
|
||||
|
||||
Device_list_element * last = nullptr;
|
||||
for (last = _device_list.first(); last; last = last->next()) {
|
||||
if (!last->next()) break; }
|
||||
_device_list.insert(&new_dc->_list_elem, last);
|
||||
}
|
||||
|
||||
|
||||
bool Session_component::has_device(Device::Name const & device) const
|
||||
{
|
||||
for (Device_list_element const * e = _device_list.first(); e;
|
||||
e = e->next()) {
|
||||
if (e->object()->device() == device) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
unsigned Session_component::devices_count() const
|
||||
{
|
||||
unsigned counter = 0;
|
||||
for (Device_list_element const * e = _device_list.first();
|
||||
e; e = e->next()) { counter++; }
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
void Session_component::update_devices_rom()
|
||||
{
|
||||
_rom_session.trigger_update();
|
||||
@ -78,40 +127,59 @@ Genode::Rom_session_capability Session_component::devices_rom() {
|
||||
Genode::Capability<Platform::Device_interface>
|
||||
Session_component::acquire_device(Platform::Session::Device_name const &name)
|
||||
{
|
||||
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
|
||||
if (e->object()->device() != name.string()) { continue; }
|
||||
Capability<Platform::Device_interface> cap;
|
||||
|
||||
if (!e->object()->acquire()) {
|
||||
error("Device ", e->object()->device(),
|
||||
" already acquired!");
|
||||
break;
|
||||
}
|
||||
/* Search for existing, aquired device session */
|
||||
_device_registry.for_each([&] (Device_component & dc) {
|
||||
if (dc.device() == name)
|
||||
cap = dc.cap();
|
||||
});
|
||||
|
||||
return _env.env.ep().rpc_ep().manage(e->object());
|
||||
}
|
||||
if (cap.valid())
|
||||
return cap;
|
||||
|
||||
return Capability<Platform::Device_interface>();
|
||||
_env.devices.for_each([&] (Device & dev)
|
||||
{
|
||||
if (dev.name() != name || !matches(dev))
|
||||
return;
|
||||
if (dev.owner().valid())
|
||||
warning("Cannot aquire device ", name, " already in use");
|
||||
else
|
||||
cap = _acquire(dev);
|
||||
});
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
|
||||
Genode::Capability<Platform::Device_interface>
|
||||
Session_component::acquire_single_device()
|
||||
{
|
||||
Device_list_element * e = _device_list.first();
|
||||
if (!e) { return Capability<Platform::Device_interface>(); }
|
||||
Capability<Platform::Device_interface> cap;
|
||||
|
||||
return acquire_device(e->object()->device());
|
||||
/* Search for existing, aquired device session */
|
||||
_device_registry.for_each([&] (Device_component & dc) {
|
||||
cap = dc.cap(); });
|
||||
|
||||
if (cap.valid())
|
||||
return cap;
|
||||
|
||||
_env.devices.for_each([&] (Device & dev) {
|
||||
if (matches(dev) && !dev.owner().valid())
|
||||
cap = _acquire(dev); });
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
|
||||
void Session_component::release_device(Capability<Platform::Device_interface> device_cap)
|
||||
{
|
||||
_env.env.ep().rpc_ep().apply(device_cap, [&] (Device_component * dc) {
|
||||
if (!dc)
|
||||
return;
|
||||
_env.env.ep().rpc_ep().dissolve(dc);
|
||||
dc->release();
|
||||
});
|
||||
if (!device_cap.valid())
|
||||
return;
|
||||
|
||||
_device_registry.for_each([&] (Device_component & dc) {
|
||||
if (device_cap.local_name() == dc.cap().local_name())
|
||||
_release_device(dc); });
|
||||
}
|
||||
|
||||
|
||||
@ -123,7 +191,7 @@ Session_component::alloc_dma_buffer(size_t const size, Cache cache)
|
||||
if (!ram_cap.valid()) return ram_cap;
|
||||
|
||||
try {
|
||||
_buffer_list.insert(new (_md_alloc) Dma_buffer(ram_cap));
|
||||
new (heap()) Dma_buffer(_buffer_registry, ram_cap);
|
||||
} catch (Out_of_ram) {
|
||||
_env_ram.free(ram_cap);
|
||||
throw;
|
||||
@ -140,44 +208,41 @@ void Session_component::free_dma_buffer(Ram_dataspace_capability ram_cap)
|
||||
{
|
||||
if (!ram_cap.valid()) { return; }
|
||||
|
||||
for (Dma_buffer * buf = _buffer_list.first(); buf; buf = buf->next()) {
|
||||
|
||||
if (buf->cap.local_name() != ram_cap.local_name()) continue;
|
||||
|
||||
_buffer_list.remove(buf);
|
||||
destroy(_md_alloc, buf);
|
||||
_env_ram.free(ram_cap);
|
||||
return;
|
||||
}
|
||||
_buffer_registry.for_each([&] (Dma_buffer & buf) {
|
||||
if (buf.cap.local_name() == ram_cap.local_name())
|
||||
_free_dma_buffer(buf); });
|
||||
}
|
||||
|
||||
|
||||
Genode::addr_t Session_component::dma_addr(Ram_dataspace_capability ram_cap)
|
||||
{
|
||||
if (!ram_cap.valid()) { return 0; }
|
||||
addr_t ret = 0;
|
||||
|
||||
for (Dma_buffer * buf = _buffer_list.first(); buf; buf = buf->next()) {
|
||||
if (!ram_cap.valid())
|
||||
return ret;
|
||||
|
||||
if (buf->cap.local_name() != ram_cap.local_name()) continue;
|
||||
_buffer_registry.for_each([&] (Dma_buffer & buf) {
|
||||
if (buf.cap.local_name() == ram_cap.local_name()) {
|
||||
Dataspace_client dsc(buf.cap);
|
||||
ret = dsc.phys_addr();
|
||||
} });
|
||||
|
||||
Dataspace_client dsc(buf->cap);
|
||||
return dsc.phys_addr();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Session_component::Session_component(Driver::Env & env,
|
||||
Session_registry & registry,
|
||||
Label const & label,
|
||||
Resources const & resources,
|
||||
Diag const & diag,
|
||||
bool const info)
|
||||
: Session_object<Platform::Session>(env.env.ep(), resources, label, diag),
|
||||
Session_registry::Element(registry, *this),
|
||||
Dynamic_rom_session::Xml_producer("devices"),
|
||||
_env(env), _info(info)
|
||||
Session_component::Session_component(Driver::Env & env,
|
||||
Session_registry & registry,
|
||||
Label const & label,
|
||||
Resources const & resources,
|
||||
Diag const & diag,
|
||||
bool const info,
|
||||
Policy_version const version)
|
||||
:
|
||||
Session_object<Platform::Session>(env.env.ep(), resources, label, diag),
|
||||
Session_registry::Element(registry, *this),
|
||||
Dynamic_rom_session::Xml_producer("devices"),
|
||||
_env(env), _info(info), _version(version)
|
||||
{
|
||||
/*
|
||||
* FIXME: As the ROM session does not propagate Out_of_*
|
||||
@ -188,25 +253,21 @@ Session_component::Session_component(Driver::Env & env,
|
||||
* we account the costs here until the ROM session interface
|
||||
* changes.
|
||||
*/
|
||||
_cap_quota_guard().withdraw(Cap_quota{1});
|
||||
_cap_quota_guard().withdraw(Cap_quota{Rom_session::CAP_QUOTA});
|
||||
_ram_quota_guard().withdraw(Ram_quota{5*1024});
|
||||
}
|
||||
|
||||
|
||||
Session_component::~Session_component()
|
||||
{
|
||||
while (_device_list.first()) {
|
||||
Device_list_element * e = _device_list.first();
|
||||
release_device(e->object()->cap());
|
||||
_device_list.remove(e);
|
||||
destroy(_md_alloc, e->object());
|
||||
}
|
||||
_device_registry.for_each([&] (Device_component & dc) {
|
||||
_release_device(dc); });
|
||||
|
||||
/* also free up dma buffers */
|
||||
while (_buffer_list.first())
|
||||
free_dma_buffer(_buffer_list.first()->cap);
|
||||
/* free up dma buffers */
|
||||
_buffer_registry.for_each([&] (Dma_buffer & buf) {
|
||||
_free_dma_buffer(buf); });
|
||||
|
||||
/* replenish quota for rom sessions, see constructor for explanation */
|
||||
_cap_quota_guard().replenish(Cap_quota{1});
|
||||
_cap_quota_guard().replenish(Cap_quota{Rom_session::CAP_QUOTA});
|
||||
_ram_quota_guard().replenish(Ram_quota{5*1024});
|
||||
}
|
||||
|
@ -40,26 +40,29 @@ class Driver::Session_component
|
||||
public:
|
||||
|
||||
using Session_registry = Registry<Session_component>;
|
||||
using Policy_version = String<64>;
|
||||
|
||||
Session_component(Driver::Env & env,
|
||||
Session_registry & registry,
|
||||
Label const & label,
|
||||
Resources const & resources,
|
||||
Diag const & diag,
|
||||
bool const info,
|
||||
Policy_version const version);
|
||||
|
||||
Session_component(Driver::Env & env,
|
||||
Session_registry & registry,
|
||||
Label const & label,
|
||||
Resources const & resources,
|
||||
Diag const & diag,
|
||||
bool const info);
|
||||
~Session_component();
|
||||
|
||||
Heap & heap();
|
||||
Driver::Env & env();
|
||||
|
||||
void add(Device::Name const &);
|
||||
bool has_device(Device::Name const &) const;
|
||||
unsigned devices_count() const;
|
||||
void update_devices_rom();
|
||||
bool matches(Device &) const;
|
||||
void update_devices_rom();
|
||||
|
||||
Ram_quota_guard & ram_quota_guard() { return _ram_quota_guard(); }
|
||||
Cap_quota_guard & cap_quota_guard() { return _cap_quota_guard(); }
|
||||
|
||||
void update_policy(bool info, Policy_version version);
|
||||
|
||||
|
||||
/**************************
|
||||
** Platform Session API **
|
||||
@ -80,28 +83,32 @@ class Driver::Session_component
|
||||
|
||||
friend class Root;
|
||||
|
||||
struct Dma_buffer : List<Dma_buffer>::Element
|
||||
struct Dma_buffer : Registry<Dma_buffer>::Element
|
||||
{
|
||||
Ram_dataspace_capability const cap;
|
||||
|
||||
Dma_buffer(Ram_dataspace_capability const cap)
|
||||
: cap(cap) {}
|
||||
Dma_buffer(Registry<Dma_buffer> & registry,
|
||||
Ram_dataspace_capability const cap)
|
||||
: Registry<Dma_buffer>::Element(registry, *this), cap(cap) {}
|
||||
};
|
||||
|
||||
using Device_list_element = List_element<Device_component>;
|
||||
using Device_list = List<Device_list_element>;
|
||||
|
||||
Driver::Env & _env;
|
||||
Constrained_ram_allocator _env_ram { _env.env.pd(),
|
||||
_ram_quota_guard(),
|
||||
_cap_quota_guard() };
|
||||
Heap _md_alloc { _env_ram, _env.env.rm() };
|
||||
Device_list _device_list { };
|
||||
List<Dma_buffer> _buffer_list { };
|
||||
Dynamic_rom_session _rom_session { _env.env.ep(), _env.env.ram(),
|
||||
_env.env.rm(), *this };
|
||||
bool const _info;
|
||||
Driver::Env & _env;
|
||||
Device::Owner _owner_id { *this };
|
||||
Constrained_ram_allocator _env_ram { _env.env.pd(),
|
||||
_ram_quota_guard(),
|
||||
_cap_quota_guard() };
|
||||
Heap _md_alloc { _env_ram, _env.env.rm() };
|
||||
Registry<Device_component> _device_registry { };
|
||||
Registry<Dma_buffer> _buffer_registry { };
|
||||
Dynamic_rom_session _rom_session { _env.env.ep(), _env.env.ram(),
|
||||
_env.env.rm(), *this };
|
||||
bool _info;
|
||||
Policy_version _version;
|
||||
|
||||
Device_capability _acquire(Device & device);
|
||||
void _release_device(Device_component & dc);
|
||||
void _free_dma_buffer(Dma_buffer & buf);
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user