Kernel: Add preliminary support for PCIe

Only segment 0 is supported, but devices can now be accessed through
mmio.

Adding more segments would require adding argument to every PCI API so
it is left for later.
This commit is contained in:
2024-05-25 20:50:07 +03:00
parent 3b18730af6
commit 2a4d986da5
4 changed files with 328 additions and 238 deletions

View File

@@ -56,7 +56,11 @@ namespace Kernel::PCI
class Device
{
public:
Device(uint8_t, uint8_t, uint8_t);
Device() = default;
void set_location(uint8_t bus, uint8_t dev, uint8_t func);
void initialize(paddr_t pcie_paddr);
bool is_valid() const { return m_is_valid; }
uint32_t read_dword(uint8_t) const;
uint16_t read_word(uint8_t) const;
@@ -103,17 +107,20 @@ namespace Kernel::PCI
void disable_pin_interrupts();
private:
const uint8_t m_bus;
const uint8_t m_dev;
const uint8_t m_func;
bool m_is_valid { false };
uint8_t m_bus { 0 };
uint8_t m_dev { 0 };
uint8_t m_func { 0 };
uint8_t m_class_code;
uint8_t m_subclass;
uint8_t m_prog_if;
vaddr_t m_mmio_config { 0 };
uint8_t m_header_type;
uint16_t m_vendor_id;
uint16_t m_device_id;
uint8_t m_class_code { 0 };
uint8_t m_subclass { 0 };
uint8_t m_prog_if { 0 };
uint8_t m_header_type { 0 };
uint16_t m_vendor_id { 0 };
uint16_t m_device_id { 0 };
uint32_t m_reserved_irqs { 0 };
uint8_t m_reserved_irq_count { 0 };
@@ -131,26 +138,39 @@ namespace Kernel::PCI
static void initialize();
static PCIManager& get();
const BAN::Vector<PCI::Device>& devices() const { return m_devices; }
void initialize_devices();
static uint32_t read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
static uint16_t read_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
static uint8_t read_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
template<typename F>
void for_each_device(F callback)
{
for (auto& bus : m_buses)
for (auto& dev : bus)
for (auto& func : dev)
if (func.is_valid())
callback(func);
};
static void write_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint32_t value);
static void write_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint16_t value);
static void write_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint8_t value);
uint32_t read_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
uint16_t read_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
uint8_t read_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset);
void write_config_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint32_t value);
void write_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint16_t value);
void write_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint8_t value);
private:
PCIManager() = default;
PCIManager() : m_bus_pcie_paddr(0) {}
void check_function(uint8_t bus, uint8_t dev, uint8_t func);
void check_device(uint8_t bus, uint8_t dev);
void check_bus(uint8_t bus);
void check_all_buses();
void initialize_devices();
void initialize_impl();
private:
BAN::Vector<PCI::Device> m_devices;
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
BAN::Array<PCIBus, 256> m_buses;
BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
bool m_is_pcie { false };
};
}