123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- /*
- * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/Badge.h>
- #include <AK/DistinctNumeric.h>
- #include <AK/Function.h>
- #include <AK/Types.h>
- #include <AK/Vector.h>
- #include <Kernel/Debug.h>
- #include <Kernel/Locking/Spinlock.h>
- #include <Kernel/PhysicalAddress.h>
- namespace Kernel::PCI {
- enum class HeaderType {
- Device = 0,
- Bridge = 1,
- };
- enum class HeaderType0BaseRegister {
- BAR0 = 0,
- BAR1,
- BAR2,
- BAR3,
- BAR4,
- BAR5,
- };
- enum class BARSpaceType {
- IOSpace,
- Memory16BitSpace,
- Memory32BitSpace,
- Memory64BitSpace,
- };
- enum class RegisterOffset {
- VENDOR_ID = 0x00, // word
- DEVICE_ID = 0x02, // word
- COMMAND = 0x04, // word
- STATUS = 0x06, // word
- REVISION_ID = 0x08, // byte
- PROG_IF = 0x09, // byte
- SUBCLASS = 0x0a, // byte
- CLASS = 0x0b, // byte
- CACHE_LINE_SIZE = 0x0c, // byte
- LATENCY_TIMER = 0x0d, // byte
- HEADER_TYPE = 0x0e, // byte
- BIST = 0x0f, // byte
- BAR0 = 0x10, // u32
- BAR1 = 0x14, // u32
- BAR2 = 0x18, // u32
- SECONDARY_BUS = 0x19, // byte
- BAR3 = 0x1C, // u32
- BAR4 = 0x20, // u32
- BAR5 = 0x24, // u32
- SUBSYSTEM_VENDOR_ID = 0x2C, // u16
- SUBSYSTEM_ID = 0x2E, // u16
- EXPANSION_ROM_POINTER = 0x30, // u32
- CAPABILITIES_POINTER = 0x34, // u8
- INTERRUPT_LINE = 0x3C, // byte
- INTERRUPT_PIN = 0x3D, // byte
- };
- enum class Limits {
- MaxDevicesPerBus = 32,
- MaxBusesPerDomain = 256,
- MaxFunctionsPerDevice = 8,
- };
- static constexpr u16 address_port = 0xcf8;
- static constexpr u16 value_port = 0xcfc;
- 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);
- // Taken from https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf
- enum class ClassID {
- MassStorage = 0x1,
- Multimedia = 0x4,
- Bridge = 0x6,
- };
- namespace MassStorage {
- enum class SubclassID {
- IDEController = 0x1,
- SATAController = 0x6,
- NVMeController = 0x8,
- };
- enum class SATAProgIF {
- AHCI = 0x1,
- };
- }
- namespace Multimedia {
- enum class SubclassID {
- AudioController = 0x1,
- };
- }
- namespace Bridge {
- enum class SubclassID {
- PCI_TO_PCI = 0x4,
- };
- }
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, CapabilityID);
- namespace Capabilities {
- enum ID {
- Null = 0x0,
- MSI = 0x5,
- VendorSpecific = 0x9,
- MSIX = 0x11,
- };
- }
- struct HardwareID {
- u16 vendor_id { 0 };
- u16 device_id { 0 };
- bool is_null() const { return !vendor_id && !device_id; }
- bool operator==(HardwareID const& other) const
- {
- return vendor_id == other.vendor_id && device_id == other.device_id;
- }
- bool operator!=(HardwareID const& other) const
- {
- return vendor_id != other.vendor_id || device_id != other.device_id;
- }
- };
- class Domain {
- public:
- Domain() = delete;
- Domain(u32 domain_number, u8 start_bus, u8 end_bus)
- : m_domain_number(domain_number)
- , m_start_bus(start_bus)
- , m_end_bus(end_bus)
- {
- }
- u8 start_bus() const { return m_start_bus; }
- u8 end_bus() const { return m_end_bus; }
- u32 domain_number() const { return m_domain_number; }
- private:
- u32 m_domain_number;
- u8 m_start_bus;
- u8 m_end_bus;
- };
- struct Address {
- public:
- Address() = default;
- Address(u32 domain)
- : m_domain(domain)
- , m_bus(0)
- , m_device(0)
- , m_function(0)
- {
- }
- Address(u32 domain, u8 bus, u8 device, u8 function)
- : m_domain(domain)
- , m_bus(bus)
- , m_device(device)
- , m_function(function)
- {
- }
- Address(Address const& address) = default;
- bool is_null() const { return !m_bus && !m_device && !m_function; }
- operator bool() const { return !is_null(); }
- // Disable default implementations that would use surprising integer promotion.
- bool operator<=(Address const&) const = delete;
- bool operator>=(Address const&) const = delete;
- bool operator<(Address const&) const = delete;
- bool operator>(Address const&) const = delete;
- bool operator==(Address const& other) const
- {
- if (this == &other)
- return true;
- return m_domain == other.m_domain && m_bus == other.m_bus && m_device == other.m_device && m_function == other.m_function;
- }
- bool operator!=(Address const& other) const
- {
- return !(*this == other);
- }
- u32 domain() const { return m_domain; }
- u8 bus() const { return m_bus; }
- u8 device() const { return m_device; }
- u8 function() const { return m_function; }
- private:
- u32 m_domain { 0 };
- u8 m_bus { 0 };
- u8 m_device { 0 };
- u8 m_function { 0 };
- };
- class Capability {
- public:
- Capability(Address address, u8 id, u8 ptr)
- : m_address(address)
- , m_id(id)
- , m_ptr(ptr)
- {
- }
- CapabilityID id() const { return m_id; }
- u8 read8(size_t offset) const;
- u16 read16(size_t offset) const;
- u32 read32(size_t offset) const;
- private:
- const Address m_address;
- const CapabilityID m_id;
- const u8 m_ptr;
- };
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, ClassCode);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, SubclassCode);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, ProgrammingInterface);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, RevisionID);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemID);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemVendorID);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptLine);
- AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptPin);
- class Access;
- class EnumerableDeviceIdentifier {
- public:
- EnumerableDeviceIdentifier(Address address, HardwareID hardware_id, RevisionID revision_id, ClassCode class_code, SubclassCode subclass_code, ProgrammingInterface prog_if, SubsystemID subsystem_id, SubsystemVendorID subsystem_vendor_id, InterruptLine interrupt_line, InterruptPin interrupt_pin, Vector<Capability> const& capabilities)
- : m_address(address)
- , m_hardware_id(hardware_id)
- , m_revision_id(revision_id)
- , m_class_code(class_code)
- , m_subclass_code(subclass_code)
- , m_prog_if(prog_if)
- , m_subsystem_id(subsystem_id)
- , m_subsystem_vendor_id(subsystem_vendor_id)
- , m_interrupt_line(interrupt_line)
- , m_interrupt_pin(interrupt_pin)
- , m_capabilities(capabilities)
- {
- if constexpr (PCI_DEBUG) {
- for (auto const& capability : capabilities)
- dbgln("{} has capability {}", address, capability.id());
- }
- }
- Vector<Capability> const& capabilities() const { return m_capabilities; }
- HardwareID const& hardware_id() const { return m_hardware_id; }
- Address const& address() const { return m_address; }
- RevisionID revision_id() const { return m_revision_id; }
- ClassCode class_code() const { return m_class_code; }
- SubclassCode subclass_code() const { return m_subclass_code; }
- ProgrammingInterface prog_if() const { return m_prog_if; }
- SubsystemID subsystem_id() const { return m_subsystem_id; }
- SubsystemVendorID subsystem_vendor_id() const { return m_subsystem_vendor_id; }
- InterruptLine interrupt_line() const { return m_interrupt_line; }
- InterruptPin interrupt_pin() const { return m_interrupt_pin; }
- void apply_subclass_code_change(Badge<Access>, SubclassCode new_subclass)
- {
- m_subclass_code = new_subclass;
- }
- void apply_prog_if_change(Badge<Access>, ProgrammingInterface new_progif)
- {
- m_prog_if = new_progif;
- }
- protected:
- Address m_address;
- HardwareID m_hardware_id;
- RevisionID m_revision_id;
- ClassCode m_class_code;
- SubclassCode m_subclass_code;
- ProgrammingInterface m_prog_if;
- SubsystemID m_subsystem_id;
- SubsystemVendorID m_subsystem_vendor_id;
- InterruptLine m_interrupt_line;
- InterruptPin m_interrupt_pin;
- Vector<Capability> m_capabilities;
- };
- class DeviceIdentifier
- : public RefCounted<DeviceIdentifier>
- , public EnumerableDeviceIdentifier {
- AK_MAKE_NONCOPYABLE(DeviceIdentifier);
- public:
- static ErrorOr<NonnullRefPtr<DeviceIdentifier>> from_enumerable_identifier(EnumerableDeviceIdentifier const& other_identifier);
- Spinlock<LockRank::None>& operation_lock() { return m_operation_lock; }
- Spinlock<LockRank::None>& operation_lock() const { return m_operation_lock; }
- virtual ~DeviceIdentifier() = default;
- private:
- DeviceIdentifier(EnumerableDeviceIdentifier const& other_identifier)
- : EnumerableDeviceIdentifier(other_identifier.address(),
- other_identifier.hardware_id(),
- other_identifier.revision_id(),
- other_identifier.class_code(),
- other_identifier.subclass_code(),
- other_identifier.prog_if(),
- other_identifier.subsystem_id(),
- other_identifier.subsystem_vendor_id(),
- other_identifier.interrupt_line(),
- other_identifier.interrupt_pin(),
- other_identifier.capabilities())
- {
- }
- mutable Spinlock<LockRank::None> m_operation_lock;
- };
- class Domain;
- class Device;
- }
- template<>
- struct AK::Formatter<Kernel::PCI::Address> : Formatter<FormatString> {
- ErrorOr<void> format(FormatBuilder& builder, Kernel::PCI::Address value)
- {
- return Formatter<FormatString>::format(
- builder,
- "PCI [{:04x}:{:02x}:{:02x}:{:02x}]"sv, value.domain(), value.bus(), value.device(), value.function());
- }
- };
- template<>
- struct AK::Formatter<Kernel::PCI::HardwareID> : Formatter<FormatString> {
- ErrorOr<void> format(FormatBuilder& builder, Kernel::PCI::HardwareID value)
- {
- return Formatter<FormatString>::format(
- builder,
- "PCI::HardwareID [{:04x}:{:04x}]"sv, value.vendor_id, value.device_id);
- }
- };
|