diff --git a/Kernel/Bus/PCI/Definitions.h b/Kernel/Bus/PCI/Definitions.h index 8591e3f61e..4825268dec 100644 --- a/Kernel/Bus/PCI/Definitions.h +++ b/Kernel/Bus/PCI/Definitions.h @@ -79,6 +79,9 @@ static constexpr size_t mmio_device_space_size = 4096; static constexpr u16 none_value = 0xffff; static constexpr size_t memory_range_per_bus = mmio_device_space_size * to_underlying(Limits::MaxFunctionsPerDevice) * to_underlying(Limits::MaxDevicesPerBus); static constexpr u32 bar_address_mask = 0xfffffff0; +static constexpr u16 msix_control_table_mask = 0x07ff; +static constexpr u8 msix_table_bir_mask = 0x7; +static constexpr u16 msix_table_offset_mask = 0xfff8; // Taken from https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf enum class ClassID { @@ -319,6 +322,22 @@ protected: Vector m_capabilities; }; +class MSIxInfo { +public: + MSIxInfo(u16 table_size, u8 table_bar, u32 table_offset) + : table_size(table_size) + , table_bar(table_bar) + , table_offset(table_offset) + { + } + + MSIxInfo() = default; + + u16 table_size {}; + u8 table_bar {}; + u32 table_offset {}; +}; + class DeviceIdentifier : public RefCounted , public EnumerableDeviceIdentifier { @@ -327,6 +346,11 @@ class DeviceIdentifier public: static ErrorOr> from_enumerable_identifier(EnumerableDeviceIdentifier const& other_identifier); + void initialize(); + bool is_msix_capable() const { return m_msix_info.table_size > 0; } + u8 get_msix_table_bar() const { return m_msix_info.table_bar; } + u32 get_msix_table_offset() const { return m_msix_info.table_offset; } + Spinlock& operation_lock() { return m_operation_lock; } Spinlock& operation_lock() const { return m_operation_lock; } @@ -349,6 +373,7 @@ private: } mutable Spinlock m_operation_lock; + MSIxInfo m_msix_info {}; }; class Domain; diff --git a/Kernel/Bus/PCI/Device.cpp b/Kernel/Bus/PCI/Device.cpp index 6f0149d177..28761b2ca5 100644 --- a/Kernel/Bus/PCI/Device.cpp +++ b/Kernel/Bus/PCI/Device.cpp @@ -13,6 +13,7 @@ namespace Kernel::PCI { Device::Device(DeviceIdentifier const& pci_identifier) : m_pci_identifier(pci_identifier) { + m_pci_identifier->initialize(); } bool Device::is_msi_capable() const diff --git a/Kernel/Bus/PCI/Device.h b/Kernel/Bus/PCI/Device.h index 1f6a22877e..bb75f75f0a 100644 --- a/Kernel/Bus/PCI/Device.h +++ b/Kernel/Bus/PCI/Device.h @@ -38,7 +38,7 @@ protected: explicit Device(DeviceIdentifier const& pci_identifier); private: - NonnullRefPtr const m_pci_identifier; + NonnullRefPtr const m_pci_identifier; }; template diff --git a/Kernel/Bus/PCI/DeviceIdentifier.cpp b/Kernel/Bus/PCI/DeviceIdentifier.cpp index 785dfebff8..ee07737402 100644 --- a/Kernel/Bus/PCI/DeviceIdentifier.cpp +++ b/Kernel/Bus/PCI/DeviceIdentifier.cpp @@ -17,4 +17,16 @@ ErrorOr> DeviceIdentifier::from_enumerable_ident return adopt_nonnull_ref_or_enomem(new (nothrow) DeviceIdentifier(other_identifier)); } +void DeviceIdentifier::initialize() +{ + for (auto cap : capabilities()) { + if (cap.id() == PCI::Capabilities::ID::MSIX) { + auto msix_bir_bar = (cap.read8(4) & msix_table_bir_mask); + auto msix_bir_offset = (cap.read32(4) & msix_table_offset_mask); + auto msix_count = (cap.read16(2) & msix_control_table_mask) + 1; + m_msix_info = MSIxInfo(msix_count, msix_bir_bar, msix_bir_offset); + } + } +} + }