From 3c23ddb2d56f04957d8529126a537dd7c9991e25 Mon Sep 17 00:00:00 2001 From: Reto Buerki Date: Tue, 16 Feb 2016 17:13:47 +0100 Subject: [PATCH] hw_x86_64_muen: Add support for MSI Use the new Sinfo::get_dev_info function to retrieve device information in the platform-specific get_msi_params function. If the requested device supports MSI, set the IRQ and MSI address/data register values to enable MSIs in remappable format (see VT-d specification, section 5.1.2.2). Currently only one MSI per device is supported as the subhandle in the data register is always set to 0. --- .../core/spec/x86_64/muen/platform_support.cc | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/repos/base-hw/src/core/spec/x86_64/muen/platform_support.cc b/repos/base-hw/src/core/spec/x86_64/muen/platform_support.cc index 7927f674f..c974939af 100644 --- a/repos/base-hw/src/core/spec/x86_64/muen/platform_support.cc +++ b/repos/base-hw/src/core/spec/x86_64/muen/platform_support.cc @@ -12,17 +12,63 @@ * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ +#include + /* core includes */ #include +#include using namespace Genode; +struct Mmconf_address : Register<64> +{ + enum { PCI_CONFIG_BASE = 0xf8000000 }; + + struct Sid : Bitfield<12, 16> { }; + + /** + * Calculate SID (source-id, see VT-d spec section 3.4.1) from device PCI + * config space address. + */ + static unsigned to_sid(access_t const addr) { + return Sid::get(addr - PCI_CONFIG_BASE); } +}; + +struct Msi_handle : Register<16> +{ + struct Bits_0 : Bitfield<0, 15> { }; + struct Bits_1 : Bitfield<15, 1> { }; +}; + +struct Msi_address : Register<32> +{ + enum { BASE = 0xfee00010 }; + + struct Bits_0 : Bitfield<5, 15> { }; + struct Bits_1 : Bitfield<2, 1> { }; + + /** + * Return MSI address register value for given handle to enable Interrupt + * Requests in Remappable Format, see VT-d specification section 5.1.2.2. + */ + static access_t to_msi_addr(Msi_handle::access_t const handle) + { + access_t addr = BASE; + Bits_0::set(addr, Msi_handle::Bits_0::get(handle)); + Bits_1::set(addr, Msi_handle::Bits_1::get(handle)); + return addr; + } +}; + + Native_region * Platform::_core_only_mmio_regions(unsigned const i) { static Native_region _regions[] = { /* Sinfo pages */ { 0x000e00000000, 0x7000 }, + /* Timer page */ { 0x000e00010000, 0x1000 }, }; @@ -36,7 +82,25 @@ void Platform::setup_irq_mode(unsigned, unsigned, unsigned) { } bool Platform::get_msi_params(const addr_t mmconf, addr_t &address, addr_t &data, unsigned &irq_number) { - return false; + const unsigned sid = Mmconf_address::to_sid(mmconf); + + struct Sinfo::Dev_info dev_info; + if (!Sinfo::get_dev_info(sid, &dev_info)) { + PERR("error retrieving Muen info for device with SID 0x%x", sid); + return false; + } + if (!dev_info.msi_capable) { + PERR("device 0x%x not configured for MSI", sid); + return false; + } + + data = 0; + address = Msi_address::to_msi_addr(dev_info.irte_start); + irq_number = dev_info.irq_start; + + PDBG("enabling MSI for device with SID 0x%x: IRTE %d, IRQ %d", + sid, dev_info.irte_start, irq_number); + return true; }