platform: introduce I/O ports in API

* Introduces Platform::Device::Io_port client utility
* Implements I/O ports as common device resources in platform driver

Fix genodelabs/genode#4436
This commit is contained in:
Stefan Kalkowski 2022-03-01 17:05:45 +01:00 committed by Christian Helmuth
parent 8a4cbe3cc9
commit 57aab46fc3
7 changed files with 168 additions and 13 deletions

View File

@ -21,6 +21,7 @@
#include <base/exception.h>
#include <io_mem_session/client.h>
#include <irq_session/client.h>
#include <io_port_session/client.h>
#include <platform_session/connection.h>
class Platform::Device : Interface, Noncopyable
@ -29,6 +30,7 @@ class Platform::Device : Interface, Noncopyable
struct Mmio;
struct Irq;
struct Io_port_range;
typedef Platform::Session::Device_name Name;
@ -52,6 +54,11 @@ class Platform::Device : Interface, Noncopyable
return _cap.call<Device_interface::Rpc_io_mem>(index, range, cache);
}
Io_port_session_capability _io_port_range(unsigned index)
{
return _cap.call<Device_interface::Rpc_io_port_range>(index);
}
Region_map &_rm() { return _platform._rm; }
public:
@ -167,4 +174,33 @@ class Platform::Device::Irq : Noncopyable
}
};
class Platform::Device::Io_port_range : Noncopyable
{
private:
Io_port_session_client _io_port_range;
public:
struct Index { unsigned value; };
Io_port_range(Device &device, Index index)
: _io_port_range(device._io_port_range(index.value)) { }
explicit Io_port_range(Device &device)
: Io_port_range(device, Index { 0 }) { }
uint8_t inb(uint16_t addr) { return _io_port_range.inb(addr); };
uint16_t inw(uint16_t addr) { return _io_port_range.inw(addr); };
uint32_t inl(uint16_t addr) { return _io_port_range.inl(addr); };
void outb(uint16_t addr, uint8_t value) {
_io_port_range.outb(addr, value); };
void outw(uint16_t addr, uint16_t value) {
_io_port_range.outw(addr, value); };
void outl(uint16_t addr, uint32_t value) {
_io_port_range.outl(addr, value); };
};
#endif /* _INCLUDE__PLATFORM_SESSION__DEVICE_H_ */

View File

@ -21,6 +21,7 @@
#include <rom_session/capability.h>
#include <irq_session/capability.h>
#include <io_mem_session/capability.h>
#include <io_port_session/capability.h>
#include <session/session.h>
namespace Platform {
@ -42,8 +43,10 @@ struct Platform::Device_interface : Interface
GENODE_RPC(Rpc_irq, Irq_session_capability, irq, unsigned);
GENODE_RPC(Rpc_io_mem, Io_mem_session_capability, io_mem,
unsigned, Range &, Cache);
GENODE_RPC(Rpc_io_port_range, Io_port_session_capability, io_port_range,
unsigned);
GENODE_RPC_INTERFACE(Rpc_irq, Rpc_io_mem);
GENODE_RPC_INTERFACE(Rpc_irq, Rpc_io_mem, Rpc_io_port_range);
};

View File

@ -122,6 +122,12 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
xml.attribute("number", irq.number);
});
});
_io_port_range_list.for_each([&] (Io_port_range & io_port_range) {
xml.node("io_port_range", [&] () {
xml.attribute("phys_addr", String<16>(Hex(io_port_range.addr)));
xml.attribute("size", String<16>(Hex(io_port_range.size)));
});
});
_property_list.for_each([&] (Property & p) {
xml.node("property", [&] () {
xml.attribute("name", p.name);

View File

@ -35,6 +35,7 @@ namespace Driver {
class Session_component;
struct Irq_update_policy;
struct Io_mem_update_policy;
struct Io_port_update_policy;
struct Property_update_policy;
struct Clock_update_policy;
struct Reset_domain_update_policy;
@ -78,6 +79,15 @@ class Driver::Device : private List_model<Device>::Element
Irq(unsigned number) : number(number) {}
};
struct Io_port_range : List_model<Io_port_range>::Element
{
uint16_t addr;
uint16_t size;
Io_port_range(uint16_t addr, uint16_t size)
: addr(addr), size(size) {}
};
struct Property : List_model<Property>::Element
{
using Name = Genode::String<64>;
@ -149,6 +159,13 @@ class Driver::Device : private List_model<Device>::Element
fn(idx++, iomem.range); });
}
template <typename FN> void for_each_io_port_range(FN const & fn)
{
unsigned idx = 0;
_io_port_range_list.for_each([&] (Io_port_range const & ipr) {
fn(idx++, ipr.addr, ipr.size); });
}
void report(Xml_generator &, Session_component &);
protected:
@ -160,15 +177,16 @@ 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 {};
List_model<Clock> _clock_list {};
List_model<Power_domain> _power_domain_list {};
List_model<Reset_domain> _reset_domain_list {};
Name _name;
Type _type;
Owner _owner {};
List_model<Io_mem> _io_mem_list {};
List_model<Irq> _irq_list {};
List_model<Io_port_range> _io_port_range_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
@ -290,6 +308,39 @@ struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update
};
struct Driver::Io_port_update_policy
: Genode::List_model<Device::Io_port_range>::Update_policy
{
Genode::Allocator & alloc;
Io_port_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & ipr) {
Genode::destroy(alloc, &ipr); }
Element & create_element(Genode::Xml_node node)
{
uint16_t addr = node.attribute_value<uint16_t>("address", 0);
uint16_t size = node.attribute_value<uint16_t>("size", 0);
return *(new (alloc) Element(addr, size));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & ipr, Genode::Xml_node node)
{
uint16_t addr = node.attribute_value<uint16_t>("address", 0);
uint16_t size = node.attribute_value<uint16_t>("size", 0);
return addr == ipr.addr && size == ipr.size;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("io_port_range");
}
};
struct Driver::Property_update_policy : Genode::List_model<Device::Property>::Update_policy
{
Genode::Allocator & alloc;

View File

@ -81,6 +81,25 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
}
Genode::Io_port_session_capability Device_component::io_port_range(unsigned idx)
{
Io_port_session_capability cap;
_io_port_range_registry.for_each([&] (Io_port_range & ipr)
{
if (ipr.idx != idx)
return;
if (!ipr.io_port_range.constructed())
ipr.io_port_range.construct(_session.env(), ipr.addr, ipr.size);
cap = ipr.io_port_range->cap();
});
return cap;
}
Device_component::Device_component(Registry<Device_component> & registry,
Driver::Session_component & session,
Driver::Device & device)
@ -109,7 +128,7 @@ Device_component::Device_component(Registry<Device_component> & registry,
_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});
@ -118,6 +137,17 @@ Device_component::Device_component(Registry<Device_component> & registry,
_cap_quota += Io_mem_session::CAP_QUOTA;
new (session.heap()) Io_mem(_io_mem_registry, idx, range);
});
device.for_each_io_port_range([&] (unsigned idx, uint16_t addr,
uint16_t size)
{
session.ram_quota_guard().withdraw(Ram_quota{Io_port_session::RAM_QUOTA});
_ram_quota += Io_port_session::RAM_QUOTA;
session.cap_quota_guard().withdraw(Cap_quota{Io_port_session::CAP_QUOTA});
_cap_quota += Io_port_session::CAP_QUOTA;
new (session.heap()) Io_port_range(_io_port_range_registry,
idx, addr, size);
});
} catch(...) {
_release_resources();
throw;

View File

@ -16,6 +16,7 @@
#include <base/registry.h>
#include <base/rpc_server.h>
#include <io_port_session/connection.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <platform_session/device.h>
@ -63,6 +64,22 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
idx(idx), range(range) {}
};
struct Io_port_range : Registry<Io_port_range>::Element
{
unsigned idx;
uint16_t addr;
uint16_t size;
Constructible<Io_port_connection> io_port_range {};
Io_port_range(Registry<Io_port_range> & registry,
unsigned idx,
uint16_t addr,
uint16_t size)
:
Registry<Io_port_range>::Element(registry, *this),
idx(idx), addr(addr), size(size) {}
};
Device_component(Registry<Device_component> & registry,
Session_component & session,
Driver::Device & device);
@ -76,8 +93,9 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
** Platform::Device RPC functions **
************************************/
Irq_session_capability irq(unsigned);
Io_mem_session_capability io_mem(unsigned, Range &, Cache);
Irq_session_capability irq(unsigned);
Io_mem_session_capability io_mem(unsigned, Range &, Cache);
Io_port_session_capability io_port_range(unsigned);
private:
@ -88,6 +106,7 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
Registry<Device_component>::Element _reg_elem;
Registry<Irq> _irq_registry {};
Registry<Io_mem> _io_mem_registry {};
Registry<Io_port_range> _io_port_range_registry {};
void _release_resources();

View File

@ -28,6 +28,11 @@ void Device_model::destroy_element(Device & device)
device._io_mem_list.destroy_all_elements(policy);
}
{
Io_port_update_policy policy(_heap);
device._io_port_range_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_heap);
device._property_list.destroy_all_elements(policy);
@ -73,6 +78,11 @@ void Device_model::update_element(Device & device,
device._io_mem_list.update_from_xml(policy, node);
}
{
Io_port_update_policy policy(_heap);
device._io_port_range_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_heap);
device._property_list.update_from_xml(policy, node);