Serenity Operating System
at master 136 lines 7.4 kB view raw
1/* 2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Format.h> 8#include <Kernel/Bus/PCI/Access.h> 9#include <Kernel/Bus/PCI/Controller/HostController.h> 10#include <Kernel/Bus/PCI/Definitions.h> 11#include <Kernel/Sections.h> 12 13namespace Kernel::PCI { 14 15HostController::HostController(PCI::Domain const& domain) 16 : m_domain(domain) 17 , m_enumerated_buses(Bitmap::create(256, false).release_value_but_fixme_should_propagate_errors()) 18{ 19} 20 21UNMAP_AFTER_INIT Optional<u8> HostController::get_capabilities_pointer_for_function(BusNumber bus, DeviceNumber device, FunctionNumber function) 22{ 23 if (read16_field(bus, device, function, PCI::RegisterOffset::STATUS) & (1 << 4)) { 24 return read8_field(bus, device, function, PCI::RegisterOffset::CAPABILITIES_POINTER); 25 } 26 return {}; 27} 28 29UNMAP_AFTER_INIT Vector<Capability> HostController::get_capabilities_for_function(BusNumber bus, DeviceNumber device, FunctionNumber function) 30{ 31 auto capabilities_pointer = get_capabilities_pointer_for_function(bus, device, function); 32 if (!capabilities_pointer.has_value()) { 33 return {}; 34 } 35 Vector<Capability> capabilities; 36 auto capability_pointer = capabilities_pointer.value(); 37 while (capability_pointer != 0) { 38 u16 capability_header = read16_field(bus, device, function, capability_pointer); 39 u8 capability_id = capability_header & 0xff; 40 41 // FIXME: Don't attach a PCI address to a capability object 42 capabilities.append({ Address(domain_number(), bus.value(), device.value(), function.value()), capability_id, capability_pointer }); 43 capability_pointer = capability_header >> 8; 44 } 45 return capabilities; 46} 47 48u8 HostController::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, PCI::RegisterOffset field) 49{ 50 return read8_field(bus, device, function, to_underlying(field)); 51} 52u16 HostController::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, PCI::RegisterOffset field) 53{ 54 return read16_field(bus, device, function, to_underlying(field)); 55} 56 57UNMAP_AFTER_INIT void HostController::enumerate_functions(Function<IterationDecision(EnumerableDeviceIdentifier)> const& callback, BusNumber bus, DeviceNumber device, FunctionNumber function, bool recursive_search_into_bridges) 58{ 59 dbgln_if(PCI_DEBUG, "PCI: Enumerating function, bus={}, device={}, function={}", bus, device, function); 60 Address address(domain_number(), bus.value(), device.value(), function.value()); 61 auto pci_class = (read8_field(bus, device, function, PCI::RegisterOffset::CLASS) << 8u) | read8_field(bus, device, function, PCI::RegisterOffset::SUBCLASS); 62 63 HardwareID id = { read16_field(bus, device, function, PCI::RegisterOffset::VENDOR_ID), read16_field(bus, device, function, PCI::RegisterOffset::DEVICE_ID) }; 64 ClassCode class_code = read8_field(bus, device, function, PCI::RegisterOffset::CLASS); 65 SubclassCode subclass_code = read8_field(bus, device, function, PCI::RegisterOffset::SUBCLASS); 66 ProgrammingInterface prog_if = read8_field(bus, device, function, PCI::RegisterOffset::PROG_IF); 67 RevisionID revision_id = read8_field(bus, device, function, PCI::RegisterOffset::REVISION_ID); 68 SubsystemID subsystem_id = read16_field(bus, device, function, PCI::RegisterOffset::SUBSYSTEM_ID); 69 SubsystemVendorID subsystem_vendor_id = read16_field(bus, device, function, PCI::RegisterOffset::SUBSYSTEM_VENDOR_ID); 70 InterruptLine interrupt_line = read8_field(bus, device, function, PCI::RegisterOffset::INTERRUPT_LINE); 71 InterruptPin interrupt_pin = read8_field(bus, device, function, PCI::RegisterOffset::INTERRUPT_PIN); 72 auto capabilities = get_capabilities_for_function(bus, device, function); 73 callback(EnumerableDeviceIdentifier { address, id, revision_id, class_code, subclass_code, prog_if, subsystem_id, subsystem_vendor_id, interrupt_line, interrupt_pin, capabilities }); 74 75 if (pci_class == (to_underlying(PCI::ClassID::Bridge) << 8 | to_underlying(PCI::Bridge::SubclassID::PCI_TO_PCI)) 76 && recursive_search_into_bridges 77 && (!m_enumerated_buses.get(read8_field(bus, device, function, PCI::RegisterOffset::SECONDARY_BUS)))) { 78 u8 secondary_bus = read8_field(bus, device, function, PCI::RegisterOffset::SECONDARY_BUS); 79 dbgln_if(PCI_DEBUG, "PCI: Found secondary bus: {}", secondary_bus); 80 VERIFY(secondary_bus != bus); 81 m_enumerated_buses.set(secondary_bus, true); 82 enumerate_bus(callback, secondary_bus, recursive_search_into_bridges); 83 } 84} 85 86UNMAP_AFTER_INIT void HostController::enumerate_device(Function<IterationDecision(EnumerableDeviceIdentifier)> const& callback, BusNumber bus, DeviceNumber device, bool recursive_search_into_bridges) 87{ 88 dbgln_if(PCI_DEBUG, "PCI: Enumerating device in bus={}, device={}", bus, device); 89 if (read16_field(bus, device, 0, PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) 90 return; 91 enumerate_functions(callback, bus, device, 0, recursive_search_into_bridges); 92 if (!(read8_field(bus, device, 0, PCI::RegisterOffset::HEADER_TYPE) & 0x80)) 93 return; 94 for (u8 function = 1; function < 8; ++function) { 95 if (read16_field(bus, device, function, PCI::RegisterOffset::VENDOR_ID) != PCI::none_value) 96 enumerate_functions(callback, bus, device, function, recursive_search_into_bridges); 97 } 98} 99 100UNMAP_AFTER_INIT void HostController::enumerate_bus(Function<IterationDecision(EnumerableDeviceIdentifier)> const& callback, BusNumber bus, bool recursive_search_into_bridges) 101{ 102 dbgln_if(PCI_DEBUG, "PCI: Enumerating bus {}", bus); 103 for (u8 device = 0; device < 32; ++device) 104 enumerate_device(callback, bus, device, recursive_search_into_bridges); 105} 106 107UNMAP_AFTER_INIT void HostController::enumerate_attached_devices(Function<IterationDecision(EnumerableDeviceIdentifier)> callback) 108{ 109 VERIFY(Access::the().access_lock().is_locked()); 110 VERIFY(Access::the().scan_lock().is_locked()); 111 // First scan bus 0. Find any device on that bus, and if it's a PCI-to-PCI 112 // bridge, recursively scan it too. 113 m_enumerated_buses.set(m_domain.start_bus(), true); 114 enumerate_bus(callback, m_domain.start_bus(), true); 115 116 // Handle Multiple PCI host bridges on bus 0, device 0, functions 1-7 (function 0 117 // is the main host bridge). 118 // If we happen to miss some PCI buses because they are not reachable through 119 // recursive PCI-to-PCI bridges starting from bus 0, we might find them here. 120 if ((read8_field(0, 0, 0, PCI::RegisterOffset::HEADER_TYPE) & 0x80) != 0) { 121 for (int bus_as_function_number = 1; bus_as_function_number < 8; ++bus_as_function_number) { 122 if (read16_field(0, 0, bus_as_function_number, PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) 123 continue; 124 if (read16_field(0, 0, bus_as_function_number, PCI::RegisterOffset::CLASS) != 0x6) 125 continue; 126 if (Checked<u8>::addition_would_overflow(m_domain.start_bus(), bus_as_function_number)) 127 break; 128 if (m_enumerated_buses.get(m_domain.start_bus() + bus_as_function_number)) 129 continue; 130 enumerate_bus(callback, m_domain.start_bus() + bus_as_function_number, false); 131 m_enumerated_buses.set(m_domain.start_bus() + bus_as_function_number, true); 132 } 133 } 134} 135 136}