From c6cc43f0e49a5d40e1875942195146df0b251581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Tue, 22 Mar 2022 13:57:24 +0100 Subject: [PATCH] lx_kit/x86: use virtual information for PCI This commit removes all physical notions from the information given to the Linux kernel regarding PCI BARs. With the exception for the host bridge that needs to be located at '0:00.0' as required by the Intel FB driver, all other devices are announced at the PCI BUS in an ascending order. Additionally the MMIO regions start at 1 GiB and are capped at 32 bit to prevent unnecessary access to 64 bit addresses. --- .../src/lib/lx_kit/spec/x86/platform.cc | 93 ++++++++++++++----- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc b/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc index 36aeace63b..c93bc8a762 100644 --- a/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc +++ b/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc @@ -50,37 +50,49 @@ static void scan_resources(Legacy_platform::Device &device, static Str create_device_node(Xml_generator &xml, Legacy_platform::Device &device) { - struct { - char const *key; - unsigned char value; - } bdf[3] = { - { .key = "bus", .value = 0u }, - { .key = "dev", .value = 0u }, - { .key = "func", .value = 0u }, - }; - device.bus_address(&bdf[0].value, &bdf[1].value, &bdf[2].value); + using namespace Genode; /* start arbitrarily and count up */ static unsigned char irq = 8; - using namespace Genode; + /* start arbitrarily at the dev 1 for the first device */ + static unsigned char bdf[3] = { 0, 1, 0 }; + + /* start arbitrarily at 1 GiB */ + static unsigned long mmio_phys_addr = 0x40000000; + + unsigned char pbdf[3]; + device.bus_address(&pbdf[0], &pbdf[1], &pbdf[2]); + + /* + * The host-bridge is only required by the Intel framebuffer + * driver and has to be located at 00:00.0. For every other + * type of device we simply count upwards. + */ + unsigned char vbdf[3] = { 0, 0, 0 }; + unsigned const class_code = device.class_code() >> 8; + if (class_code != 0x600 /* host-bridge */) { + vbdf[0] = bdf[0]; vbdf[1] = bdf[1]; vbdf[2] = bdf[2]; + bdf[1]++; + } + + log("override physical BDF ", + Hex(pbdf[0], Hex::OMIT_PREFIX), ":", + Hex(pbdf[1], Hex::OMIT_PREFIX), ".", + Hex(pbdf[2], Hex::OMIT_PREFIX), " -> ", + Hex(vbdf[0], Hex::OMIT_PREFIX), ":", + Hex(vbdf[1], Hex::OMIT_PREFIX), ".", + Hex(vbdf[2], Hex::OMIT_PREFIX)); Str name = to_string("pci-", - Hex(bdf[0].value, Hex::OMIT_PREFIX), ":", - Hex(bdf[1].value, Hex::OMIT_PREFIX), ".", - Hex(bdf[2].value, Hex::OMIT_PREFIX)); + Hex(vbdf[0], Hex::OMIT_PREFIX), ":", + Hex(vbdf[1], Hex::OMIT_PREFIX), ".", + Hex(vbdf[2], Hex::OMIT_PREFIX)); xml.node("device", [&] () { xml.attribute("name", name); xml.attribute("type", "pci"); - for (auto i : bdf) { - xml.node("property", [&] () { - xml.attribute("name", i.key); - xml.attribute("value", to_string(i.value)); - }); - } - xml.node("irq", [&] () { xml.attribute("number", irq++); }); @@ -89,11 +101,17 @@ static Str create_device_node(Xml_generator &xml, scan_resources(device, [&] (unsigned id, R const &r) { - xml.node(r.type() == R::MEMORY ? "io_mem" : "io_port", [&] () { - xml.attribute("phys_addr", to_string(Hex(r.base()))); + bool const memory = r.type() == R::MEMORY; + + xml.node(memory ? "io_mem" : "io_port", [&] () { + xml.attribute("phys_addr", + to_string(Hex(memory ? mmio_phys_addr : r.bar()))); xml.attribute("size", to_string(Hex(r.size()))); xml.attribute("bar", id); }); + + if (memory) + mmio_phys_addr += align_addr(r.size(), 12); }); }); @@ -242,6 +260,35 @@ static unsigned bar_size(Platform::Device const &dev, } +static unsigned bar_address(Platform::Device const &dev, + Xml_node const &devices, unsigned bar) +{ + if (bar > 6) + return 0; + + using namespace Genode; + + unsigned val = 0; + apply(dev, devices, [&] (Xml_node device) { + device.for_each_sub_node("io_mem", [&] (Xml_node node) { + if (node.attribute_value("bar", 6u) != bar) + return; + + val = node.attribute_value("phys_addr", 0u); + }); + + device.for_each_sub_node("io_port", [&] (Xml_node node) { + if (node.attribute_value("bar", 6u) != bar) + return; + + val = node.attribute_value("phys_addr", 0u); + }); + }); + + return val; +} + + static unsigned char irq_line(Platform::Device const &dev, Xml_node const &devices) { @@ -288,6 +335,8 @@ unsigned Platform::Device::Config_space::read(unsigned char address, _device._bar_checked_for_size[bar] = 0; return bar_size(_device, *_device._platform._devices_node, bar); } + + return bar_address(_device, *_device._platform._devices_node, bar); } if (address == 0x3c)