pci_decode: limit bus parsing to subordinate buses

While this approach still scans "holes" in the bus range, it stops
scanning at the maximum subordinate bus number reachable from the base
PCI bus at the host bridge. Startup under Qemu no longer takes about 12
seconds for scanning 256 buses.
This commit is contained in:
Christian Helmuth 2023-06-21 17:16:29 +02:00 committed by Norman Feske
parent 0ab69a2bb8
commit 2232b33b8e
2 changed files with 46 additions and 22 deletions

View File

@ -246,8 +246,9 @@ install_config $config
build_boot_image [build_artifacts]
append qemu_args " -nographic "
append qemu_args " -device pcie-root-port,id=root_port1 "
append qemu_args " -drive id=nvme0,file=bin/nvme.raw,format=raw,if=none "
append qemu_args " -device nvme,drive=nvme0,serial=fnord,id=nvme0n1 "
append qemu_args " -device nvme,drive=nvme0,serial=fnord,id=nvme0n1,bus=root_port1 "
run_genode_until {.*child "block_tester" exited with exit value 0.*\n} 300

View File

@ -43,11 +43,11 @@ struct Main
Constructible<Attached_io_mem_dataspace> pci_config_ds {};
void parse_pci_function(Bdf bdf, Config & cfg,
addr_t cfg_phys_base,
Xml_generator & generator, unsigned & msi);
void parse_pci_bus(bus_t bus, addr_t base, addr_t phys_base,
Xml_generator & generator, unsigned & msi);
bus_t parse_pci_function(Bdf bdf, Config & cfg,
addr_t cfg_phys_base,
Xml_generator & generator, unsigned & msi);
bus_t parse_pci_bus(bus_t bus, addr_t base, addr_t phys_base,
Xml_generator & generator, unsigned & msi);
void parse_irq_override_rules(Xml_node & xml);
void parse_pci_config_spaces(Xml_node & xml, Xml_generator & generator);
@ -64,14 +64,22 @@ struct Main
};
void Main::parse_pci_function(Bdf bdf,
Config & cfg,
addr_t cfg_phys_base,
Xml_generator & gen,
unsigned & msi_number)
/*
* The bus and function parsers return either the current bus number or the
* subordinate bus number (highest bus number of all of the busses that can be
* reached downstream of a bridge).
*/
bus_t Main::parse_pci_function(Bdf bdf,
Config & cfg,
addr_t cfg_phys_base,
Xml_generator & gen,
unsigned & msi_number)
{
cfg.scan();
bus_t subordinate_bus = bdf.bus;
/* check for bridges */
if (cfg.read<Config::Header_type::Type>()) {
for_bridge(bdf.bus, [&] (Bridge & parent) {
@ -80,6 +88,8 @@ void Main::parse_pci_function(Bdf bdf,
bcfg.secondary_bus_number(),
bcfg.subordinate_bus_number());
subordinate_bus = bcfg.subordinate_bus_number();
/* enable I/O spaces and DMA in bridges if not done already */
using Command = Pci::Config::Command;
Command::access_t command = bcfg.read<Command>();
@ -231,23 +241,30 @@ void Main::parse_pci_function(Bdf bdf,
});
});
});
return subordinate_bus;
}
void Main::parse_pci_bus(bus_t bus,
addr_t base,
addr_t phys_base,
Xml_generator & generator,
unsigned & msi_number)
bus_t Main::parse_pci_bus(bus_t bus,
addr_t base,
addr_t phys_base,
Xml_generator & generator,
unsigned & msi_number)
{
bus_t max_subordinate_bus = bus;
auto per_function = [&] (addr_t config_base, addr_t config_phys_base,
dev_t dev, func_t fn) {
Config cfg(config_base);
if (!cfg.valid())
return true;
parse_pci_function({(bus_t)bus, dev, fn}, cfg,
config_phys_base, generator, msi_number);
bus_t const subordinate_bus =
parse_pci_function({(bus_t)bus, dev, fn}, cfg,
config_phys_base, generator, msi_number);
max_subordinate_bus = max(max_subordinate_bus, subordinate_bus);
return !(fn == 0 && !cfg.read<Config::Header_type::Multi_function>());
};
@ -262,6 +279,8 @@ void Main::parse_pci_bus(bus_t bus,
break;
}
}
return max_subordinate_bus;
}
@ -359,15 +378,19 @@ void Main::parse_pci_config_spaces(Xml_node & xml, Xml_generator & generator)
bus_off, last_bus);
bus_t bus = 0;
bus_t max_subordinate_bus = bus;
do {
enum { BUS_SIZE = DEVICES_PER_BUS_MAX * FUNCTION_PER_DEVICE_MAX
* FUNCTION_CONFIG_SPACE_SIZE };
addr_t offset = base + bus * BUS_SIZE;
pci_config_ds.construct(env, offset, BUS_SIZE);
parse_pci_bus((bus_t)bus + bus_off,
(addr_t)pci_config_ds->local_addr<void>(),
offset, generator, msi_number);
} while (bus++ < last_bus);
bus_t const subordinate_bus =
parse_pci_bus((bus_t)bus + bus_off,
(addr_t)pci_config_ds->local_addr<void>(),
offset, generator, msi_number);
max_subordinate_bus = max(max_subordinate_bus, subordinate_bus);
} while (bus++ < max_subordinate_bus);
pci_config_ds.destruct();
});