/* * Copyright (c) 2022, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include namespace Kernel::PCI { static Atomic s_vmd_pci_domain_number = 0x10000; NonnullOwnPtr VolumeManagementDevice::must_create(PCI::DeviceIdentifier const& device_identifier) { SpinlockLocker locker(device_identifier.operation_lock()); u8 start_bus = 0; switch ((PCI::read16_locked(device_identifier, static_cast(0x44)) >> 8) & 0x3) { case 0: break; case 1: start_bus = 128; break; case 2: start_bus = 224; break; default: dbgln("VMD @ {}: Unknown bus offset option was set to {}", device_identifier.address(), ((PCI::read16_locked(device_identifier, static_cast(0x44)) >> 8) & 0x3)); VERIFY_NOT_REACHED(); } // FIXME: The end bus might not be 255, so we actually need to check it with the // resource size of BAR0. dbgln("VMD Host bridge @ {}: Start bus at {}, end bus {}", device_identifier.address(), start_bus, 0xff); PCI::Domain domain { s_vmd_pci_domain_number++, start_bus, 0xff }; auto start_address = PhysicalAddress(PCI::get_BAR0(device_identifier)).page_base(); return adopt_own_if_nonnull(new (nothrow) VolumeManagementDevice(domain, start_address)).release_nonnull(); } void VolumeManagementDevice::write8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u8 value) { SpinlockLocker locker(m_config_lock); // Note: We must write then read to ensure completion before returning. MemoryBackedHostBridge::write8_field(bus, device, function, field, value); MemoryBackedHostBridge::read8_field(bus, device, function, field); } void VolumeManagementDevice::write16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u16 value) { SpinlockLocker locker(m_config_lock); // Note: We must write then read to ensure completion before returning. MemoryBackedHostBridge::write16_field(bus, device, function, field, value); MemoryBackedHostBridge::read16_field(bus, device, function, field); } void VolumeManagementDevice::write32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u32 value) { SpinlockLocker locker(m_config_lock); // Note: We must write then read to ensure completion before returning. MemoryBackedHostBridge::write32_field(bus, device, function, field, value); MemoryBackedHostBridge::read32_field(bus, device, function, field); } u8 VolumeManagementDevice::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) { SpinlockLocker locker(m_config_lock); return MemoryBackedHostBridge::read8_field(bus, device, function, field); } u16 VolumeManagementDevice::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) { SpinlockLocker locker(m_config_lock); return MemoryBackedHostBridge::read16_field(bus, device, function, field); } u32 VolumeManagementDevice::read32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) { SpinlockLocker locker(m_config_lock); return MemoryBackedHostBridge::read32_field(bus, device, function, field); } VolumeManagementDevice::VolumeManagementDevice(PCI::Domain const& domain, PhysicalAddress start_address) : MemoryBackedHostBridge(domain, start_address) { } }