x86: detect root bridge properly

Beforehand the root bridge was expected to be at 0:0.0.

Fixes #2801
This commit is contained in:
Alexander Boettcher 2018-05-03 13:51:13 +02:00 committed by Christian Helmuth
parent 58fb5ed722
commit 0de62717f9
5 changed files with 56 additions and 106 deletions

View File

@ -88,6 +88,17 @@ struct Generic
uint8_t creator[4];
uint32_t creator_rev;
void print(Genode::Output &out) const
{
Genode::String<7> s_oem((const char *)oemid);
Genode::String<9> s_oemtabid((const char *)oemtabid);
Genode::String<5> s_creator((const char *)creator);
Genode::print(out, "OEM '", s_oem, "', table id '", s_oemtabid, "', "
"revision ", oemrev, ", creator '", s_creator, "' (",
creator_rev, ")");
}
uint8_t const *data() { return reinterpret_cast<uint8_t *>(this); }
/* MADT ACPI structure */
@ -495,6 +506,9 @@ class Pci_routing : public List<Pci_routing>::Element
}
};
/* set during ACPI Table walk to valid value */
enum { INVALID_ROOT_BRIDGE = 0x10000U };
static unsigned root_bridge_bdf = INVALID_ROOT_BRIDGE;
/**
* A table element (method, device, scope or name)
@ -1081,6 +1095,13 @@ class Element : private List<Element>::Element
if (prt) prt->dump();
if (prt) {
uint32_t const hid= e->_value("_HID");
uint32_t const cid= e->_value("_CID");
if (hid == 0x80ad041 || cid == 0x80ad041 || // "PNP0A08" PCI Express root bridge
hid == 0x30ad041 || cid == 0x30ad041) { // "PNP0A03" PCI root bridge
root_bridge_bdf = e->_bdf;
}
if (verbose)
Genode::log("Scanning device ", Genode::Hex(e->_bdf));
@ -1091,31 +1112,6 @@ class Element : private List<Element>::Element
e->_routed = true;
}
}
/**
* Search for GSI of given device, bridge, and pin
*/
static uint32_t search_gsi(uint32_t device_bdf, uint32_t bridge_bdf, uint32_t pin)
{
Element *e = list()->first();
for (; e; e = e->next()) {
if (!e->is_device() || e->_bdf != bridge_bdf)
continue;
Pci_routing *r = e->pci_list().first();
for (; r; r = r->next()) {
if (r->match_bdf(device_bdf) && r->pin() == pin) {
if (verbose)
Genode::log("Found GSI: ", r->gsi(), " "
"device : ", Genode::Hex(device_bdf), " ",
"pin ", pin);
return r->gsi();
}
}
}
throw -1;
}
};
@ -1287,16 +1283,6 @@ class Acpi_table
return;
}
if (verbose) {
uint8_t oem[7];
memcpy(oem, rsdp->oemid, 6);
oem[6] = 0;
Genode::log("ACPI revision ", rsdp->revision, " of "
"OEM '", oem, "', "
"rsdt:", Genode::Hex(rsdp->rsdt), " "
"xsdt:", Genode::Hex(rsdp->xsdt));
}
rsdt = rsdp->rsdt;
xsdt = rsdp->xsdt;
acpi_revision = rsdp->revision;
@ -1311,6 +1297,8 @@ class Acpi_table
uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1);
_parse_tables(alloc, entries, table.entry_count(entries));
Genode::log("XSDT ", *table.table());
} else {
/* running (32bit) or (64bit and xsdt isn't valid) */
Table_wrapper table(_memory, rsdt);
@ -1318,6 +1306,8 @@ class Acpi_table
uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1);
_parse_tables(alloc, entries, table.entry_count(entries));
Genode::log("RSDT ", *table.table());
}
/* free up memory of elements not of any use */
@ -1348,14 +1338,11 @@ void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc)
acpi.enabled(true);
Genode::Reporter::Xml_generator xml(acpi, [&] () {
if (!(!Fadt::features && !Fadt::reset_type &&
!Fadt::reset_addr && !Fadt::reset_value))
xml.node("fadt", [&] () {
attribute_hex(xml, "features" , Fadt::features);
attribute_hex(xml, "reset_type" , Fadt::reset_type);
attribute_hex(xml, "reset_addr" , Fadt::reset_addr);
attribute_hex(xml, "reset_value", Fadt::reset_value);
if (root_bridge_bdf != INVALID_ROOT_BRIDGE) {
xml.node("root_bridge", [&] () {
attribute_hex(xml, "bdf", root_bridge_bdf);
});
}
for (Pci_config_space *e = Pci_config_space::list()->first(); e;
e = e->next())

View File

@ -287,12 +287,15 @@ void Platform::Irq_session_component::sigh(Genode::Signal_context_capability sig
unsigned short Platform::Irq_routing::rewrite(unsigned char bus, unsigned char dev,
unsigned char /* func */, unsigned char pin)
unsigned char, unsigned char pin)
{
for (Irq_routing *i = list()->first(); i; i = i->next())
unsigned const bridge_bdf_bus = Platform::bridge_bdf(bus);
for (Irq_routing *i = list()->first(); i; i = i->next()) {
if ((dev == i->_device) && (pin - 1 == i->_device_pin) &&
(i->_bridge_bdf == Platform::bridge_bdf(bus)))
(i->_bridge_bdf == bridge_bdf_bus))
return i->_gsi;
}
return 0;
}

View File

@ -53,4 +53,7 @@ class Platform::Bridge : public Genode::List<Bridge>::Element
bdf = (bdf << 8) | ((_dev & 0x1f) << 3) | (_fun & 0x7);
return bdf;
}
enum { INVALID_ROOT_BRIDGE = 0x10000U };
static unsigned root_bridge_bdf;
};

View File

@ -34,9 +34,10 @@
#include <base/allocator_guard.h>
/* local */
#include "pci_device_component.h"
#include "pci_config_access.h"
#include "device_pd.h"
#include "pci_bridge.h"
#include "pci_config_access.h"
#include "pci_device_component.h"
typedef Genode::Ram_dataspace_capability Ram_capability;
@ -828,27 +829,6 @@ class Platform::Root : public Genode::Root_component<Session_component>
{
private:
struct Fadt {
Genode::uint32_t features = 0, reset_type = 0, reset_value = 0;
Genode::uint64_t reset_addr = 0;
/* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */
struct Features : Genode::Register<32> {
struct Reset : Bitfield<10, 1> { };
};
/* ACPI spec - 5.2.3.2 Generic Address Structure */
struct Gas : Genode::Register<32>
{
struct Address_space : Bitfield <0, 8> {
enum { SYSTEM_IO = 1 };
};
struct Access_size : Bitfield<24,8> {
enum { UNDEFINED = 0, BYTE = 1, WORD = 2, DWORD = 3, QWORD = 4};
};
};
} fadt { };
Genode::Env &_env;
Genode::Attached_rom_dataspace &_config;
@ -974,11 +954,8 @@ class Platform::Root : public Genode::Root_component<Session_component>
continue;
}
if (node.has_type("fadt")) {
node.attribute("features").value(&fadt.features);
node.attribute("reset_type").value(&fadt.reset_type);
node.attribute("reset_addr").value(&fadt.reset_addr);
node.attribute("reset_value").value(&fadt.reset_value);
if (node.has_type("root_bridge")) {
node.attribute("bdf").value(&Platform::Bridge::root_bridge_bdf);
continue;
}
@ -997,40 +974,9 @@ class Platform::Root : public Genode::Root_component<Session_component>
node.attribute("device").value(&device);
node.attribute("device_pin").value(&device_pin);
/* check that bridge bdf is actually a valid device */
Device_config config((bridge_bdf >> 8 & 0xff),
(bridge_bdf >> 3) & 0x1f,
bridge_bdf & 0x7, &config_access);
if (!config.valid())
continue;
/* drop routing information on non ACPI platform */
if (!acpi_platform) {
if (config.pci_bridge())
continue;
Device_config dev(device << 3);
enum { PCI_IRQ_LINE = 0x3c };
uint8_t pin = dev.read(config_access, PCI_IRQ_LINE,
Platform::Device::ACCESS_8BIT);
warning(dev, " ignore ACPI IRQ routing: ", pin, "->", gsi);
if (!acpi_platform)
continue;
}
if (!config.pci_bridge() && bridge_bdf != 0)
/**
* If the bridge bdf has not a type header of a bridge in
* the pci config space, then it should be the host bridge
* device. The host bridge device need not to be
* necessarily at 0:0.0, it may be on another location. The
* irq routing information for the host bridge however
* contain entries for the bridge bdf to be 0:0.0 -
* therefore we override it here for the irq rerouting
* information of host bridge devices.
*/
bridge_bdf = 0;
Irq_routing * r = new (_heap) Irq_routing(gsi, bridge_bdf,
device, device_pin);
@ -1123,6 +1069,12 @@ class Platform::Root : public Genode::Root_component<Session_component>
throw;
}
if (Platform::Bridge::root_bridge_bdf < Platform::Bridge::INVALID_ROOT_BRIDGE) {
Device_config config(Platform::Bridge::root_bridge_bdf);
Genode::log("Root bridge: ", config);
} else
Genode::warning("Root bridge: unknown");
_construct_buses();
_pci_reporter.enabled(config.xml().has_sub_node("report") &&

View File

@ -15,6 +15,10 @@
#include "pci_bridge.h"
/* set during ACPI ROM parsing to valid value */
unsigned Platform::Bridge::root_bridge_bdf = INVALID_ROOT_BRIDGE;
static Genode::List<Platform::Bridge> *bridges()
{
static Genode::List<Platform::Bridge> list;
@ -30,7 +34,8 @@ unsigned short Platform::bridge_bdf(unsigned char bus)
if (bridge->part_of(bus))
return bridge->bdf();
}
return 0;
/* XXX Ideally, this case should never happen */
return Platform::Bridge::root_bridge_bdf;
}
void Platform::Pci_buses::scan_bus(Config_access &config_access,