platform_drv: consider IRQ type, mode, polarity

Parse the devices ROM for additional interrupt information, and
pass them to the IRQ connection when needed.

Fix genodelabs/genode#4497
This commit is contained in:
Stefan Kalkowski 2022-05-02 14:56:14 +02:00 committed by Christian Helmuth
parent de7fdd3e1a
commit 6b92006565
3 changed files with 60 additions and 12 deletions

View File

@ -75,7 +75,12 @@ class Driver::Device : private List_model<Device>::Element
struct Irq : List_model<Irq>::Element
{
unsigned number;
enum Type { LEGACY, MSI, MSIX };
unsigned number;
Type type { LEGACY };
Irq_session::Polarity polarity { Irq_session::POLARITY_UNCHANGED };
Irq_session::Trigger mode { Irq_session::TRIGGER_UNCHANGED };
Irq(unsigned number) : number(number) {}
};
@ -150,7 +155,7 @@ class Driver::Device : private List_model<Device>::Element
{
unsigned idx = 0;
_irq_list.for_each([&] (Irq const & irq) {
fn(idx++, irq.number); });
fn(idx++, irq.number, irq.type, irq.polarity, irq.mode, 0); });
}
template <typename FN> void for_each_io_mem(FN const & fn)
@ -258,8 +263,22 @@ struct Driver::Irq_update_policy : Genode::List_model<Device::Irq>::Update_polic
Element & create_element(Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return *(new (alloc) Element(number));
unsigned number = node.attribute_value<unsigned>("number", 0);
Element & elem = *(new (alloc) Element(number));
String<16> polarity = node.attribute_value("polarity", String<16>());
String<16> mode = node.attribute_value("mode", String<16>());
String<16> type = node.attribute_value("type", String<16>());
if (polarity.valid())
elem.polarity = (polarity == "high") ? Irq_session::POLARITY_HIGH
: Irq_session::POLARITY_LOW;
if (mode.valid())
elem.mode = (mode == "edge") ? Irq_session::TRIGGER_EDGE
: Irq_session::TRIGGER_LEVEL;
if (type.valid())
elem.type = (type == "msi-x") ? Element::MSIX : Element::MSI;
return elem;
}
void update_element(Element &, Genode::Xml_node) {}

View File

@ -71,8 +71,21 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx)
if (irq.idx != idx)
return;
if (!irq.irq.constructed())
irq.irq.construct(_session.env(), irq.number);
if (!irq.irq.constructed()) {
/*
* Unfortunately, we have to deliver the PCI config space address
* to the IRQ session for working MSI(-x) on NOVA. It is used
* for IOMMU configuration as some kind of access control
*
* Once, the IOMMU support is solved kernel-independent, this
* attribute has to be removed from the IRQs
*/
addr_t pci_cfg_addr = (irq.type != Device::Irq::LEGACY)
? irq.pci_config_addr : 0;
irq.irq.construct(_session.env(), irq.number, irq.mode, irq.polarity,
pci_cfg_addr);
}
cap = irq.irq->cap();
});
@ -120,13 +133,19 @@ Device_component::Device_component(Registry<Device_component> & registry,
*/
try {
device.for_each_irq([&] (unsigned idx, unsigned nr)
device.for_each_irq([&] (unsigned idx,
unsigned nr,
Device::Irq::Type type,
Irq_session::Polarity polarity,
Irq_session::Trigger mode,
addr_t pci_cfg_addr)
{
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);
new (session.heap()) Irq(_irq_registry, idx, nr, type,
polarity, mode, pci_cfg_addr);
});
device.for_each_io_mem([&] (unsigned idx, Range range)

View File

@ -40,14 +40,24 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
{
unsigned idx;
unsigned number;
Device::Irq::Type type;
Irq_session::Polarity polarity;
Irq_session::Trigger mode;
addr_t pci_config_addr;
Constructible<Irq_connection> irq {};
Irq(Registry<Irq> & registry,
unsigned idx,
unsigned number)
Irq(Registry<Irq> & registry,
unsigned idx,
unsigned number,
Device::Irq::Type type,
Irq_session::Polarity polarity,
Irq_session::Trigger mode,
addr_t pci_config_addr)
:
Registry<Irq>::Element(registry, *this),
idx(idx), number(number) {}
idx(idx), number(number), type(type),
polarity(polarity), mode(mode),
pci_config_addr(pci_config_addr) {}
};
struct Io_mem : Registry<Io_mem>::Element