summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-05-21 12:06:20 +0300
committerLinus Groh <mail@linusgroh.de>2021-05-21 17:58:53 +0100
commit07474b434918c2b927f2829a1a944c9f5f4c0c7d (patch)
treeacb78ea929200a15762f58b3d5e47c00ef34d023
parentc6ffee7f180396495a9ee4633ba36589abbe45f9 (diff)
downloadserenity-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.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);
+ }
}
}