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:
@@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user