diff options
author | Liav A <liavalb@gmail.com> | 2021-05-21 12:06:20 +0300 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-05-21 17:58:53 +0100 |
commit | 07474b434918c2b927f2829a1a944c9f5f4c0c7d (patch) | |
tree | acb78ea929200a15762f58b3d5e47c00ef34d023 | |
parent | c6ffee7f180396495a9ee4633ba36589abbe45f9 (diff) | |
download | serenity-07474b434918c2b927f2829a1a944c9f5f4c0c7d.zip |
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.
-rw-r--r-- | Kernel/PCI/Access.cpp | 4 | ||||
-rw-r--r-- | Kernel/PCI/Access.h | 2 | ||||
-rw-r--r-- | 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 <AK/Bitmap.h> #include <AK/String.h> #include <AK/Vector.h> #include <Kernel/PCI/Definitions.h> @@ -49,6 +50,7 @@ protected: virtual ~Access() = default; Vector<PhysicalID> 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<void(Address, ID)> 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); + } } } |