/* * Copyright (c) 2022, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Kernel::PCI { AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, BusNumber); AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, DeviceNumber); AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, FunctionNumber); struct PCIInterruptSpecifier { u8 interrupt_pin { 0 }; FunctionNumber function { 0 }; DeviceNumber device { 0 }; BusNumber bus { 0 }; bool operator==(PCIInterruptSpecifier const& other) const { return bus == other.bus && device == other.device && function == other.function && interrupt_pin == other.interrupt_pin; } PCIInterruptSpecifier operator&(PCIInterruptSpecifier other) const { return PCIInterruptSpecifier { .interrupt_pin = static_cast(interrupt_pin & other.interrupt_pin), .function = function.value() & other.function.value(), .device = device.value() & other.device.value(), .bus = bus.value() & other.bus.value(), }; } PCIInterruptSpecifier& operator&=(PCIInterruptSpecifier const& other) { *this = *this & other; return *this; } }; } namespace AK { template<> struct Traits : public DefaultTraits { static unsigned hash(Kernel::PCI::PCIInterruptSpecifier value) { return int_hash(value.bus.value() << 24 | value.device.value() << 16 | value.function.value() << 8 | value.interrupt_pin); } }; } namespace Kernel::PCI { struct PCIConfiguration { FlatPtr mmio_32bit_base { 0 }; FlatPtr mmio_32bit_end { 0 }; FlatPtr mmio_64bit_base { 0 }; FlatPtr mmio_64bit_end { 0 }; // The keys contains the bus, device & function at the same offsets as OpenFirmware PCI addresses, // with the least significant 8 bits being the interrupt pin. HashMap masked_interrupt_mapping; PCIInterruptSpecifier interrupt_mask; }; class HostController { public: virtual ~HostController() = default; void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value); void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value); void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value); u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field); u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field); u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field); u32 domain_number() const { return m_domain.domain_number(); } void enumerate_attached_devices(Function callback, Function post_bridge_callback = nullptr); void configure_attached_devices(PCIConfiguration&); private: void enumerate_bus(Function const& callback, Function& post_bridge_callback, BusNumber, bool recursive_search_into_bridges); void enumerate_functions(Function const& callback, Function& post_bridge_callback, BusNumber, DeviceNumber, FunctionNumber, bool recursive_search_into_bridges); void enumerate_device(Function const& callback, Function& post_bridge_callback, BusNumber bus, DeviceNumber device, bool recursive_search_into_bridges); void write8_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field, u8 value); void write16_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field, u16 value); void write32_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field, u32 value); u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field); u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field); Optional get_capabilities_pointer_for_function(BusNumber, DeviceNumber, FunctionNumber); Vector get_capabilities_for_function(BusNumber, DeviceNumber, FunctionNumber); protected: virtual void write8_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) = 0; virtual void write16_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) = 0; virtual void write32_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) = 0; virtual u8 read8_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; virtual u16 read16_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; virtual u32 read32_field_locked(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; explicit HostController(PCI::Domain const& domain); const PCI::Domain m_domain; Spinlock m_access_lock; private: Bitmap m_enumerated_buses; }; }