From e5ffa960d7b585f4aba0eb18b89a14dee9e7e2b5 Mon Sep 17 00:00:00 2001 From: Liav A Date: Tue, 31 Dec 2019 13:04:30 +0200 Subject: Kernel: Create support for PCI ECAM The new PCI subsystem is initialized during runtime. PCI::Initializer is supposed to be called during early boot, to perform a few tests, and initialize the proper configuration space access mechanism. Kernel boot parameters can be specified by a user to determine what tests will occur, to aid debugging on problematic machines. After that, PCI::Initializer should be dismissed. PCI::IOAccess is a class that is derived from PCI::Access class and implements PCI configuration space access mechanism via x86 IO ports. PCI::MMIOAccess is a class that is derived from PCI::Access and implements PCI configurtaion space access mechanism via memory access. The new PCI subsystem also supports determination of IO/MMIO space needed by a device by checking a given BAR. In addition, Every device or component that use the PCI subsystem has changed to match the last changes. --- Kernel/PCI/Access.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 Kernel/PCI/Access.cpp (limited to 'Kernel/PCI/Access.cpp') diff --git a/Kernel/PCI/Access.cpp b/Kernel/PCI/Access.cpp new file mode 100644 index 0000000000..6e342027f8 --- /dev/null +++ b/Kernel/PCI/Access.cpp @@ -0,0 +1,142 @@ +#include +#include + +static PCI::Access* s_access; + +PCI::Access& PCI::Access::the() +{ + if (s_access == nullptr) { + ASSERT_NOT_REACHED(); // We failed to initialize the PCI subsystem, so stop here! + } + return *s_access; +} + +bool PCI::Access::is_initialized() +{ + return (s_access != nullptr); +} + +PCI::Access::Access() +{ + s_access = this; +} + +void PCI::Access::enumerate_functions(int type, u8 bus, u8 slot, u8 function, Function& callback) +{ + Address address(0, bus, slot, function); + if (type == -1 || type == read_type(address)) + callback(address, { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }); + if (read_type(address) == PCI_TYPE_BRIDGE) { + u8 secondary_bus = read8_field(address, PCI_SECONDARY_BUS); +#ifdef PCI_DEBUG + kprintf("PCI: Found secondary bus: %u\n", secondary_bus); +#endif + ASSERT(secondary_bus != bus); + enumerate_bus(type, secondary_bus, callback); + } +} + +void PCI::Access::enumerate_slot(int type, u8 bus, u8 slot, Function& callback) +{ + Address address(0, bus, slot, 0); + if (read16_field(address, PCI_VENDOR_ID) == PCI_NONE) + return; + enumerate_functions(type, bus, slot, 0, callback); + if (!(read8_field(address, PCI_HEADER_TYPE) & 0x80)) + return; + for (u8 function = 1; function < 8; ++function) { + Address address(0, bus, slot, function); + if (read16_field(address, PCI_VENDOR_ID) != PCI_NONE) + enumerate_functions(type, bus, slot, function, callback); + } +} + +void PCI::Access::enumerate_bus(int type, u8 bus, Function& callback) +{ + for (u8 slot = 0; slot < 32; ++slot) + enumerate_slot(type, bus, slot, callback); +} + +void PCI::Access::enable_bus_mastering(Address address) +{ + auto value = read16_field(address, PCI_COMMAND); + value |= (1 << 2); + value |= (1 << 0); + write16_field(address, PCI_COMMAND, value); +} + +void PCI::Access::disable_bus_mastering(Address address) +{ + auto value = read16_field(address, PCI_COMMAND); + value &= ~(1 << 2); + value |= (1 << 0); + write16_field(address, PCI_COMMAND, value); +} + +namespace PCI { +void enumerate_all(Function callback) +{ + PCI::Access::the().enumerate_all(callback); +} + +u8 get_interrupt_line(Address address) +{ + return PCI::Access::the().get_interrupt_line(address); +} +u32 get_BAR0(Address address) +{ + return PCI::Access::the().get_BAR0(address); +} +u32 get_BAR1(Address address) +{ + return PCI::Access::the().get_BAR1(address); +} +u32 get_BAR2(Address address) +{ + return PCI::Access::the().get_BAR2(address); +} +u32 get_BAR3(Address address) +{ + return PCI::Access::the().get_BAR3(address); +} +u32 get_BAR4(Address address) +{ + return PCI::Access::the().get_BAR4(address); +} +u32 get_BAR5(Address address) +{ + return PCI::Access::the().get_BAR5(address); +} +u8 get_revision_id(Address address) +{ + return PCI::Access::the().get_revision_id(address); +} +u8 get_subclass(Address address) +{ + return PCI::Access::the().get_subclass(address); +} +u8 get_class(Address address) +{ + return PCI::Access::the().get_class(address); +} +u16 get_subsystem_id(Address address) +{ + return PCI::Access::the().get_subsystem_id(address); +} +u16 get_subsystem_vendor_id(Address address) +{ + return PCI::Access::the().get_subsystem_vendor_id(address); +} +void enable_bus_mastering(Address address) +{ + PCI::Access::the().enable_bus_mastering(address); +} +void disable_bus_mastering(Address address) +{ + PCI::Access::the().disable_bus_mastering(address); +} +u32 get_BAR_Space_Size(Address address, u8 bar_number) +{ + return PCI::Access::the().get_BAR_Space_Size(address, bar_number); +} +} -- cgit v1.2.3