HostBridge.cpp 8.9 KB

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