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.
This commit is contained in:
parent
d137f0f2bf
commit
3c23ddb2d5
|
@ -12,17 +12,63 @@
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/mmio.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
#include <sinfo.h>
|
||||||
|
|
||||||
using namespace Genode;
|
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)
|
Native_region * Platform::_core_only_mmio_regions(unsigned const i)
|
||||||
{
|
{
|
||||||
static Native_region _regions[] =
|
static Native_region _regions[] =
|
||||||
{
|
{
|
||||||
/* Sinfo pages */
|
/* Sinfo pages */
|
||||||
{ 0x000e00000000, 0x7000 },
|
{ 0x000e00000000, 0x7000 },
|
||||||
|
|
||||||
/* Timer page */
|
/* Timer page */
|
||||||
{ 0x000e00010000, 0x1000 },
|
{ 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,
|
bool Platform::get_msi_params(const addr_t mmconf, addr_t &address,
|
||||||
addr_t &data, unsigned &irq_number)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue