From 0de62717f9fb9ed34bbbd181fea4e839643749c4 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 3 May 2018 13:51:13 +0200 Subject: [PATCH] x86: detect root bridge properly Beforehand the root bridge was expected to be at 0:0.0. Fixes #2801 --- repos/os/src/drivers/acpi/acpi.cc | 71 ++++++++---------- repos/os/src/drivers/platform/spec/x86/irq.cc | 9 ++- .../drivers/platform/spec/x86/pci_bridge.h | 3 + .../platform/spec/x86/pci_session_component.h | 72 ++++--------------- .../src/drivers/platform/spec/x86/session.cc | 7 +- 5 files changed, 56 insertions(+), 106 deletions(-) diff --git a/repos/os/src/drivers/acpi/acpi.cc b/repos/os/src/drivers/acpi/acpi.cc index 99caea394d..cef6f0fd77 100644 --- a/repos/os/src/drivers/acpi/acpi.cc +++ b/repos/os/src/drivers/acpi/acpi.cc @@ -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(this); } /* MADT ACPI structure */ @@ -495,6 +506,9 @@ class Pci_routing : public List::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 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 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(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(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()) diff --git a/repos/os/src/drivers/platform/spec/x86/irq.cc b/repos/os/src/drivers/platform/spec/x86/irq.cc index 1853236d99..6c55d87cda 100644 --- a/repos/os/src/drivers/platform/spec/x86/irq.cc +++ b/repos/os/src/drivers/platform/spec/x86/irq.cc @@ -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; } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_bridge.h b/repos/os/src/drivers/platform/spec/x86/pci_bridge.h index d989183efe..961b958f39 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_bridge.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_bridge.h @@ -53,4 +53,7 @@ class Platform::Bridge : public Genode::List::Element bdf = (bdf << 8) | ((_dev & 0x1f) << 3) | (_fun & 0x7); return bdf; } + + enum { INVALID_ROOT_BRIDGE = 0x10000U }; + static unsigned root_bridge_bdf; }; diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index 644da7e999..71435a7739 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -34,9 +34,10 @@ #include /* 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 { 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 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 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 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") && diff --git a/repos/os/src/drivers/platform/spec/x86/session.cc b/repos/os/src/drivers/platform/spec/x86/session.cc index 301760cd62..d245efe76b 100644 --- a/repos/os/src/drivers/platform/spec/x86/session.cc +++ b/repos/os/src/drivers/platform/spec/x86/session.cc @@ -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 *bridges() { static Genode::List 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,