diff options
author | Liav A <liavalb@gmail.com> | 2019-12-31 13:04:30 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2020-01-02 00:50:09 +0100 |
commit | e5ffa960d7b585f4aba0eb18b89a14dee9e7e2b5 (patch) | |
tree | 4f6333ceb99e4010936b30082ce990d4ce0def1c /Kernel/PCI/Access.cpp | |
parent | d85874be4bae26f414cbb573ff2d67f491a331d6 (diff) | |
download | serenity-e5ffa960d7b585f4aba0eb18b89a14dee9e7e2b5.zip |
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.
Diffstat (limited to 'Kernel/PCI/Access.cpp')
-rw-r--r-- | Kernel/PCI/Access.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
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 <Kernel/PCI/Access.h> +#include <Kernel/PCI/IOAccess.h> + +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<void(Address, ID)>& 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<void(Address, ID)>& 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<void(Address, ID)>& 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<void(Address, ID)> 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); +} +} |