summaryrefslogtreecommitdiff
path: root/Kernel/PCI
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/PCI')
-rw-r--r--Kernel/PCI/Access.cpp4
-rw-r--r--Kernel/PCI/Access.h2
-rw-r--r--Kernel/PCI/IOAccess.cpp29
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);
+ }
}
}