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 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) {} Irq(unsigned number) : number(number) {}
}; };
@ -150,7 +155,7 @@ class Driver::Device : private List_model<Device>::Element
{ {
unsigned idx = 0; unsigned idx = 0;
_irq_list.for_each([&] (Irq const & irq) { _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) 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) Element & create_element(Genode::Xml_node node)
{ {
unsigned number = node.attribute_value<unsigned>("number", 0); unsigned number = node.attribute_value<unsigned>("number", 0);
return *(new (alloc) Element(number)); 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) {} 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) if (irq.idx != idx)
return; return;
if (!irq.irq.constructed()) if (!irq.irq.constructed()) {
irq.irq.construct(_session.env(), irq.number);
/*
* 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(); cap = irq.irq->cap();
}); });
@ -120,13 +133,19 @@ Device_component::Device_component(Registry<Device_component> & registry,
*/ */
try { 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}); session.ram_quota_guard().withdraw(Ram_quota{Irq_session::RAM_QUOTA});
_ram_quota += Irq_session::RAM_QUOTA; _ram_quota += Irq_session::RAM_QUOTA;
session.cap_quota_guard().withdraw(Cap_quota{Irq_session::CAP_QUOTA}); session.cap_quota_guard().withdraw(Cap_quota{Irq_session::CAP_QUOTA});
_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) 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 idx;
unsigned number; unsigned number;
Device::Irq::Type type;
Irq_session::Polarity polarity;
Irq_session::Trigger mode;
addr_t pci_config_addr;
Constructible<Irq_connection> irq {}; Constructible<Irq_connection> irq {};
Irq(Registry<Irq> & registry, Irq(Registry<Irq> & registry,
unsigned idx, unsigned idx,
unsigned number) unsigned number,
Device::Irq::Type type,
Irq_session::Polarity polarity,
Irq_session::Trigger mode,
addr_t pci_config_addr)
: :
Registry<Irq>::Element(registry, *this), 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 struct Io_mem : Registry<Io_mem>::Element