From 07474b434918c2b927f2829a1a944c9f5f4c0c7d Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 21 May 2021 12:06:20 +0300 Subject: [PATCH] Kernel/PCI: Fix support of multiple PCI host controllers enumeration First scan PCI bus 0. Find any device on that bus, and if it's a PCI-to-PCI bridge, recursively scan it too. Then try to handle Multiple PCI host bridges on slot 0, device 0. If we happen to miss some PCI buses because they are not reachable through recursive PCI-to-PCI bridges scanning starting from bus 0, we might find them in this scanning. --- Kernel/PCI/Access.cpp | 4 +++- Kernel/PCI/Access.h | 2 ++ Kernel/PCI/IOAccess.cpp | 29 +++++++++++++++++++---------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Kernel/PCI/Access.cpp b/Kernel/PCI/Access.cpp index 39ff9eef4e..f16c2c480f 100644 --- a/Kernel/PCI/Access.cpp +++ b/Kernel/PCI/Access.cpp @@ -35,6 +35,7 @@ bool Access::is_initialized() } UNMAP_AFTER_INIT Access::Access() + : m_enumerated_buses(256, false) { s_access = this; } @@ -85,10 +86,11 @@ void Access::enumerate_functions(int type, u8 bus, u8 device, u8 function, Funct Address address(0, bus, device, function); if (type == -1 || type == early_read_type(address)) callback(address, { early_read16_field(address, PCI_VENDOR_ID), early_read16_field(address, PCI_DEVICE_ID) }); - if (early_read_type(address) == PCI_TYPE_BRIDGE && recursive) { + if (early_read_type(address) == PCI_TYPE_BRIDGE && recursive && (!m_enumerated_buses.get(early_read8_field(address, PCI_SECONDARY_BUS)))) { u8 secondary_bus = early_read8_field(address, PCI_SECONDARY_BUS); dbgln_if(PCI_DEBUG, "PCI: Found secondary bus: {}", secondary_bus); VERIFY(secondary_bus != bus); + m_enumerated_buses.set(secondary_bus, true); enumerate_bus(type, secondary_bus, callback, recursive); } } diff --git a/Kernel/PCI/Access.h b/Kernel/PCI/Access.h index 42dc14d95b..d2c12695c2 100644 --- a/Kernel/PCI/Access.h +++ b/Kernel/PCI/Access.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -49,6 +50,7 @@ protected: virtual ~Access() = default; Vector m_physical_ids; + Bitmap m_enumerated_buses; }; } diff --git a/Kernel/PCI/IOAccess.cpp b/Kernel/PCI/IOAccess.cpp index d2fc93defb..ebcc155d06 100644 --- a/Kernel/PCI/IOAccess.cpp +++ b/Kernel/PCI/IOAccess.cpp @@ -67,17 +67,26 @@ void IOAccess::write32_field(Address address, u32 field, u32 value) void IOAccess::enumerate_hardware(Function callback) { dbgln_if(PCI_DEBUG, "PCI: IO enumerating hardware"); - // Single PCI host controller. - if ((read8_field(Address(), PCI_HEADER_TYPE) & 0x80) == 0) { - enumerate_bus(-1, 0, callback, true); - return; - } - // Multiple PCI host controllers. - for (int bus = 0; bus < 256; ++bus) { - if (read16_field(Address(0, 0, 0, bus), PCI_VENDOR_ID) == PCI_NONE) - break; - enumerate_bus(-1, bus, callback, false); + // First scan bus 0. Find any device on that bus, and if it's a PCI-to-PCI + // bridge, recursively scan it too. + m_enumerated_buses.set(0, true); + enumerate_bus(-1, 0, callback, true); + + // Handle Multiple PCI host bridges on slot 0, device 0. + // If we happen to miss some PCI buses because they are not reachable through + // recursive PCI-to-PCI bridges starting from bus 0, we might find them here. + if ((read8_field(Address(), PCI_HEADER_TYPE) & 0x80) != 0) { + for (int bus = 1; bus < 256; ++bus) { + if (read16_field(Address(0, 0, 0, bus), PCI_VENDOR_ID) == PCI_NONE) + continue; + if (read16_field(Address(0, 0, 0, bus), PCI_CLASS) != 0x6) + continue; + if (m_enumerated_buses.get(bus)) + continue; + enumerate_bus(-1, bus, callback, false); + m_enumerated_buses.set(bus, true); + } } }