mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-02 01:08:13 +00:00
parent
66e5796017
commit
1c38d4903b
@ -7,6 +7,7 @@ proc append_platform_drv_build_components {} {
|
||||
|
||||
lappend_if [have_platform_drv] build_components drivers/platform
|
||||
lappend_if [have_spec acpi] build_components drivers/acpi
|
||||
lappend_if [have_spec acpi] build_components server/report_rom
|
||||
lappend_if [have_spec pci] build_components drivers/pci
|
||||
}
|
||||
|
||||
@ -15,6 +16,7 @@ proc append_platform_drv_boot_modules {} {
|
||||
|
||||
lappend_if [have_platform_drv] boot_modules platform_drv
|
||||
lappend_if [have_spec acpi] boot_modules acpi_drv
|
||||
lappend_if [have_spec acpi] boot_modules report_rom
|
||||
lappend_if [have_spec pci] boot_modules pci_drv
|
||||
lappend_if [have_spec nova] boot_modules pci_device_pd
|
||||
}
|
||||
@ -37,7 +39,6 @@ proc append_platform_drv_config {} {
|
||||
|
||||
if {[have_platform_drv]} {
|
||||
append config {
|
||||
|
||||
<start name="platform_drv">
|
||||
<resource name="RAM" quantum="1M" />
|
||||
<provides>
|
||||
@ -50,41 +51,78 @@ proc append_platform_drv_config {} {
|
||||
|
||||
if {[have_spec acpi]} {
|
||||
|
||||
append config "
|
||||
append config "
|
||||
<start name=\"acpi_drv\" [platform_drv_priority]>"
|
||||
|
||||
append config {
|
||||
<resource name="RAM" quantum="5M" constrain_phys="yes"/>
|
||||
append config {
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="Report"> <child name="acpi_report_rom"/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append config "
|
||||
<start name=\"acpi_report_rom\" [platform_drv_priority]>"
|
||||
|
||||
append config {
|
||||
<binary name="report_rom"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides>
|
||||
<service name="PCI"/>
|
||||
<service name="IRQ" />
|
||||
<service name="ROM" />
|
||||
<service name="Report" />
|
||||
</provides>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
<config>
|
||||
<policy label="acpi_drv"> <pci class="ALL"/> </policy>}
|
||||
|
||||
append config [platform_drv_policy]
|
||||
|
||||
append config {
|
||||
<rom> <policy label="pci_drv -> acpi" report="acpi_drv -> acpi"/> </rom>
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
}
|
||||
|
||||
if {[expr ![have_spec acpi] && [have_spec pci]]} {
|
||||
if {[have_spec pci]} {
|
||||
|
||||
append config "
|
||||
append config "
|
||||
<start name=\"pci_drv\" [platform_drv_priority]>"
|
||||
|
||||
append config {
|
||||
append config {
|
||||
<resource name="RAM" quantum="3M" constrain_phys="yes"/>
|
||||
<provides> <service name="PCI"/> </provides>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
<route>}
|
||||
|
||||
if {[have_spec acpi]} {
|
||||
append config {
|
||||
<service name="ROM">
|
||||
<if-arg key="label" value="acpi"/> <child name="acpi_report_rom"/>
|
||||
</service>}
|
||||
}
|
||||
|
||||
append config {
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>}
|
||||
|
||||
if {[have_spec acpi]} {
|
||||
|
||||
append config {
|
||||
<config>}
|
||||
|
||||
append config [platform_drv_policy]
|
||||
} else {
|
||||
|
||||
append config {
|
||||
append config {
|
||||
<config acpi="no">}
|
||||
|
||||
}
|
||||
|
||||
append config [platform_drv_policy]
|
||||
|
||||
append config {
|
||||
</config>
|
||||
</start>}
|
||||
|
||||
|
@ -9,11 +9,10 @@ set build_components {
|
||||
test/input
|
||||
}
|
||||
|
||||
lappend_if [have_spec acpi] build_components drivers/acpi
|
||||
lappend_if [have_spec pci] build_components drivers/pci
|
||||
lappend_if [have_spec pci] build_components drivers/pci/device_pd
|
||||
lappend_if [have_spec platform_arndale] build_components drivers/platform
|
||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
@ -42,12 +41,6 @@ append config {
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec platform_arndale] config {
|
||||
<start name="platform_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Regulator"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec gpio] config {
|
||||
<start name="gpio_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
@ -55,33 +48,7 @@ append_if [have_spec gpio] config {
|
||||
<config/>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec acpi] config {
|
||||
<start name="acpi">
|
||||
<resource name="RAM" quantum="8M" constrain_phys="yes"/>
|
||||
<binary name="acpi_drv"/>
|
||||
<provides>
|
||||
<service name="PCI"/>
|
||||
<service name="IRQ" />
|
||||
</provides>
|
||||
<config>
|
||||
<policy label="acpi_drv">
|
||||
<pci class="ALL"/>
|
||||
</policy>
|
||||
<policy label="usb_drv">
|
||||
<pci class="USB"/>
|
||||
</policy>
|
||||
</config>
|
||||
<route>
|
||||
<service name="PCI"> <any-child /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append_if [expr ![have_spec acpi] && [have_spec pci]] config {
|
||||
<start name="pci_drv">
|
||||
<resource name="RAM" quantum="5M" constrain_phys="yes"/>
|
||||
<provides><service name="PCI"/></provides>
|
||||
</start>}
|
||||
append_platform_drv_config
|
||||
|
||||
append config {
|
||||
<start name="timer">
|
||||
@ -111,12 +78,10 @@ set boot_modules {
|
||||
core init timer usb_drv test-input
|
||||
}
|
||||
|
||||
lappend_if [have_spec acpi] boot_modules acpi_drv
|
||||
lappend_if [have_spec pci] boot_modules pci_drv
|
||||
lappend_if [have_spec nova] boot_modules pci_device_pd
|
||||
lappend_if [have_spec platform_arndale] boot_modules platform_drv
|
||||
lappend_if [have_spec gpio] boot_modules gpio_drv
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -m 256 -usb -usbdevice mouse -usbdevice keyboard"
|
||||
|
@ -49,7 +49,7 @@ class Genode::Irq_proxy : public THREAD,
|
||||
char _name[32];
|
||||
Lock _startup_lock;
|
||||
|
||||
long _irq_number;
|
||||
unsigned _irq_number;
|
||||
|
||||
Lock _mutex; /* protects this object */
|
||||
int _num_sharers; /* number of clients sharing this IRQ */
|
||||
@ -86,9 +86,9 @@ class Genode::Irq_proxy : public THREAD,
|
||||
** Implementation **
|
||||
********************/
|
||||
|
||||
const char *_construct_name(long irq_number)
|
||||
const char *_construct_name(unsigned irq_number)
|
||||
{
|
||||
snprintf(_name, sizeof(_name), "irqproxy%02lx", irq_number);
|
||||
snprintf(_name, sizeof(_name), "irqproxy%02x", irq_number);
|
||||
return _name;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ class Genode::Irq_proxy : public THREAD,
|
||||
|
||||
public:
|
||||
|
||||
Irq_proxy(long irq_number)
|
||||
Irq_proxy(unsigned irq_number)
|
||||
:
|
||||
THREAD(_construct_name(irq_number)),
|
||||
_startup_lock(Lock::LOCKED), _irq_number(irq_number),
|
||||
@ -186,7 +186,7 @@ class Genode::Irq_proxy : public THREAD,
|
||||
s->notify();
|
||||
}
|
||||
|
||||
long irq_number() const { return _irq_number; }
|
||||
unsigned irq_number() const { return _irq_number; }
|
||||
|
||||
virtual bool add_sharer(Irq_sigh *s)
|
||||
{
|
||||
@ -217,7 +217,10 @@ class Genode::Irq_proxy : public THREAD,
|
||||
}
|
||||
|
||||
template <typename PROXY>
|
||||
static PROXY *get_irq_proxy(long irq_number, Range_allocator *irq_alloc = 0)
|
||||
static PROXY *get_irq_proxy(unsigned irq_number,
|
||||
Range_allocator *irq_alloc = 0,
|
||||
Genode::Irq_session::Trigger trigger = Genode::Irq_session::TRIGGER_UNCHANGED,
|
||||
Genode::Irq_session::Polarity polarity = Genode::Irq_session::POLARITY_UNCHANGED)
|
||||
{
|
||||
static List<Irq_proxy> proxies;
|
||||
static Lock proxies_lock;
|
||||
@ -233,7 +236,8 @@ class Genode::Irq_proxy : public THREAD,
|
||||
if (!irq_alloc || irq_alloc->alloc_addr(1, irq_number).is_error())
|
||||
return 0;
|
||||
|
||||
PROXY *new_proxy = new (env()->heap()) PROXY(irq_number);
|
||||
PROXY *new_proxy = new (env()->heap()) PROXY(irq_number, trigger,
|
||||
polarity);
|
||||
proxies.insert(new_proxy);
|
||||
return new_proxy;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
# Build
|
||||
#
|
||||
|
||||
assert_spec x86
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
drivers/input
|
||||
@ -46,6 +48,9 @@ append config {
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="IRQ"> <parent/> </service>
|
||||
<service name="IO_PORT"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
@ -58,6 +63,8 @@ append config {
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="IRQ"> <parent/> </service>
|
||||
<service name="PCI"> <any-child/> </service>
|
||||
</route>
|
||||
</start>
|
||||
@ -93,6 +100,7 @@ set boot_modules {
|
||||
test-input
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief ACPI parsing and PCI rewriting code
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \author Alexander Boettcher
|
||||
* \date 2012-02-25
|
||||
*
|
||||
* This code parses the DSDT and SSDT-ACPI tables and extracts the PCI-bridge
|
||||
@ -10,15 +11,17 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
||||
* Copyright (C) 2009-2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* base includes */
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <pci_session/connection.h>
|
||||
#include <pci_device/client.h>
|
||||
|
||||
/* os includes */
|
||||
#include <os/reporter.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
|
||||
#include "acpi.h"
|
||||
@ -165,7 +168,7 @@ class Irq_override : public List<Irq_override>::Element
|
||||
return &_list;
|
||||
}
|
||||
|
||||
bool match(uint32_t irq) const { return irq == _irq; }
|
||||
uint32_t irq() const { return _irq; }
|
||||
uint32_t gsi() const { return _gsi; }
|
||||
uint32_t flags() const { return _flags; }
|
||||
};
|
||||
@ -373,8 +376,9 @@ class Pci_routing : public List<Pci_routing>::Element
|
||||
/**
|
||||
* Accessors
|
||||
*/
|
||||
uint32_t pin() const { return _pin; }
|
||||
uint32_t gsi() const { return _gsi; }
|
||||
uint32_t pin() const { return _pin; }
|
||||
uint32_t gsi() const { return _gsi; }
|
||||
uint32_t device() const { return _adr >> 16; }
|
||||
|
||||
/* debug */
|
||||
void dump() { if (verbose) PDBG("Pci: adr %x pin %x gsi: %u", _adr, _pin, _gsi); }
|
||||
@ -818,7 +822,6 @@ class Element : public List<Element>::Element
|
||||
}
|
||||
}
|
||||
|
||||
bool is_device() { return _type == SUB_DEVICE; }
|
||||
bool is_device_name() { return _type == DEVICE_NAME; }
|
||||
|
||||
/**
|
||||
@ -852,6 +855,9 @@ class Element : public List<Element>::Element
|
||||
uint32_t size_len() const { return _size_len; }
|
||||
uint8_t const *data() const { return _data; }
|
||||
bool valid() const { return _valid; }
|
||||
uint32_t bdf() const { return _bdf; }
|
||||
bool is_device() const { return _type == SUB_DEVICE; }
|
||||
|
||||
|
||||
static bool supported_acpi_format()
|
||||
{
|
||||
@ -996,44 +1002,6 @@ class Element : public List<Element>::Element
|
||||
}
|
||||
throw -1;
|
||||
}
|
||||
|
||||
static void create_config_file(char * text, size_t max)
|
||||
{
|
||||
Pci_config_space *e = Pci_config_space::list()->first();
|
||||
|
||||
int len = snprintf(text, max, "<config>");
|
||||
text += len;
|
||||
max -= len;
|
||||
for (; e; e = e->next())
|
||||
{
|
||||
using namespace Genode;
|
||||
len = snprintf(text, max, "<bdf><start>%u</start>", e->_bdf_start);
|
||||
text += len;
|
||||
max -= len;
|
||||
len = snprintf(text, max, "<count>%u</count>" , e->_func_count);
|
||||
text += len;
|
||||
max -= len;
|
||||
len = snprintf(text, max, "<base>0x%lx</base></bdf>" , e->_base);
|
||||
text += len;
|
||||
max -= len;
|
||||
}
|
||||
|
||||
Attached_rom_dataspace rom("config");
|
||||
char * rom_text = rom.local_addr<char>();
|
||||
size_t rom_len = strlen(rom_text);
|
||||
|
||||
if (max > rom_len - 9) {
|
||||
rom_text += 9;
|
||||
rom_len -= 9;
|
||||
memcpy(text, rom_text, rom_len);
|
||||
text += rom_len;
|
||||
max -= rom_len;
|
||||
} else
|
||||
PERR("could not add pci_drv policy");
|
||||
|
||||
if (max < 2)
|
||||
PERR("config file could not be generated, buffer to small");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1215,157 +1183,6 @@ class Acpi_table
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pci::Device_client extensions identifies bridges and adds IRQ line re-write
|
||||
*/
|
||||
class Pci_client : public ::Pci::Device_client
|
||||
{
|
||||
public:
|
||||
|
||||
Pci_client(Pci::Device_capability &cap) : ::Pci::Device_client(cap) { }
|
||||
|
||||
/**
|
||||
* Return true if this is a PCI-PCI bridge
|
||||
*/
|
||||
bool is_bridge()
|
||||
{
|
||||
enum { BRIDGE_CLASS = 0x6 };
|
||||
if ((class_code() >> 16) != BRIDGE_CLASS)
|
||||
return false;
|
||||
|
||||
/* see PCI bridge spec (3.2) */
|
||||
enum { BRIDGE = 0x1 };
|
||||
uint16_t header = config_read(0xe, ::Pci::Device::ACCESS_16BIT);
|
||||
|
||||
/* skip multi function flag 0x80) */
|
||||
return ((header & 0x3f) != BRIDGE) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return bus-device function of this device
|
||||
*/
|
||||
uint32_t bdf()
|
||||
{
|
||||
uint8_t bus, dev, func;
|
||||
bus_address(&bus, &dev, &func);
|
||||
return (bus << 8) | ((dev & 0x1f) << 3) | (func & 0x7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IRQ pin
|
||||
*/
|
||||
uint32_t irq_pin()
|
||||
{
|
||||
return ((config_read(0x3c, ::Pci::Device::ACCESS_32BIT) >> 8) & 0xf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return IRQ line
|
||||
*/
|
||||
uint8_t irq_line()
|
||||
{
|
||||
return (config_read(0x3c, ::Pci::Device::ACCESS_8BIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write line to config space
|
||||
*/
|
||||
void irq_line(uint32_t gsi)
|
||||
{
|
||||
config_write(0x3c, gsi, ::Pci::Device::ACCESS_8BIT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List of PCI-bridge devices
|
||||
*/
|
||||
class Pci_bridge : public List<Pci_bridge>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
/* PCI config space fields of bridge */
|
||||
uint32_t _bdf;
|
||||
uint32_t _secondary_bus;
|
||||
uint32_t _subordinate_bus;
|
||||
|
||||
Pci_bridge(Pci_client &client) : _bdf(client.bdf())
|
||||
{
|
||||
/* PCI bridge spec 3.2.5.3, 3.2.5.4 */
|
||||
uint32_t bus = client.config_read(0x18, ::Pci::Device::ACCESS_32BIT);
|
||||
_secondary_bus = (bus >> 8) & 0xff;
|
||||
_subordinate_bus = (bus >> 16) & 0xff;
|
||||
|
||||
if (verbose)
|
||||
PDBG("New bridge: bdf %x se: %u su: %u", _bdf, _secondary_bus, _subordinate_bus);
|
||||
}
|
||||
|
||||
static List<Pci_bridge> *_list()
|
||||
{
|
||||
static List<Pci_bridge> list;
|
||||
return &list;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Scan PCI bus for bridges
|
||||
*/
|
||||
Pci_bridge(Pci::Session_capability &session)
|
||||
{
|
||||
Pci::Session_client pci(session);
|
||||
Pci::Device_capability device_cap = pci.first_device(), prev_device_cap;
|
||||
|
||||
/* search for bridges */
|
||||
while (device_cap.valid()) {
|
||||
prev_device_cap = device_cap;
|
||||
Pci_client device(device_cap);
|
||||
|
||||
if (device.is_bridge())
|
||||
_list()->insert(new (env()->heap()) Pci_bridge(device));
|
||||
|
||||
device_cap = pci.next_device(device_cap);
|
||||
pci.release_device(prev_device_cap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate BDF of bridge belonging to given bdf
|
||||
*/
|
||||
static uint32_t bridge_bdf(uint32_t bdf)
|
||||
{
|
||||
Pci_bridge *bridge = _list()->first();
|
||||
uint32_t bus = bdf >> 8;
|
||||
|
||||
for (; bridge; bridge = bridge->next())
|
||||
if (bridge->_secondary_bus <= bus && bridge->_subordinate_bus >= bus)
|
||||
return bridge->_bdf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Debugging
|
||||
*/
|
||||
static void dump_bdf(uint32_t a, uint32_t b, uint32_t pin)
|
||||
{
|
||||
if (verbose)
|
||||
PDBG("Device bdf %02x:%02x.%u (%x) bridge %02x:%02x.%u (%x) Pin: %u",
|
||||
(a >> 8), (a >> 3) & 0x1f, (a & 0x7), a,
|
||||
(b >> 8), (b >> 3) & 0x1f, (b & 0x7), b, pin);
|
||||
}
|
||||
|
||||
|
||||
static void dump_rewrite(uint32_t bdf, uint8_t line, uint8_t gsi)
|
||||
{
|
||||
PINF("Rewriting %02x:%02x.%u IRQ: %02u -> GSI: %02u",
|
||||
(bdf >> 8), (bdf >> 3) & 0x1f, (bdf & 0x7), line, gsi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse acpi table
|
||||
*/
|
||||
@ -1375,73 +1192,64 @@ static void init_acpi_table()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create config file for pci_drv
|
||||
*/
|
||||
void Acpi::create_pci_config_file(char * config_space,
|
||||
Genode::size_t config_space_max)
|
||||
void Acpi::generate_report()
|
||||
{
|
||||
init_acpi_table();
|
||||
Element::create_config_file(config_space, config_space_max);
|
||||
}
|
||||
|
||||
enum { REPORT_SIZE = 4 * 4096 };
|
||||
static Reporter acpi("acpi", REPORT_SIZE);
|
||||
acpi.enabled(true);
|
||||
|
||||
/**
|
||||
* Rewrite GSIs of PCI config space
|
||||
*/
|
||||
void Acpi::configure_pci_devices(Pci::Session_capability &session)
|
||||
{
|
||||
init_acpi_table();
|
||||
static Pci_bridge bridge(session);
|
||||
Genode::Reporter::Xml_generator xml(acpi, [&] () {
|
||||
for (Pci_config_space *e = Pci_config_space::list()->first(); e;
|
||||
e = e->next())
|
||||
{
|
||||
xml.node("bdf", [&] () {
|
||||
char number[20];
|
||||
Genode::snprintf(number, sizeof(number), "%u", e->_bdf_start);
|
||||
xml.attribute("start", number);
|
||||
Genode::snprintf(number, sizeof(number), "%u", e->_func_count);
|
||||
xml.attribute("count", number);
|
||||
Genode::snprintf(number, sizeof(number), "0x%lx", e->_base);
|
||||
xml.attribute("base", number);
|
||||
});
|
||||
}
|
||||
|
||||
/* if no _PIC method could be found don't rewrite */
|
||||
bool acpi_rewrite = Element::supported_acpi_format();
|
||||
for (Irq_override *i = Irq_override::list()->first(); i; i = i->next())
|
||||
{
|
||||
xml.node("irq_override", [&] () {
|
||||
char number[8];
|
||||
Genode::snprintf(number, sizeof(number), "%u", i->irq());
|
||||
xml.attribute("irq", number);
|
||||
Genode::snprintf(number, sizeof(number), "%u", i->gsi());
|
||||
xml.attribute("gsi", number);
|
||||
Genode::snprintf(number, sizeof(number), "0x%x", i->flags());
|
||||
xml.attribute("flags", number);
|
||||
});
|
||||
}
|
||||
|
||||
if (acpi_rewrite)
|
||||
PINF("ACPI table format is supported - rewrite GSIs");
|
||||
else
|
||||
PWRN("ACPI table format not supported - will not rewrite GSIs");
|
||||
{
|
||||
Element *e = Element::list()->first();
|
||||
|
||||
Pci::Session_client pci(session);
|
||||
Pci::Device_capability device_cap = pci.first_device(), prev_device_cap;
|
||||
for (; e; e = e->next()) {
|
||||
if (!e->is_device())
|
||||
continue;
|
||||
|
||||
while (device_cap.valid()) {
|
||||
prev_device_cap = device_cap;
|
||||
Pci_client device(device_cap);
|
||||
|
||||
/* rewrite IRQs */
|
||||
if (acpi_rewrite && !device.is_bridge()) {
|
||||
uint32_t device_bdf = device.bdf();
|
||||
uint32_t bridge_bdf = Pci_bridge::bridge_bdf(device_bdf);
|
||||
uint32_t irq_pin = device.irq_pin();
|
||||
if (irq_pin) {
|
||||
dump_bdf(device_bdf, bridge_bdf, irq_pin - 1);
|
||||
try {
|
||||
uint8_t gsi = Element::search_gsi(device_bdf, bridge_bdf, irq_pin - 1);
|
||||
dump_rewrite(device_bdf, device.irq_line(), gsi);
|
||||
device.irq_line(gsi);
|
||||
} catch (...) { }
|
||||
Pci_routing *r = e->pci_list()->first();
|
||||
for (; r; r = r->next()) {
|
||||
xml.node("routing", [&] () {
|
||||
char number[8];
|
||||
Genode::snprintf(number, sizeof(number), "0x%x", r->gsi());
|
||||
xml.attribute("gsi", number);
|
||||
Genode::snprintf(number, sizeof(number), "0x%x", e->bdf());
|
||||
xml.attribute("bridge_bdf", number);
|
||||
Genode::snprintf(number, sizeof(number), "0x%x", r->device());
|
||||
xml.attribute("device", number);
|
||||
Genode::snprintf(number, sizeof(number), "0x%x", r->pin());
|
||||
xml.attribute("device_pin", number);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_cap = pci.next_device(device_cap);
|
||||
pci.release_device(prev_device_cap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search override structures
|
||||
*/
|
||||
unsigned Acpi::override(unsigned irq, unsigned *mode)
|
||||
{
|
||||
for (Irq_override *i = Irq_override::list()->first(); i; i = i->next())
|
||||
if (i->match(irq)) {
|
||||
*mode = i->flags();
|
||||
return i->gsi();
|
||||
}
|
||||
|
||||
*mode = 0;
|
||||
return irq;
|
||||
});
|
||||
}
|
||||
|
@ -14,26 +14,12 @@
|
||||
#ifndef _ACPI_H_
|
||||
#define _ACPI_H_
|
||||
|
||||
#include <pci_session/capability.h>
|
||||
|
||||
namespace Acpi
|
||||
{
|
||||
/**
|
||||
* Generate config file for pci_drv containing pointers to the
|
||||
* extended PCI config space (since PCI Express)
|
||||
* Generate report rom
|
||||
*/
|
||||
void create_pci_config_file(char * config_space,
|
||||
Genode::size_t config_space_max);
|
||||
|
||||
/**
|
||||
* Rewrite PCI-config space with GSIs found in ACPI tables.
|
||||
*/
|
||||
void configure_pci_devices(Pci::Session_capability &session);
|
||||
|
||||
/**
|
||||
* Return override GSI for IRQ
|
||||
*/
|
||||
unsigned override(unsigned irq, unsigned *mode);
|
||||
void generate_report();
|
||||
}
|
||||
|
||||
#endif /* _ACPI_H_ */
|
||||
|
@ -2,321 +2,36 @@
|
||||
* \brief Service and session interface
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-02-25
|
||||
*
|
||||
* The 'acpi_drv' provides the 'PCI' after rewriting the IRQ information of PCI
|
||||
* devices. For this it uses the 'pci_drv' as a client and forwards the session
|
||||
* capability of the 'pci_drv' afterwards
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
||||
* Copyright (C) 2009-2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <os/slave.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <pci_session/client.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <root/component.h>
|
||||
|
||||
#include <os/reporter.h>
|
||||
|
||||
#include "acpi.h"
|
||||
|
||||
/**
|
||||
* IRQ service
|
||||
*/
|
||||
namespace Irq {
|
||||
|
||||
typedef Genode::Rpc_object<Genode::Typed_root<Genode::Irq_session> > Irq_session;
|
||||
|
||||
/**
|
||||
* Root interface of IRQ service
|
||||
*/
|
||||
class Root : public Irq_session
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Irq_session::Trigger _mode2trigger(unsigned mode)
|
||||
{
|
||||
enum { EDGE = 0x4, LEVEL = 0xc };
|
||||
|
||||
switch (mode & 0xc) {
|
||||
case EDGE:
|
||||
return Genode::Irq_session::TRIGGER_EDGE;
|
||||
case LEVEL:
|
||||
return Genode::Irq_session::TRIGGER_LEVEL;
|
||||
default:
|
||||
return Genode::Irq_session::TRIGGER_UNCHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Irq_session::Polarity _mode2polarity(unsigned mode)
|
||||
{
|
||||
using namespace Genode;
|
||||
enum { HIGH = 0x1, LOW = 0x3 };
|
||||
|
||||
switch (mode & 0x3) {
|
||||
case HIGH:
|
||||
return Genode::Irq_session::POLARITY_HIGH;
|
||||
case LOW:
|
||||
return Genode::Irq_session::POLARITY_LOW;
|
||||
default:
|
||||
return Genode::Irq_session::POLARITY_UNCHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Remap IRQ number and create IRQ session at parent
|
||||
*/
|
||||
Genode::Session_capability session(Root::Session_args const &args,
|
||||
Genode::Affinity const &)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!args.is_valid_string()) throw Root::Invalid_args();
|
||||
|
||||
long irq_number = Arg_string::find_arg(args.string(), "irq_number").long_value(-1);
|
||||
long msi = Arg_string::find_arg(args.string(), "device_config_phys").long_value(0);
|
||||
|
||||
/* check for 'MADT' overrides */
|
||||
unsigned mode;
|
||||
long irq_legacy = Acpi::override(irq_number, &mode);
|
||||
/* rewrite IRQ solely if this is not a MSI request */
|
||||
if (!msi)
|
||||
irq_number = irq_legacy;
|
||||
|
||||
/* allocate IRQ at parent*/
|
||||
try {
|
||||
Irq_connection irq(irq_number, _mode2trigger(mode),
|
||||
_mode2polarity(mode), msi);
|
||||
irq.on_destruction(Irq_connection::KEEP_OPEN);
|
||||
return irq.cap();
|
||||
} catch (...) { throw Root::Unavailable(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session at parent
|
||||
*/
|
||||
void close(Genode::Session_capability session) {
|
||||
Genode::env()->parent()->close(session); }
|
||||
|
||||
void upgrade(Genode::Session_capability session, Upgrade_args const &args) { }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace Pci {
|
||||
|
||||
struct Provider
|
||||
{
|
||||
bool ready_to_use() { return root().valid(); }
|
||||
|
||||
virtual Genode::Root_capability root() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Root interface of PCI service
|
||||
*/
|
||||
class Root : public Genode::Rpc_object<Genode::Typed_root<Pci::Session> >
|
||||
{
|
||||
private:
|
||||
|
||||
Provider &_pci_provider;
|
||||
Genode::Ram_session_capability _slave_ram_cap;
|
||||
|
||||
public:
|
||||
|
||||
Root(Provider &pci_provider,
|
||||
Genode::Ram_session_capability ram_cap)
|
||||
: _pci_provider(pci_provider), _slave_ram_cap(ram_cap) { }
|
||||
|
||||
Genode::Session_capability session(Session_args const &args,
|
||||
Genode::Affinity const &affinity)
|
||||
{
|
||||
if (!args.is_valid_string()) throw Invalid_args();
|
||||
|
||||
if (!_pci_provider.ready_to_use())
|
||||
throw Unavailable();
|
||||
|
||||
try {
|
||||
return Genode::Root_client(_pci_provider.root())
|
||||
.session(args.string(), affinity);
|
||||
} catch (...) {
|
||||
throw Unavailable();
|
||||
}
|
||||
}
|
||||
|
||||
void close(Genode::Session_capability session) {
|
||||
Genode::Root_client(_pci_provider.root()).close(session); }
|
||||
|
||||
void upgrade(Genode::Session_capability s,
|
||||
Upgrade_args const & args)
|
||||
{
|
||||
if (!s.valid() || !args.is_valid_string() ||
|
||||
!_slave_ram_cap.valid())
|
||||
throw Invalid_args();
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
|
||||
Ram_session_client acpi_ram(env()->ram_session_cap());
|
||||
if (acpi_ram.transfer_quota(_slave_ram_cap, ram_quota))
|
||||
throw Invalid_args();
|
||||
|
||||
try { Root_client(_pci_provider.root()).upgrade(s, args); }
|
||||
catch (...) {
|
||||
PDBG("notification about upgrade failed");
|
||||
throw Invalid_args();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static Irq::Root irq_root;
|
||||
static Genode::Local_service local_irq("IRQ", &irq_root);
|
||||
|
||||
|
||||
class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Root_capability _cap;
|
||||
Genode::Rpc_entrypoint &_pci_ep;
|
||||
Genode::Rpc_entrypoint &_irq_ep;
|
||||
Genode::Lock _lock;
|
||||
|
||||
protected:
|
||||
|
||||
Genode::Service *resolve_session_request(const char *service_name,
|
||||
const char *args) override
|
||||
{
|
||||
if (!Genode::strcmp(service_name, "IRQ"))
|
||||
return &local_irq;
|
||||
|
||||
return Genode::Slave_policy::resolve_session_request(service_name,
|
||||
args);
|
||||
}
|
||||
|
||||
char const **_permitted_services() const
|
||||
{
|
||||
static char const *permitted_services[] = { "CPU", "CAP", "RM",
|
||||
"LOG", "IO_PORT", "PD",
|
||||
"ROM", "RAM", "SIGNAL",
|
||||
"IO_MEM", 0 };
|
||||
return permitted_services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse ACPI tables and announce slave PCI service
|
||||
*/
|
||||
void _acpi_session(Genode::Ram_session_capability ram_cap)
|
||||
{
|
||||
Pci::Session_capability session;
|
||||
const char *args = "label=\"acpi_drv\", ram_quota=16K";
|
||||
|
||||
try {
|
||||
using namespace Genode;
|
||||
session = static_cap_cast<Pci::Session>(Root_client(_cap)
|
||||
.session(args, Genode::Affinity()));
|
||||
} catch (...) { return; }
|
||||
|
||||
Acpi::configure_pci_devices(session);
|
||||
|
||||
/* announce PCI/IRQ services to parent */
|
||||
static Pci::Root pci_root(*this, ram_cap);
|
||||
|
||||
Genode::env()->parent()->announce(_pci_ep.manage(&pci_root));
|
||||
Genode::env()->parent()->announce(_irq_ep.manage(&irq_root));
|
||||
|
||||
Genode::Root_client(_cap).close(session);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Pci_policy(Genode::Rpc_entrypoint &slave_ep,
|
||||
Genode::Rpc_entrypoint &pci_ep,
|
||||
Genode::Rpc_entrypoint &irq_ep)
|
||||
:
|
||||
Slave_policy("pci_drv", slave_ep, Genode::env()->ram_session()),
|
||||
_pci_ep(pci_ep), _irq_ep(irq_ep), _lock(Genode::Lock::LOCKED)
|
||||
{ }
|
||||
|
||||
bool announce_service(const char *service_name,
|
||||
Genode::Root_capability root,
|
||||
Genode::Allocator *alloc,
|
||||
Genode::Server *server)
|
||||
{
|
||||
/* wait for 'pci_drv' to announce the PCI service */
|
||||
if (Genode::strcmp(service_name, "PCI"))
|
||||
return false;
|
||||
|
||||
_cap = root;
|
||||
|
||||
/* unblock main thread blocked in wait_for_pci_drv */
|
||||
_lock.unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wait_for_pci_drv(Genode::Ram_session_capability slave_ram_cap)
|
||||
{
|
||||
/* wait until pci drv is ready */
|
||||
_lock.lock();
|
||||
|
||||
/* connect session and start ACPI parsing */
|
||||
_acpi_session(slave_ram_cap);
|
||||
}
|
||||
|
||||
Genode::Root_capability root() { return _cap; }
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
enum { STACK_SIZE = 2*4096, ACPI_MEMORY_SIZE = 2 * 1024 * 1024 };
|
||||
|
||||
/* reserve portion for acpi and give rest to pci_drv */
|
||||
Genode::addr_t avail_size = Genode::env()->ram_session()->avail();
|
||||
if (avail_size < ACPI_MEMORY_SIZE) {
|
||||
PERR("not enough memory");
|
||||
return 1;
|
||||
try {
|
||||
Acpi::generate_report();
|
||||
} catch (Genode::Xml_generator::Buffer_exceeded) {
|
||||
PERR("ACPI report too large - failure");
|
||||
throw;
|
||||
} catch (...) {
|
||||
PERR("Unknown exception occured - failure");
|
||||
throw;
|
||||
}
|
||||
avail_size -= ACPI_MEMORY_SIZE;
|
||||
PINF("available memory for ACPI %d kiB, for PCI_DRV %lu kiB",
|
||||
ACPI_MEMORY_SIZE / 1024, avail_size / 1024);
|
||||
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "acpi_ep");
|
||||
|
||||
/* IRQ service */
|
||||
static Cap_connection irq_cap;
|
||||
static Rpc_entrypoint irq_ep(&irq_cap, STACK_SIZE, "acpi_irq_ep");
|
||||
|
||||
/* use 'pci_drv' as slave service */
|
||||
static Rpc_entrypoint pci_ep(&cap, STACK_SIZE, "pci_slave");
|
||||
static Pci_policy pci_policy(pci_ep, ep, irq_ep);
|
||||
|
||||
/* generate config file for pci_drv */
|
||||
char buf[1024];
|
||||
Acpi::create_pci_config_file(buf, sizeof(buf));
|
||||
pci_policy.configure(buf);
|
||||
|
||||
/* use 'pci_drv' as slave service */
|
||||
static Genode::Slave pci_slave(pci_ep, pci_policy, avail_size);
|
||||
|
||||
/* wait until pci drv is online and then make the acpi work */
|
||||
pci_policy.wait_for_pci_drv(pci_slave.ram().cap());
|
||||
|
||||
Genode::sleep_forever();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
/* PCI driver include */
|
||||
#include "irq.h"
|
||||
#include "pci_session_component.h"
|
||||
|
||||
|
||||
namespace Pci {
|
||||
@ -194,10 +195,13 @@ class Pci::Irq_component : public Proxy
|
||||
|
||||
public:
|
||||
|
||||
Irq_component(unsigned gsi)
|
||||
Irq_component(unsigned gsi, Genode::Irq_session::Trigger trigger,
|
||||
Genode::Irq_session::Polarity polarity)
|
||||
:
|
||||
Proxy(gsi), _irq(gsi), _irq_dispatcher(irq_thread.sig_rec(), *this,
|
||||
&::Proxy::notify_about_irq),
|
||||
Proxy(gsi),
|
||||
_irq(gsi, trigger, polarity),
|
||||
_irq_dispatcher(irq_thread.sig_rec(), *this,
|
||||
&::Proxy::notify_about_irq),
|
||||
_associated(false)
|
||||
{ }
|
||||
};
|
||||
@ -234,7 +238,7 @@ Pci::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
_gsi(irq)
|
||||
{
|
||||
/* invalid irq number for pci_devices */
|
||||
if (irq >= INVALID_IRQ)
|
||||
if (_gsi >= INVALID_IRQ)
|
||||
return;
|
||||
|
||||
if (pci_config_space != ~0UL) {
|
||||
@ -262,9 +266,20 @@ Pci::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Irq_session::Trigger trigger;
|
||||
Genode::Irq_session::Polarity polarity;
|
||||
|
||||
_gsi = Pci::Irq_override::irq_override(_gsi, trigger, polarity);
|
||||
if (_gsi != irq || trigger != Genode::Irq_session::TRIGGER_UNCHANGED ||
|
||||
polarity != Genode::Irq_session::POLARITY_UNCHANGED)
|
||||
PINF("IRQ override %u->%u trigger mode=%s polarity=%s", irq, _gsi,
|
||||
trigger == Genode::Irq_session::TRIGGER_LEVEL ? "LEVEL" : trigger == Genode::Irq_session::TRIGGER_EDGE ? "EDGE" : "UNCHANGED",
|
||||
polarity == Genode::Irq_session::POLARITY_HIGH ? "HIGH" : polarity == Genode::Irq_session::POLARITY_LOW ? "LOW" : "UNCHANGED");
|
||||
|
||||
try {
|
||||
/* check if shared IRQ object was used before */
|
||||
if (Proxy::get_irq_proxy<Irq_component>(_gsi, &irq_alloc))
|
||||
if (Proxy::get_irq_proxy<Irq_component>(_gsi, &irq_alloc, trigger,
|
||||
polarity))
|
||||
return;
|
||||
} catch (Genode::Parent::Service_denied) { }
|
||||
|
||||
@ -319,3 +334,15 @@ void Pci::Irq_session_component::sigh(Genode::Signal_context_capability sigh)
|
||||
if (!old.valid() && sigh.valid())
|
||||
irq_obj->add_sharer(&_irq_sigh);
|
||||
}
|
||||
|
||||
|
||||
unsigned short Pci::Irq_routing::rewrite(unsigned char bus, unsigned char dev,
|
||||
unsigned char func, unsigned char pin)
|
||||
{
|
||||
for (Irq_routing *i = list()->first(); i; i = i->next())
|
||||
if ((dev == i->_device) && (pin - 1 == i->_device_pin) &&
|
||||
(i->_bridge_bdf == Pci::bridge_bdf(bus)))
|
||||
return i->_gsi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,7 +24,11 @@
|
||||
#include <platform/irq_proxy.h>
|
||||
|
||||
|
||||
namespace Pci { class Irq_session_component; }
|
||||
namespace Pci {
|
||||
class Irq_session_component;
|
||||
class Irq_override;
|
||||
class Irq_routing;
|
||||
}
|
||||
|
||||
|
||||
class Pci::Irq_session_component : public Genode::Rpc_object<Genode::Irq_session>,
|
||||
@ -64,3 +68,113 @@ class Pci::Irq_session_component : public Genode::Rpc_object<Genode::Irq_session
|
||||
Info info() override {
|
||||
return { .type = Genode::Irq_session::Info::Type::INVALID }; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List that holds interrupt override information
|
||||
*/
|
||||
class Pci::Irq_override : public Genode::List<Pci::Irq_override>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
unsigned short _irq; /* source IRQ */
|
||||
unsigned short _gsi; /* target GSI */
|
||||
Genode::Irq_session::Trigger _trigger; /* interrupt trigger mode */
|
||||
Genode::Irq_session::Polarity _polarity; /* interrupt polarity */
|
||||
|
||||
Genode::Irq_session::Trigger _mode2trigger(unsigned mode)
|
||||
{
|
||||
enum { EDGE = 0x4, LEVEL = 0xc };
|
||||
|
||||
switch (mode & 0xc) {
|
||||
case EDGE:
|
||||
return Genode::Irq_session::TRIGGER_EDGE;
|
||||
case LEVEL:
|
||||
return Genode::Irq_session::TRIGGER_LEVEL;
|
||||
default:
|
||||
return Genode::Irq_session::TRIGGER_UNCHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Irq_session::Polarity _mode2polarity(unsigned mode)
|
||||
{
|
||||
using namespace Genode;
|
||||
enum { HIGH = 0x1, LOW = 0x3 };
|
||||
|
||||
switch (mode & 0x3) {
|
||||
case HIGH:
|
||||
return Genode::Irq_session::POLARITY_HIGH;
|
||||
case LOW:
|
||||
return Genode::Irq_session::POLARITY_LOW;
|
||||
default:
|
||||
return Genode::Irq_session::POLARITY_UNCHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Irq_override(unsigned irq, unsigned gsi, unsigned mode)
|
||||
:
|
||||
_irq(irq), _gsi(gsi),
|
||||
_trigger(_mode2trigger(mode)), _polarity(_mode2polarity(mode))
|
||||
{ }
|
||||
|
||||
static Genode::List<Irq_override> *list()
|
||||
{
|
||||
static Genode::List<Irq_override> _list;
|
||||
return &_list;
|
||||
}
|
||||
|
||||
unsigned short irq() const { return _irq; }
|
||||
unsigned short gsi() const { return _gsi; }
|
||||
Genode::Irq_session::Trigger trigger() const { return _trigger; }
|
||||
Genode::Irq_session::Polarity polarity() const { return _polarity; }
|
||||
|
||||
static unsigned irq_override (unsigned irq,
|
||||
Genode::Irq_session::Trigger &trigger,
|
||||
Genode::Irq_session::Polarity &polarity)
|
||||
{
|
||||
for (Irq_override *i = list()->first(); i; i = i->next())
|
||||
if (i->irq() == irq) {
|
||||
trigger = i->trigger();
|
||||
polarity = i->polarity();
|
||||
return i->gsi();
|
||||
}
|
||||
|
||||
trigger = Genode::Irq_session::TRIGGER_UNCHANGED;
|
||||
polarity = Genode::Irq_session::POLARITY_UNCHANGED;
|
||||
return irq;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List that holds interrupt rewrite information
|
||||
*/
|
||||
class Pci::Irq_routing : public Genode::List<Pci::Irq_routing>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
unsigned short _gsi;
|
||||
unsigned short _bridge_bdf;
|
||||
unsigned short _device;
|
||||
unsigned char _device_pin;
|
||||
|
||||
public:
|
||||
|
||||
static Genode::List<Irq_routing> *list()
|
||||
{
|
||||
static Genode::List<Irq_routing> _list;
|
||||
return &_list;
|
||||
}
|
||||
|
||||
Irq_routing(unsigned short gsi, unsigned short bridge_bdf,
|
||||
unsigned char device, unsigned char device_pin)
|
||||
:
|
||||
_gsi(gsi), _bridge_bdf(bridge_bdf), _device(device),
|
||||
_device_pin(device_pin)
|
||||
{ }
|
||||
|
||||
static unsigned short rewrite(unsigned char bus, unsigned char dev,
|
||||
unsigned char func, unsigned char pin);
|
||||
};
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <cap_session/connection.h>
|
||||
|
||||
#include <os/slave.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
|
||||
#include "pci_session_component.h"
|
||||
#include "pci_device_config.h"
|
||||
@ -106,14 +107,44 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
|
||||
|
||||
|
||||
/**
|
||||
* If we are running with ACPI support, wait for the first report_rom
|
||||
*/
|
||||
bool wait_for_acpi = true;
|
||||
char * report_addr = nullptr;
|
||||
|
||||
try {
|
||||
char yesno[4];
|
||||
Genode::config()->xml_node().attribute("acpi").value(yesno, sizeof(yesno));
|
||||
wait_for_acpi = strcmp(yesno, "no");
|
||||
} catch (...) { }
|
||||
|
||||
if (wait_for_acpi) {
|
||||
static Attached_rom_dataspace acpi_rom("acpi");
|
||||
|
||||
Signal_receiver sig_rec;
|
||||
Signal_context sig_ctx;
|
||||
Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
|
||||
|
||||
acpi_rom.sigh(sig_cap);
|
||||
|
||||
while (!acpi_rom.is_valid()) {
|
||||
sig_rec.wait_for_signal();
|
||||
acpi_rom.update();
|
||||
}
|
||||
report_addr = acpi_rom.local_addr<char>();
|
||||
sig_rec.dissolve(&sig_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Let the entry point serve the PCI root interface
|
||||
*/
|
||||
static Pci::Root root(&ep, &sliced_heap, PCI_DEVICE_PD_RAM_QUOTA,
|
||||
device_pd_root);
|
||||
device_pd_root, report_addr);
|
||||
|
||||
env()->parent()->announce(ep.manage(&root));
|
||||
|
||||
sleep_forever();
|
||||
Genode::sleep_forever();
|
||||
return 0;
|
||||
}
|
||||
|
56
repos/os/src/drivers/pci/pci_bridge.h
Normal file
56
repos/os/src/drivers/pci/pci_bridge.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief PCI bridge discovery
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-02-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Pci { class Bridge; }
|
||||
|
||||
#include <util/list.h>
|
||||
|
||||
|
||||
/**
|
||||
* List of PCI-bridge devices
|
||||
*/
|
||||
class Pci::Bridge : public Genode::List<Bridge>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
/* PCI config space fields of bridge */
|
||||
unsigned char _bus;
|
||||
unsigned char _dev;
|
||||
unsigned char _fun;
|
||||
|
||||
unsigned char _secondary_bus;
|
||||
unsigned char _subordinate_bus;
|
||||
|
||||
public:
|
||||
|
||||
Bridge(unsigned char bus, unsigned char dev, unsigned char fun,
|
||||
unsigned char secondary_bus, unsigned char subordinate_bus)
|
||||
:
|
||||
_bus(bus), _dev(dev), _fun(fun), _secondary_bus(secondary_bus),
|
||||
_subordinate_bus(subordinate_bus)
|
||||
{ }
|
||||
|
||||
bool part_of (unsigned char bus) const
|
||||
{
|
||||
return _secondary_bus <= bus && bus <= _subordinate_bus;
|
||||
}
|
||||
|
||||
unsigned short bdf()
|
||||
{
|
||||
unsigned short bdf = _bus;
|
||||
bdf = (bdf << 8) | ((_dev & 0x1f) << 3) | (_fun & 0x7);
|
||||
return bdf;
|
||||
}
|
||||
};
|
@ -83,11 +83,6 @@ void Pci::Device_component::config_write(unsigned char address, unsigned value,
|
||||
case 0xd: /* Latency timer */
|
||||
if (size == Access_size::ACCESS_8BIT)
|
||||
break;
|
||||
case PCI_IRQ_LINE:
|
||||
/* permitted up to now solely for acpi driver */
|
||||
if (address == PCI_IRQ_LINE && _rewrite_irq_line &&
|
||||
size == Access_size::ACCESS_8BIT)
|
||||
break;
|
||||
default:
|
||||
PWRN("%x:%x:%x write access to address=%x value=0x%x "
|
||||
" size=0x%x got dropped", _device_config.bus_number(),
|
||||
|
@ -42,7 +42,6 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
Pci::Session_component *_session;
|
||||
unsigned short _irq_line;
|
||||
Irq_session_component _irq_session;
|
||||
bool _rewrite_irq_line;
|
||||
|
||||
enum {
|
||||
IO_BLOCK_SIZE = sizeof(Genode::Io_port_connection) *
|
||||
@ -107,16 +106,34 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
/**
|
||||
* Disable MSI if already enabled.
|
||||
*/
|
||||
unsigned _disable_msi(unsigned irq)
|
||||
unsigned _configure_irq(unsigned irq)
|
||||
{
|
||||
using Genode::uint16_t;
|
||||
using Genode::uint8_t;
|
||||
|
||||
uint8_t has_irq = _device_config.read(&_config_access, PCI_IRQ_PIN,
|
||||
Pci::Device::ACCESS_8BIT);
|
||||
if (!has_irq)
|
||||
uint8_t pin = _device_config.read(&_config_access, PCI_IRQ_PIN,
|
||||
Pci::Device::ACCESS_8BIT);
|
||||
if (!pin)
|
||||
return Irq_session_component::INVALID_IRQ;
|
||||
|
||||
/* lookup rewrite information as provided by acpi table */
|
||||
uint16_t irq_r = Irq_routing::rewrite(_device_config.bus_number(),
|
||||
_device_config.device_number(),
|
||||
_device_config.function_number(),
|
||||
pin);
|
||||
if (irq_r) {
|
||||
PINF("%x:%x.%x rewriting IRQ: %u -> %u",
|
||||
_device_config.bus_number(),
|
||||
_device_config.device_number(),
|
||||
_device_config.function_number(), irq, irq_r);
|
||||
|
||||
if (_irq_line != irq_r)
|
||||
_device_config.write(&_config_access, PCI_IRQ_LINE, irq_r,
|
||||
Pci::Device::ACCESS_8BIT);
|
||||
|
||||
_irq_line = irq = irq_r;
|
||||
}
|
||||
|
||||
uint16_t cap = _msi_cap();
|
||||
if (!cap)
|
||||
return irq;
|
||||
@ -163,14 +180,13 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
Device_component(Device_config device_config, Genode::addr_t addr,
|
||||
Genode::Rpc_entrypoint *ep,
|
||||
Pci::Session_component * session,
|
||||
bool rewrite_irq_line, bool use_msi)
|
||||
bool use_msi)
|
||||
:
|
||||
_device_config(device_config), _config_space(addr),
|
||||
_ep(ep), _session(session),
|
||||
_irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE,
|
||||
Pci::Device::ACCESS_8BIT)),
|
||||
_irq_session(_disable_msi(_irq_line), (!use_msi || !_msi_cap()) ? ~0UL : _config_space),
|
||||
_rewrite_irq_line(rewrite_irq_line),
|
||||
_irq_session(_configure_irq(_irq_line), (!use_msi || !_msi_cap()) ? ~0UL : _config_space),
|
||||
_slab_ioport(0, &_slab_ioport_block),
|
||||
_slab_iomem(0, &_slab_iomem_block)
|
||||
{
|
||||
@ -350,10 +366,12 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
msi_64 ? "64bit" : "32bit",
|
||||
_irq_session.msi_data(), _irq_session.msi_address());
|
||||
else
|
||||
PINF("%x:%x.%x uses IRQ, vector 0x%x",
|
||||
PINF("%x:%x.%x uses IRQ, vector 0x%x%s",
|
||||
_device_config.bus_number(),
|
||||
_device_config.device_number(),
|
||||
_device_config.function_number(), _irq_line);
|
||||
_device_config.function_number(), _irq_line,
|
||||
msi_cap ? (msi_64 ? ", MSI 64bit capable" :
|
||||
", MSI 32bit capable") : "");
|
||||
|
||||
return _irq_session.cap();
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
/* os */
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <pci_session/pci_session.h>
|
||||
|
||||
@ -36,6 +35,7 @@
|
||||
|
||||
namespace Pci {
|
||||
bool bus_valid(int bus = 0);
|
||||
unsigned short bridge_bdf(unsigned char bus);
|
||||
}
|
||||
|
||||
namespace Pci {
|
||||
@ -59,6 +59,7 @@ namespace Pci {
|
||||
|
||||
static Genode::Bit_array<MAX_PCI_DEVICES> bdf_in_use;
|
||||
|
||||
|
||||
/**
|
||||
* Scan PCI buses for a device
|
||||
*
|
||||
@ -530,8 +531,7 @@ namespace Pci {
|
||||
* device and return its capability.
|
||||
*/
|
||||
try {
|
||||
Device_component * dev = new (_device_slab) Device_component(config, config_space, _ep, this,
|
||||
!Genode::strcmp(_label.string(), "acpi_drv"), msi_usage());
|
||||
Device_component * dev = new (_device_slab) Device_component(config, config_space, _ep, this, msi_usage());
|
||||
|
||||
/* if more than one driver uses the device - warn about */
|
||||
if (bdf_in_use.get(Device_config::MAX_BUSES * bus +
|
||||
@ -658,35 +658,62 @@ namespace Pci {
|
||||
/* Ram_session for allocation of dma capable dataspaces */
|
||||
Genode::Ram_connection _ram;
|
||||
|
||||
void _parse_config()
|
||||
void _parse_report_rom(const char * acpi_rom)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* check for config file first */
|
||||
try { config(); } catch (...) { return; }
|
||||
|
||||
try {
|
||||
Xml_node xml_acpi(acpi_rom);
|
||||
if (!xml_acpi.has_type("acpi"))
|
||||
throw 1;
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < config()->xml_node().num_sub_nodes(); i++)
|
||||
for (i = 0; i < xml_acpi.num_sub_nodes(); i++)
|
||||
{
|
||||
Xml_node node = config()->xml_node().sub_node(i);
|
||||
Xml_node node = xml_acpi.sub_node(i);
|
||||
|
||||
if (!node.has_type("bdf"))
|
||||
continue;
|
||||
if (node.has_type("bdf")) {
|
||||
|
||||
uint32_t bdf_start = 0;
|
||||
uint32_t func_count = 0;
|
||||
addr_t base = 0;
|
||||
node.sub_node("start").value(&bdf_start);
|
||||
node.sub_node("count").value(&func_count);
|
||||
node.sub_node("base").value(&base);
|
||||
uint32_t bdf_start = 0;
|
||||
uint32_t func_count = 0;
|
||||
addr_t base = 0;
|
||||
|
||||
PINF("%2u BDF start %x, functions: 0x%x, physical base "
|
||||
"0x%lx", i, bdf_start, func_count, base);
|
||||
node.attribute("start").value(&bdf_start);
|
||||
node.attribute("count").value(&func_count);
|
||||
node.attribute("base").value(&base);
|
||||
|
||||
Session_component::add_config_space(bdf_start,
|
||||
func_count, base);
|
||||
Session_component::add_config_space(bdf_start,
|
||||
func_count,
|
||||
base);
|
||||
}
|
||||
|
||||
if (node.has_type("irq_override")) {
|
||||
unsigned irq = 0xff;
|
||||
unsigned gsi = 0xff;
|
||||
unsigned flags = 0xff;
|
||||
|
||||
node.attribute("irq").value(&irq);
|
||||
node.attribute("gsi").value(&gsi);
|
||||
node.attribute("flags").value(&flags);
|
||||
|
||||
using Pci::Irq_override;
|
||||
Irq_override::list()->insert(new (env()->heap()) Irq_override(irq, gsi, flags));
|
||||
}
|
||||
|
||||
if (node.has_type("routing")) {
|
||||
unsigned gsi;
|
||||
unsigned bridge_bdf;
|
||||
unsigned device;
|
||||
unsigned device_pin;
|
||||
|
||||
node.attribute("gsi").value(&gsi);
|
||||
node.attribute("bridge_bdf").value(&bridge_bdf);
|
||||
node.attribute("device").value(&device);
|
||||
node.attribute("device_pin").value(&device_pin);
|
||||
|
||||
Irq_routing::list()->insert(new (env()->heap()) Irq_routing(gsi, bridge_bdf, device, device_pin));
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
PERR("PCI config space data could not be parsed.");
|
||||
@ -728,7 +755,8 @@ namespace Pci {
|
||||
*/
|
||||
Root(Genode::Rpc_entrypoint *ep, Genode::Allocator *md_alloc,
|
||||
Genode::size_t pci_device_pd_ram_quota,
|
||||
Genode::Root_capability &device_pd_root)
|
||||
Genode::Root_capability &device_pd_root,
|
||||
const char *acpi_rom)
|
||||
:
|
||||
Genode::Root_component<Session_component>(ep, md_alloc),
|
||||
_device_pd_root(device_pd_root),
|
||||
@ -736,14 +764,15 @@ namespace Pci {
|
||||
_ram("dma", 0, (device_pd_root.valid() && sizeof(void *) == 4) ?
|
||||
0xc0000000UL : 0x100000000ULL)
|
||||
{
|
||||
_parse_config();
|
||||
/* enforce initial bus scan */
|
||||
bus_valid();
|
||||
|
||||
if (acpi_rom)
|
||||
_parse_report_rom(acpi_rom);
|
||||
|
||||
/* associate _ram session with ram_session of process */
|
||||
_ram.ref_account(Genode::env()->ram_session_cap());
|
||||
Genode::env()->ram_session()->transfer_quota(_ram.cap(), 0x1000);
|
||||
|
||||
/* enforce initial bus scan */
|
||||
bus_valid();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,27 @@
|
||||
*/
|
||||
|
||||
#include "pci_session_component.h"
|
||||
#include "pci_bridge.h"
|
||||
|
||||
|
||||
static Genode::List<Pci::Bridge> *bridges()
|
||||
{
|
||||
static Genode::List<Pci::Bridge> list;
|
||||
return &list;
|
||||
}
|
||||
|
||||
|
||||
unsigned short Pci::bridge_bdf(unsigned char bus)
|
||||
{
|
||||
for (Pci::Bridge *bridge = bridges()->first(); bridge;
|
||||
bridge = bridge->next())
|
||||
{
|
||||
if (bridge->part_of(bus))
|
||||
return bridge->bdf();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if given PCI bus was found on initial scan
|
||||
@ -24,7 +45,7 @@ bool Pci::bus_valid(int bus)
|
||||
{
|
||||
bool valid[Device_config::MAX_BUSES];
|
||||
|
||||
void scan_bus(Config_access &config_access, int bus = 0)
|
||||
void scan_bus(Config_access &config_access, unsigned char bus = 0)
|
||||
{
|
||||
for (int dev = 0; dev < Device_config::MAX_DEVICES; ++dev) {
|
||||
for (int fun = 0; fun < Device_config::MAX_FUNCTIONS; ++fun) {
|
||||
@ -43,9 +64,15 @@ bool Pci::bus_valid(int bus)
|
||||
|
||||
/* scan behind bridge */
|
||||
if (config.is_pci_bridge()) {
|
||||
int sub_bus = config.read(&config_access,
|
||||
/* PCI bridge spec 3.2.5.3, 3.2.5.4 */
|
||||
unsigned char sec_bus = config.read(&config_access,
|
||||
0x19, Device::ACCESS_8BIT);
|
||||
scan_bus(config_access, sub_bus);
|
||||
unsigned char sub_bus = config.read(&config_access,
|
||||
0x20, Device::ACCESS_8BIT);
|
||||
|
||||
bridges()->insert(new (Genode::env()->heap()) Bridge(bus, dev, fun, sec_bus, sub_bus));
|
||||
|
||||
scan_bus(config_access, sec_bus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ append_if $use_wifi_driver config {
|
||||
<service name="Rtc"> <any-child/> </service>
|
||||
<service name="File_system"> <child name="config_fs"/> </service>
|
||||
<service name="ROM"> <if-arg key="label" value="wlan_configuration" /> <child name="config_rom" /> </service>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>}
|
||||
|
@ -57,7 +57,7 @@ append config {
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <any-child/> <parent/> </any-service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
@ -67,7 +67,10 @@ append config {
|
||||
append_if [have_include "power_on/qemu"] config {
|
||||
<start name="uart_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Terminal"/></provides>
|
||||
<provides>
|
||||
<service name="Terminal"/>
|
||||
<service name="Uart"/>
|
||||
</provides>
|
||||
<config>
|
||||
<policy label="noux" uart="1"/>
|
||||
</config>
|
||||
|
@ -107,7 +107,7 @@ append config {
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <any-child/> <parent/> </any-service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
|
@ -214,7 +214,8 @@ append config_of_app {
|
||||
</vfs>
|
||||
</libc>
|
||||
</config>
|
||||
<route>}
|
||||
<route>
|
||||
<service name="Report"> <child name="report_rom" /> </service>}
|
||||
|
||||
append_if [expr $use_ram_fs] config_of_app {
|
||||
<service name="File_system">
|
||||
|
@ -86,6 +86,7 @@ append config_of_app {
|
||||
<route>
|
||||
<service name="Framebuffer"> <child name="fb_drv" /> </service>
|
||||
<service name="Input"> <child name="input_merger" /> </service>
|
||||
<service name="Report"> <child name="report_rom" /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
<config>
|
||||
@ -156,6 +157,7 @@ append config_of_app {
|
||||
<service name="File_system"> <child name="rump_fs"/> </service>
|
||||
<service name="Framebuffer"> <child name="nit_fb" /> </service>
|
||||
<service name="Input"> <child name="nit_fb" /> </service>
|
||||
<service name="Report"><child name="report_rom" /></service>
|
||||
<service name="ROM">
|
||||
<if-arg key="label" value="usb_devices"/> <child name="report_rom"/>
|
||||
</service>
|
||||
|
@ -124,6 +124,7 @@ append_if [expr $use_usb] config {
|
||||
</config>
|
||||
<route>
|
||||
<service name="IRQ"><child name="acpi_drv" /></service>
|
||||
<service name="Report"><child name="report_rom" /></service>
|
||||
<any-service> <parent /> <any-child /></any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
Loading…
x
Reference in New Issue
Block a user