platform_drv: introduce clocks, power, reset

Share datastructures for clock, power and reset related configurations
per device. In the generic platform driver component these structures
are kept empty. Driver derivates can fill the clocks settings, power and
reset switches with life. The former Driver::Env gets removed.

Fix #4338
This commit is contained in:
Stefan Kalkowski 2021-12-06 14:37:03 +01:00 committed by Norman Feske
parent f11d2b5b54
commit 6cc6047962
23 changed files with 859 additions and 407 deletions

View File

@ -1,81 +0,0 @@
/*
* \brief Platform driver - Device model policy for rpi
* \author Stefan Kalkowski
* \date 2020-08-20
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <env.h>
#include <rpi_device.h>
using Driver::Device_model;
using Driver::Device;
using Driver::Rpi_device;
void Device_model::destroy_element(Device & dev)
{
Rpi_device & device = static_cast<Rpi_device&>(dev);
{
Irq_update_policy policy(_env.heap);
device._irq_list.destroy_all_elements(policy);
}
{
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_env.heap);
device._property_list.destroy_all_elements(policy);
}
{
Power_domain_update_policy policy(_env.heap);
device._power_domain_list.destroy_all_elements(policy);
}
Genode::destroy(_env.heap, &device);
}
Device & Device_model::create_element(Genode::Xml_node node)
{
Device::Name name = node.attribute_value("name", Device::Name());
Device::Type type = node.attribute_value("type", Device::Type());
return *(new (_env.heap) Rpi_device(name, type));
}
void Device_model::update_element(Device & dev,
Genode::Xml_node node)
{
Rpi_device & device = static_cast<Rpi_device&>(dev);
{
Irq_update_policy policy(_env.heap);
device._irq_list.update_from_xml(policy, node);
}
{
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_env.heap);
device._property_list.update_from_xml(policy, node);
}
{
Power_domain_update_policy policy(_env.heap);
device._power_domain_list.update_from_xml(policy, node);
}
}

View File

@ -1,43 +0,0 @@
/*
* \brief Platform driver for rpi
* \author Stefan Kalkowski
* \date 2020-08-20
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__DRIVERS__PLATFORM__RPI__ENV_H_
#define _SRC__DRIVERS__PLATFORM__RPI__ENV_H_
#include <base/attached_rom_dataspace.h>
#include <base/env.h>
#include <base/heap.h>
#include <device.h>
#include <mbox.h>
namespace Driver {
using namespace Genode;
struct Env;
};
struct Driver::Env
{
Genode::Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Device_model devices { *this };
Mbox mbox { env };
Env(Genode::Env &env) : env(env) { }
};
#endif /* _SRC__DRIVERS__PLATFORM__RPI__ENV_H_ */

View File

@ -0,0 +1,54 @@
/*
* \brief Platform driver for Raspberry Pi 1
* \author Stefan Kalkowski
* \date 2020-04-12
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/component.h>
#include <power_domains.h>
#include <root.h>
namespace Driver { struct Main; };
struct Driver::Main
{
void update_config();
Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Device_model devices { heap };
Mbox mbox { env };
Power_domains power_domains { devices.powers(), mbox };
Signal_handler<Main> config_handler { env.ep(), *this,
&Main::update_config };
Driver::Root root { env, sliced_heap,
config, devices };
Main(Genode::Env & e)
: env(e)
{
devices.update(config.xml());
config.sigh(config_handler);
env.parent().announce(env.ep().manage(root));
}
};
void Driver::Main::update_config()
{
config.update();
devices.update(config.xml());
root.update_policy();
}
void Component::construct(Genode::Env &env) {
static Driver::Main main(env); }

View File

@ -0,0 +1,67 @@
/*
* \brief Platform driver for Raspberry Pi 1
* \author Stefan Kalkowski
* \date 2021-12-06
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <mbox.h>
#include <device.h>
#include <property_command.h>
#include <property_message.h>
namespace Driver { struct Power_domains; }
struct Driver::Power_domains
{
struct Domain : Driver::Power
{
Mbox & mbox;
unsigned const id;
Domain(Powers & powers,
Power::Name name,
Mbox & mbox,
unsigned id)
:
Power(powers, name), mbox(mbox), id(id) {}
void _on() override
{
auto & msg = mbox.message<Property_message>();
msg.append_no_response<Property_command::Set_power_state>(id,
true,
true);
mbox.call<Property_message>();
}
void _off() override
{
auto & msg = mbox.message<Property_message>();
msg.append_no_response<Property_command::Set_power_state>(id,
false,
true);
mbox.call<Property_message>();
}
};
Powers & powers;
Mbox & mbox;
Domain sdhci { powers, "sdhci", mbox, 0 };
Domain uart_0 { powers, "uart_0", mbox, 1 };
Domain uart_1 { powers, "uart_1", mbox, 2 };
Domain usb { powers, "usb", mbox, 3 };
Domain i2c_0 { powers, "i2c_0", mbox, 4 };
Domain i2c_1 { powers, "i2c_1", mbox, 5 };
Domain i2c_2 { powers, "i2c_2", mbox, 6 };
Domain spi { powers, "spi", mbox, 7 };
Domain ccp2tx { powers, "ccp2tx", mbox, 8 };
};

View File

@ -1,72 +0,0 @@
/*
* \brief Platform driver - Device abstraction for rpi
* \author Stefan Kalkowski
* \date 2020-08-17
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <property_command.h>
#include <property_message.h>
#include <rpi_device.h>
#include <session_component.h>
unsigned Driver::Rpi_device::Power_domain::id()
{
if (name == "sdhci") { return 0; }
if (name == "uart_0") { return 1; }
if (name == "uart_1") { return 2; }
if (name == "usb") { return 3; }
if (name == "i2c_0") { return 4; }
if (name == "i2c_1") { return 5; }
if (name == "i2c_2") { return 6; }
if (name == "spi") { return 7; }
if (name == "ccp2tx") { return 8; }
warning("Invalid power-domain ", name);
return ~0U;
};
void Driver::Rpi_device::acquire(Driver::Session_component & sc)
{
Driver::Device::acquire(sc);
_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>();
});
}
void Driver::Rpi_device::release(Session_component & sc)
{
_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 Driver::Device::release(sc);
}
void Driver::Rpi_device::_report_platform_specifics(Genode::Xml_generator &,
Driver::Session_component &)
{
/*
* Normally, the platform driver should report about clock settings of the
* device etc. here. But we do not implement clocking for RPI yet.
*/
}

View File

@ -1,90 +0,0 @@
/*
* \brief Platform driver - Device abstraction for rpi
* \author Stefan Kalkowski
* \date 2020-08-20
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__DRIVERS__PLATFORM__IMX8MQ__RPI_DEVICE_H_
#define _SRC__DRIVERS__PLATFORM__IMX8MQ__RPI_DEVICE_H_
#include <device.h>
namespace Driver {
using namespace Genode;
class Rpi_device;
struct Power_domain_update_policy;
}
class Driver::Rpi_device : public Driver::Device
{
public:
struct Power_domain : List_model<Power_domain>::Element
{
using Name = Genode::String<64>;
Name name;
Power_domain(Name name) : name(name) {}
unsigned id();
};
void acquire(Session_component &) override;
void release(Session_component &) override;
Rpi_device(Device::Name name, Device::Type type)
: Device(name, type) {}
protected:
friend class Driver::Device_model;
friend class List_model<Device>;
void _report_platform_specifics(Xml_generator &,
Session_component &) override;
List_model<Power_domain> _power_domain_list {};
};
struct Driver::Power_domain_update_policy
: Genode::List_model<Rpi_device::Power_domain>::Update_policy
{
Genode::Allocator & alloc;
Power_domain_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & pd) {
Genode::destroy(alloc, &pd); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return *(new (alloc) Element(name));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & pd, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return name == pd.name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("power-domain");
}
};
#endif /* _SRC__DRIVERS__PLATFORM__IMX8MQ__RPI_DEVICE_H_ */

View File

@ -3,12 +3,11 @@ REQUIRES = arm_v6
SRC_CC = device.cc
SRC_CC += device_component.cc
SRC_CC += device_model_policy.cc
SRC_CC += rpi_device.cc
SRC_CC += main.cc
SRC_CC += session_component.cc
SRC_CC += root.cc
INC_DIR = $(PRG_DIR) $(REP_DIR)/src/drivers/platform/spec/arm
LIBS = base
vpath %.cc $(PRG_DIR)
vpath %.cc $(REP_DIR)/src/drivers/platform/spec/arm
vpath main.cc $(PRG_DIR)
vpath %.cc $(REP_DIR)/src/drivers/platform/spec/arm

View File

@ -0,0 +1,107 @@
/*
* \brief Clock interface for platform driver
* \author Stefan Kalkowski
* \author Norman Feske
* \date 2020-06-12
*/
/*
* Copyright (C) 2020-2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _CLOCK_H_
#define _CLOCK_H_
#include <types.h>
#include <named_registry.h>
namespace Driver {
using namespace Genode;
class Clock;
class Fixed_clock;
class Fixed_divider;
using Clocks = Named_registry<Clock>;
}
class Driver::Clock : Clocks::Element, Interface
{
private:
/* friendships needed to make 'Clocks::Element' private */
friend class Clocks::Element;
friend class Avl_node<Clock>;
friend class Avl_tree<Clock>;
Switch<Clock> _switch { *this, &Clock::_enable, &Clock::_disable };
protected:
virtual void _enable() { }
virtual void _disable() { }
public:
using Name = Clocks::Element::Name;
using Clocks::Element::name;
using Clocks::Element::Element;
struct Rate { unsigned long value; };
virtual void rate(Rate) { }
virtual Rate rate() const { return Rate { }; }
virtual void parent(Name) { }
void enable() { _switch.use(); }
void disable() { _switch.unuse(); }
};
class Driver::Fixed_clock : public Driver::Clock
{
private:
Rate const _rate;
public:
Fixed_clock(Clocks &clocks, Name const &name, Rate rate)
:
Clock(clocks, name), _rate(rate)
{ }
Rate rate() const override { return _rate; }
};
class Driver::Fixed_divider : public Driver::Clock
{
private:
Clock &_parent;
unsigned const _divider;
public:
Fixed_divider(Clocks &clocks,
Name const &name,
Clock &parent,
unsigned divider)
:
Clock(clocks, name), _parent(parent), _divider(divider)
{ }
Rate rate() const override
{
return Rate { _parent.rate().value / _divider };
}
};
#endif /* _CLOCK_H_ */

View File

@ -29,12 +29,81 @@ Driver::Device::Type Driver::Device::type() const { return _type; }
Driver::Device::Owner Driver::Device::owner() const { return _owner; }
void Driver::Device::acquire(Session_component & sc) {
if (!_owner.valid()) _owner = sc; }
void Driver::Device::acquire(Session_component & sc)
{
if (!_owner.valid()) _owner = sc;
_power_domain_list.for_each([&] (Power_domain & p) {
bool ok = false;
sc.devices().powers().apply(p.name, [&] (Driver::Power &power) {
power.on();
ok = true;
});
if (!ok)
warning("power domain ", p.name, " is unknown");
});
_reset_domain_list.for_each([&] (Reset_domain & r) {
bool ok = false;
sc.devices().resets().apply(r.name, [&] (Driver::Reset &reset) {
reset.deassert();
ok = true;
});
if (!ok)
warning("reset domain ", r.name, " is unknown");
});
_clock_list.for_each([&] (Clock &c) {
bool ok = false;
sc.devices().clocks().apply(c.name, [&] (Driver::Clock &clock) {
if (c.parent.valid())
clock.parent(c.parent);
if (c.rate)
clock.rate(Driver::Clock::Rate { c.rate });
clock.enable();
ok = true;
});
if (!ok) {
warning("clock ", c.name, " is unknown");
return;
}
});
sc.update_devices_rom();
}
void Driver::Device::release(Session_component & sc) {
if (_owner == sc) _owner = Owner();; }
void Driver::Device::release(Session_component & sc)
{
_reset_domain_list.for_each([&] (Reset_domain & r)
{
sc.devices().resets().apply(r.name, [&] (Driver::Reset &reset) {
reset.assert(); });
});
_power_domain_list.for_each([&] (Power_domain & p)
{
sc.devices().powers().apply(p.name, [&] (Driver::Power &power) {
power.off(); });
});
_clock_list.for_each([&] (Clock & c)
{
sc.devices().clocks().apply(c.name, [&] (Driver::Clock &clock) {
clock.disable(); });
});
if (_owner == sc) _owner = Owner();
}
void Driver::Device::report(Xml_generator & xml, Session_component & sc)
@ -59,6 +128,15 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
xml.attribute("value", p.value);
});
});
_clock_list.for_each([&] (Clock &c) {
sc.devices().clocks().apply(c.name, [&] (Driver::Clock &clock) {
xml.node("clock", [&] () {
xml.attribute("rate", clock.rate().value);
xml.attribute("name", c.driver_name);
});
});
});
_report_platform_specifics(xml, sc);
});
}

View File

@ -15,23 +15,30 @@
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_
#include <base/allocator.h>
#include <base/heap.h>
#include <platform_session/device.h>
#include <util/list.h>
#include <util/list_model.h>
#include <util/reconstructible.h>
#include <util/xml_generator.h>
#include <clock.h>
#include <reset.h>
#include <power.h>
namespace Driver {
using namespace Genode;
class Env;
class Device;
struct Device_model;
class Session_component;
struct Irq_update_policy;
struct Io_mem_update_policy;
struct Property_update_policy;
struct Clock_update_policy;
struct Reset_domain_update_policy;
struct Power_domain_update_policy;
}
@ -83,6 +90,41 @@ class Driver::Device : private List_model<Device>::Element
: name(name), value(value) {}
};
struct Clock : List_model<Clock>::Element
{
using Name = Genode::String<64>;
Name name;
Name parent;
Name driver_name;
unsigned long rate;
Clock(Name name,
Name parent,
Name driver_name,
unsigned long rate)
: name(name), parent(parent),
driver_name(driver_name), rate(rate) {}
};
struct Power_domain : List_model<Power_domain>::Element
{
using Name = Genode::String<64>;
Name name;
Power_domain(Name name) : name(name) {}
};
struct Reset_domain : List_model<Reset_domain>::Element
{
using Name = Genode::String<64>;
Name name;
Reset_domain(Name name) : name(name) {}
};
Device(Name name, Type type);
virtual ~Device();
@ -118,12 +160,15 @@ class Driver::Device : private List_model<Device>::Element
friend class List_model<Device>;
friend class List<Device>;
Name _name;
Type _type;
Owner _owner {};
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 {};
List_model<Clock> _clock_list {};
List_model<Power_domain> _power_domain_list {};
List_model<Reset_domain> _reset_domain_list {};
/*
* Noncopyable
@ -138,8 +183,11 @@ class Driver::Device_model :
{
private:
Driver::Env & _env;
List_model<Device> _model {};
Heap & _heap;
List_model<Device> _model { };
Clocks _clocks { };
Resets _resets { };
Powers _powers { };
public:
@ -147,8 +195,8 @@ class Driver::Device_model :
_model.update_from_xml(*this, node);
}
Device_model(Driver::Env & env)
: _env(env) { }
Device_model(Heap & heap)
: _heap(heap) { }
~Device_model() {
_model.destroy_all_elements(*this); }
@ -173,6 +221,10 @@ class Driver::Device_model :
static bool node_is_element(Genode::Xml_node node) {
return node.has_type("device"); }
Clocks & clocks() { return _clocks; };
Resets & resets() { return _resets; };
Powers & powers() { return _powers; };
};
@ -267,4 +319,101 @@ struct Driver::Property_update_policy : Genode::List_model<Device::Property>::Up
return node.has_type("property"); }
};
struct Driver::Clock_update_policy
: Genode::List_model<Device::Clock>::Update_policy
{
Genode::Allocator & alloc;
Clock_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & clock) {
Genode::destroy(alloc, &clock); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
Element::Name parent = node.attribute_value("parent", Element::Name());
Element::Name driver = node.attribute_value("driver_name", Element::Name());
unsigned long rate = node.attribute_value<unsigned long >("rate", 0);
return *(new (alloc) Element(name, parent, driver, rate));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & clock, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
Element::Name driver_name = node.attribute_value("driver_name", Element::Name());
return name == clock.name && driver_name == clock.driver_name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("clock");
}
};
struct Driver::Power_domain_update_policy
: Genode::List_model<Device::Power_domain>::Update_policy
{
Genode::Allocator & alloc;
Power_domain_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & pd) {
Genode::destroy(alloc, &pd); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return *(new (alloc) Element(name));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & pd, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return name == pd.name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("power-domain");
}
};
struct Driver::Reset_domain_update_policy
: Genode::List_model<Device::Reset_domain>::Update_policy
{
Genode::Allocator & alloc;
Reset_domain_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & pd) {
Genode::destroy(alloc, &pd); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return *(new (alloc) Element(name));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & pd, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return name == pd.name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("reset-domain");
}
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ */

View File

@ -48,7 +48,7 @@ Device_component::io_mem(unsigned idx, Range &range, Cache cache)
return;
if (!iomem.io_mem.constructed())
iomem.io_mem.construct(_session.env().env,
iomem.io_mem.construct(_session.env(),
iomem.range.start,
iomem.range.size,
cache == WRITE_COMBINED);
@ -72,7 +72,7 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
return;
if (!irq.irq.constructed())
irq.irq.construct(_session.env().env, irq.number);
irq.irq.construct(_session.env(), irq.number);
cap = irq.irq->cap();
});

View File

@ -22,7 +22,6 @@
#include <platform_session/platform_session.h>
#include <util/reconstructible.h>
#include <env.h>
#include <device.h>
namespace Driver {

View File

@ -11,7 +11,6 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include <env.h>
#include <device.h>
using Driver::Device_model;
@ -20,21 +19,36 @@ using Driver::Device;
void Device_model::destroy_element(Device & device)
{
{
Irq_update_policy policy(_env.heap);
Irq_update_policy policy(_heap);
device._irq_list.destroy_all_elements(policy);
}
{
Io_mem_update_policy policy(_env.heap);
Io_mem_update_policy policy(_heap);
device._io_mem_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_env.heap);
Property_update_policy policy(_heap);
device._property_list.destroy_all_elements(policy);
}
Genode::destroy(_env.heap, &device);
{
Clock_update_policy policy(_heap);
device._clock_list.destroy_all_elements(policy);
}
{
Power_domain_update_policy policy(_heap);
device._power_domain_list.destroy_all_elements(policy);
}
{
Reset_domain_update_policy policy(_heap);
device._reset_domain_list.destroy_all_elements(policy);
}
Genode::destroy(_heap, &device);
}
@ -42,7 +56,7 @@ Device & Device_model::create_element(Genode::Xml_node node)
{
Device::Name name = node.attribute_value("name", Device::Name());
Device::Type type = node.attribute_value("type", Device::Type());
return *(new (_env.heap) Device(name, type));
return *(new (_heap) Device(name, type));
}
@ -50,17 +64,32 @@ void Device_model::update_element(Device & device,
Genode::Xml_node node)
{
{
Irq_update_policy policy(_env.heap);
Irq_update_policy policy(_heap);
device._irq_list.update_from_xml(policy, node);
}
{
Io_mem_update_policy policy(_env.heap);
Io_mem_update_policy policy(_heap);
device._io_mem_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_env.heap);
Property_update_policy policy(_heap);
device._property_list.update_from_xml(policy, node);
}
{
Clock_update_policy policy(_heap);
device._clock_list.update_from_xml(policy, node);
}
{
Power_domain_update_policy policy(_heap);
device._power_domain_list.update_from_xml(policy, node);
}
{
Reset_domain_update_policy policy(_heap);
device._reset_domain_list.update_from_xml(policy, node);
}
}

View File

@ -1,41 +0,0 @@
/*
* \brief Platform driver for ARM
* \author Stefan Kalkowski
* \date 2020-04-12
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#include <base/attached_rom_dataspace.h>
#include <base/env.h>
#include <base/heap.h>
#include <device.h>
namespace Driver {
using namespace Genode;
struct Env;
};
struct Driver::Env
{
Genode::Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Device_model devices { *this };
Env(Genode::Env &env) : env(env) {}
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_ */

View File

@ -12,7 +12,6 @@
*/
#include <base/component.h>
#include <env.h>
#include <root.h>
namespace Driver { struct Main; };
@ -21,25 +20,29 @@ struct Driver::Main
{
void update_config();
Driver::Env env;
Signal_handler<Main> config_handler { env.env.ep(), *this,
Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Device_model devices { heap };
Signal_handler<Main> config_handler { env.ep(), *this,
&Main::update_config };
Driver::Root root { env };
Driver::Root root { env, sliced_heap, config, devices };
Main(Genode::Env & e)
: env(e)
{
env.devices.update(env.config.xml());
env.config.sigh(config_handler);
env.env.parent().announce(env.env.ep().manage(root));
devices.update(config.xml());
config.sigh(config_handler);
env.parent().announce(env.ep().manage(root));
}
};
void Driver::Main::update_config()
{
env.config.update();
env.devices.update(env.config.xml());
config.update();
devices.update(config.xml());
root.update_policy();
}

View File

@ -0,0 +1,90 @@
/*
* \brief Utility for finding objecs by name
* \author Norman Feske
* \date 2021-11-11
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NAMED_REGISTRY_H_
#define _NAMED_REGISTRY_H_
#include <util/string.h>
#include <util/avl_tree.h>
#include <util/noncopyable.h>
namespace Driver { template <typename T> class Named_registry; }
template <typename T>
class Driver::Named_registry : Noncopyable
{
private:
Avl_tree<T> _tree { };
public:
class Element : private Avl_node<T>
{
public:
using Name = Genode::String<64>;
Name const name;
private:
Named_registry<T> &_registry;
bool higher(T const *other) const { return name > other->name; }
friend class Avl_tree<T>;
friend class Avl_node<T>;
friend class Named_registry<T>;
static T *_matching_sub_tree(T &curr, Name const &name)
{
typename Avl_node<T>::Side side = (curr.name > name);
return curr.Avl_node<T>::child(side);
}
public:
Element(Named_registry &registry, Name const &name)
:
name(name), _registry(registry)
{
_registry._tree.insert(this);
}
~Element()
{
_registry._tree.remove(this);
}
};
template <typename FN>
void apply(typename Element::Name const &name, FN const &fn)
{
T *curr_ptr = _tree.first();
for (;;) {
if (!curr_ptr)
return;
if (curr_ptr->name == name) {
fn(*curr_ptr);
return;
}
curr_ptr = Element::_matching_sub_tree(*curr_ptr, name);
}
}
};
#endif /* _NAMED_REGISTRY_H_ */

View File

@ -0,0 +1,56 @@
/*
* \brief Power-domain interface
* \author Norman Feske
* \date 2021-11-18
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _POWER_H_
#define _POWER_H_
#include <types.h>
#include <named_registry.h>
namespace Driver {
using namespace Genode;
struct Power;
using Powers = Named_registry<Power>;
}
class Driver::Power : Powers::Element, Interface
{
private:
/* friendships needed to make 'Powers::Element' private */
friend class Powers::Element;
friend class Avl_node<Power>;
friend class Avl_tree<Power>;
Switch<Power> _switch { *this, &Power::_on, &Power::_off };
protected:
virtual void _on() { }
virtual void _off() { }
public:
using Name = Powers::Element::Name;
using Powers::Element::name;
using Powers::Element::Element;
void on() { _switch.use(); }
void off() { _switch.unuse(); }
};
#endif /* _POWER_H_ */

View File

@ -0,0 +1,56 @@
/*
* \brief Reset-domain interface
* \author Norman Feske
* \date 2021-11-03
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _RESET_H_
#define _RESET_H_
#include <types.h>
#include <named_registry.h>
namespace Driver {
using namespace Genode;
struct Reset;
using Resets = Named_registry<Reset>;
}
class Driver::Reset : Resets::Element, Interface
{
private:
/* friendships needed to make 'Resets::Element' private */
friend class Resets::Element;
friend class Avl_node<Reset>;
friend class Avl_tree<Reset>;
Switch<Reset> _switch { *this, &Reset::_deassert, &Reset::_assert };
protected:
virtual void _deassert() { }
virtual void _assert() { }
public:
using Name = Resets::Element::Name;
using Resets::Element::name;
using Resets::Element::Element;
void deassert() { _switch.use(); }
void assert() { _switch.unuse(); }
};
#endif /* _RESET_H_ */

View File

@ -20,7 +20,7 @@ void Driver::Root::update_policy()
_sessions.for_each([&] (Session_component & sc)
{
try {
Session_policy const policy { sc._label, _env.config.xml() };
Session_policy const policy { sc._label, _config.xml() };
sc.update_policy(policy.attribute_value("info", false),
policy.attribute_value("version", Version()));
}
@ -39,10 +39,10 @@ Driver::Session_component * Driver::Root::_create_session(const char *args)
try {
Session::Label const label { session_label_from_args(args) };
Session_policy const policy { label, _env.config.xml() };
Session_policy const policy { label, _config.xml() };
sc = new (md_alloc())
Session_component(_env, _sessions, label,
Session_component(_env, _config, _devices, _sessions, label,
session_resources_from_args(args),
session_diag_from_args(args),
policy.attribute_value("info", false),
@ -67,6 +67,9 @@ void Driver::Root::_upgrade_session(Session_component * sc, const char * args)
}
Driver::Root::Root(Driver::Env & env)
: Root_component<Session_component>(env.env.ep(), env.sliced_heap),
_env(env) { }
Driver::Root::Root(Env & env,
Sliced_heap & sliced_heap,
Attached_rom_dataspace & config,
Device_model & devices)
: Root_component<Session_component>(env.ep(), sliced_heap),
_env(env), _config(config), _devices(devices) { }

View File

@ -27,7 +27,10 @@ class Driver::Root : public Root_component<Session_component>
{
public:
Root(Driver::Env & env);
Root(Env & env,
Sliced_heap & sliced_heap,
Attached_rom_dataspace & config,
Device_model & devices);
void update_policy();
@ -37,7 +40,9 @@ class Driver::Root : public Root_component<Session_component>
void _upgrade_session(Session_component *, const char *) override;
Driver::Env & _env;
Env & _env;
Attached_rom_dataspace & _config;
Device_model & _devices;
Registry<Session_component> _sessions {};
};

View File

@ -25,17 +25,17 @@ 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);
return _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);
_env.ep().rpc_ep().dissolve(&dc);
destroy(heap(), &dc);
_env.devices.for_each([&] (Device & dev) {
_devices.for_each([&] (Device & dev) {
if (name == dev.name()) dev.release(*this); });
}
@ -53,7 +53,7 @@ bool Session_component::matches(Device & dev) const
bool ret = false;
try {
Session_policy const policy { label(), _env.config.xml() };
Session_policy const policy { label(), _config.xml() };
policy.for_each_sub_node("device", [&] (Xml_node node) {
if (dev.name() == node.attribute_value("name", Device::Name()))
ret = true;
@ -73,7 +73,7 @@ void Session_component::update_policy(bool info, Policy_version version)
_device_registry.for_each([&] (Device_component & dc) {
Device_state state = AWAY;
_env.devices.for_each([&] (Device & dev) {
_devices.for_each([&] (Device & dev) {
if (dev.name() != dc.device())
return;
state = (dev.owner() == _owner_id) ? UNCHANGED : CHANGED;
@ -103,17 +103,20 @@ void Session_component::produce_xml(Xml_generator &xml)
if (_version.valid())
xml.attribute("version", _version);
_env.devices.for_each([&] (Device & dev) {
_devices.for_each([&] (Device & dev) {
if (matches(dev)) dev.report(xml, *this); });
}
Genode::Env & Session_component::env() { return _env; }
Driver::Device_model & Session_component::devices() { return _devices; }
Genode::Heap & Session_component::heap() { return _md_alloc; }
Driver::Env & Session_component::env() { return _env; }
void Session_component::update_devices_rom()
{
_rom_session.trigger_update();
@ -138,7 +141,7 @@ Session_component::acquire_device(Platform::Session::Device_name const &name)
if (cap.valid())
return cap;
_env.devices.for_each([&] (Device & dev)
_devices.for_each([&] (Device & dev)
{
if (dev.name() != name || !matches(dev))
return;
@ -164,7 +167,7 @@ Session_component::acquire_single_device()
if (cap.valid())
return cap;
_env.devices.for_each([&] (Device & dev) {
_devices.for_each([&] (Device & dev) {
if (matches(dev) && !dev.owner().valid())
cap = _acquire(dev); });
@ -231,18 +234,20 @@ Genode::addr_t Session_component::dma_addr(Ram_dataspace_capability ram_cap)
}
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_component::Session_component(Env & env,
Attached_rom_dataspace & config,
Device_model & devices,
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_object<Platform::Session>(env.ep(), resources, label, diag),
Session_registry::Element(registry, *this),
Dynamic_rom_session::Xml_producer("devices"),
_env(env), _info(info), _version(version)
_env(env), _config(config), _devices(devices), _info(info), _version(version)
{
/*
* FIXME: As the ROM session does not propagate Out_of_*

View File

@ -14,6 +14,7 @@
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_
#include <base/attached_rom_dataspace.h>
#include <base/env.h>
#include <base/heap.h>
#include <base/quota_guard.h>
@ -42,18 +43,21 @@ class Driver::Session_component
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(Env & env,
Attached_rom_dataspace & config,
Device_model & devices,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag,
bool const info,
Policy_version const version);
~Session_component();
Env & env();
Heap & heap();
Driver::Env & env();
Device_model & devices();
bool matches(Device &) const;
void update_devices_rom();
@ -92,16 +96,18 @@ class Driver::Session_component
: Registry<Dma_buffer>::Element(registry, *this), cap(cap) {}
};
Driver::Env & _env;
Env & _env;
Attached_rom_dataspace & _config;
Device_model & _devices;
Device::Owner _owner_id { *this };
Constrained_ram_allocator _env_ram { _env.env.pd(),
Constrained_ram_allocator _env_ram { _env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Heap _md_alloc { _env_ram, _env.env.rm() };
Heap _md_alloc { _env_ram, _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 };
Dynamic_rom_session _rom_session { _env.ep(), _env.ram(),
_env.rm(), *this };
bool _info;
Policy_version _version;

View File

@ -0,0 +1,73 @@
/*
* \brief Common types used by the platform driver
* \author Norman Feske
* \date 2021-11-03
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _TYPES_H_
#define _TYPES_H_
#include <util/avl_tree.h>
namespace Driver {
using namespace Genode;
template <size_t N1, size_t N2>
static inline bool operator > (String<N1> const &s1, String<N2> const &s2)
{
return strcmp(s1.string(), s2.string()) > 0;
}
/**
* Utility for switching clocks/resets/powers on/off depending on the
* number of users
*/
template <typename DEV>
class Switch : Noncopyable
{
private:
unsigned _count = 0;
DEV &_dev;
void (DEV::*_activate) ();
void (DEV::*_deactivate) ();
public:
Switch(DEV &dev, void (DEV::*activate) (), void (DEV::*deactivate) ())
:
_dev(dev), _activate(activate), _deactivate(deactivate)
{ }
void use()
{
if (_count == 0)
(_dev.*_activate)();
_count++;
}
void unuse()
{
if (_count == 0)
return;
_count--;
if (--_count == 0)
(_dev.*_deactivate)();
}
};
}
#endif /* _TYPES_H_ */