diff --git a/repos/os/src/drivers/platform/device.h b/repos/os/src/drivers/platform/device.h index 3aa5bdc990..ff59c19d2a 100644 --- a/repos/os/src/drivers/platform/device.h +++ b/repos/os/src/drivers/platform/device.h @@ -75,7 +75,12 @@ class Driver::Device : private List_model::Element struct Irq : List_model::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::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 void for_each_io_mem(FN const & fn) @@ -258,8 +263,22 @@ struct Driver::Irq_update_policy : Genode::List_model::Update_polic Element & create_element(Genode::Xml_node node) { - unsigned number = node.attribute_value("number", 0); - return *(new (alloc) Element(number)); + unsigned number = node.attribute_value("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) {} diff --git a/repos/os/src/drivers/platform/device_component.cc b/repos/os/src/drivers/platform/device_component.cc index 5ec400f0de..5df487a3c8 100644 --- a/repos/os/src/drivers/platform/device_component.cc +++ b/repos/os/src/drivers/platform/device_component.cc @@ -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 & 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) diff --git a/repos/os/src/drivers/platform/device_component.h b/repos/os/src/drivers/platform/device_component.h index babefbef91..1e3d4c5b79 100644 --- a/repos/os/src/drivers/platform/device_component.h +++ b/repos/os/src/drivers/platform/device_component.h @@ -40,14 +40,24 @@ class Driver::Device_component : public Rpc_object irq {}; - Irq(Registry & registry, - unsigned idx, - unsigned number) + Irq(Registry & registry, + unsigned idx, + unsigned number, + Device::Irq::Type type, + Irq_session::Polarity polarity, + Irq_session::Trigger mode, + addr_t pci_config_addr) : Registry::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::Element