diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device.cc b/repos/os/src/drivers/platform/spec/x86/pci_device.cc index cf2c20c7c4..529d9d403c 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device.cc +++ b/repos/os/src/drivers/platform/spec/x86/pci_device.cc @@ -196,14 +196,16 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i if (_irq_session->msi()) Genode::log(_device_config, " uses ", msix_used ? "MSI-X " : "", + (msix_used && msi_cap) ? "(supports MSI) " : "", msi_used ? "MSI ": "", + (msi_used && msix_cap) ? "(supports MSI-X) " : "", (!msi_used && !msix_used) ? "no MSI/-X/IRQ " : "", "vector ", Genode::Hex(_irq_session->msi_data()), ", " "address ", Genode::Hex(_irq_session->msi_address())); else Genode::log(_device_config, " uses IRQ, vector ", Genode::Hex(_irq_line), - ", supports: ", + (msi_cap || msix_cap) ? ", supports:" : "", msi_cap ? " MSI" : "", msix_cap ? " MSI-X" : ""); @@ -284,45 +286,51 @@ bool Platform::Device_component::_setup_msix(Genode::uint16_t const msix_cap) table_off > res.size() - SIZE_IOMEM) return false; - Genode::uint64_t const msix_base = res.base() + table_off; - - Io_mem io_mem(_env, msix_base, SIZE_IOMEM, false); - Attached_dataspace x(_env.rm(), io_mem.dataspace()); - if (slots * SIZEOF_MSI_TABLE_ENTRY > SIZE_IOMEM) return false; - struct Msi_entry : public Mmio { - Msi_entry(addr_t const base) : Mmio(base) { } + Genode::uint64_t const msix_table_phys = res.base() + table_off; - struct Address : Register<0x0, 64> { }; - struct Value : Register<0x8, 32> { }; - struct Vector : Register<0xc, 32> { - struct Mask : Bitfield <0, 1> { }; - }; - } msi_entry_0 (reinterpret_cast(x.local_addr())); + apply_msix_table(res, msix_table_phys, SIZE_IOMEM, + [&](Genode::addr_t const msix_table) + { + struct Msi_entry : public Mmio { + Msi_entry(addr_t const base) : Mmio(base) { } - /* setup first msi-x table entry */ - msi_entry_0.write(msi_address & ~(0x3UL)); - msi_entry_0.write(msi_value); - msi_entry_0.write(0); + struct Address : Register<0x0, 64> { }; + struct Value : Register<0x8, 32> { }; + struct Vector : Register<0xc, 32> { + struct Mask : Bitfield <0, 1> { }; + }; + } msi_entry_0 (msix_table); - /* disable all msi-x table entries beside the first one */ - for (unsigned i = 1; i < slots; i++) { - struct Msi_entry unused (reinterpret_cast(x.local_addr()) + SIZEOF_MSI_TABLE_ENTRY * i); - unused.write(1); - } + /* setup first msi-x table entry */ + msi_entry_0.write(msi_address & ~(0x3UL)); + msi_entry_0.write(msi_value); + msi_entry_0.write(0); - /* enable MSI-X */ - Msix_ctrl::Fmask::set(ctrl, 0); - Msix_ctrl::Enable::set(ctrl, 1); - _device_config.write(_config_access, msix_cap + 2, ctrl, - Platform::Device::ACCESS_16BIT); + /* disable all msi-x table entries beside the first one */ + for (unsigned i = 1; i < slots; i++) { + struct Msi_entry unused (msix_table + SIZEOF_MSI_TABLE_ENTRY * i); + unused.write(1); + } + /* enable MSI-X */ + Msix_ctrl::Fmask::set(ctrl, 0); + Msix_ctrl::Enable::set(ctrl, 1); + _device_config.write(_config_access, msix_cap + 2, ctrl, + Platform::Device::ACCESS_16BIT); + }); + + /* check back that MSI-X got enabled */ ctrl = _device_config.read(_config_access, msix_cap + 2, Platform::Device::ACCESS_16BIT); return Msix_ctrl::Enable::get(ctrl); - } catch (...) { } + } catch (Genode::Out_of_caps) { + Genode::warning("Out_of_caps during MSI-X enablement"); } + catch (Genode::Out_of_ram) { + Genode::warning("Out_of_ram during MSI-X enablement"); } + catch (...) { Genode::warning("MSI-X enablement failed"); } return false; } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h index 460b7a7d47..d1e8735ef0 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h @@ -60,6 +60,7 @@ class Platform::Device_component : public Genode::Rpc_object, private: friend class Genode::List; + friend class Platform::Device_component; public: @@ -222,6 +223,47 @@ class Platform::Device_component : public Genode::Rpc_object, bool _setup_msi(Genode::uint16_t); bool _setup_msix(Genode::uint16_t); + template + void apply_msix_table(Pci::Resource const &lookup, + Genode::addr_t const msix_table_phys, + Genode::size_t const msix_table_size, + FUNC const &fn) + { + Genode::uint8_t max = sizeof(_io_mem) / sizeof(_io_mem[0]); + for (unsigned i = 0; i < max; ++i) { + Pci::Resource res = _device_config.resource(i); + + if (!res.valid() || !res.mem()) + continue; + + if (res.base() != lookup.base() || res.size() != lookup.size()) + continue; + + for (Io_mem * io_mem = _io_mem[i].first(); io_mem; io_mem = io_mem->next()) { + + Dataspace_client ds_client(io_mem->dataspace()); + + if (!(ds_client.phys_addr() <= msix_table_phys && + msix_table_phys + msix_table_size <= ds_client.phys_addr() + ds_client.size())) + continue; + + Genode::size_t const offset = msix_table_phys - ds_client.phys_addr(); + + Attached_dataspace mem_io(_env.rm(), io_mem->dataspace()); + + fn(reinterpret_cast(mem_io.local_addr()) + offset); + + return; + } + } + + /* requested io_mem not allocated by Pci::Resource - try direct */ + Io_mem io_mem(_env, msix_table_phys, msix_table_size, false); + Attached_dataspace mem_io(_env.rm(), io_mem.dataspace()); + Genode::addr_t const msix_table = reinterpret_cast(mem_io.local_addr()); + fn(msix_table); + }; + public: /**