mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 14:27:35 +00:00
Kernel/PCI: Add basic support for the VMD PCI bridge device
This commit is contained in:
parent
df73e8b46b
commit
eb9c8f3895
7 changed files with 161 additions and 2 deletions
|
@ -108,6 +108,22 @@ UNMAP_AFTER_INIT bool Access::initialize_for_one_pci_domain()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Access::add_host_controller_and_enumerate_attached_devices(NonnullOwnPtr<HostController> controller, Function<void(DeviceIdentifier const&)> callback)
|
||||||
|
{
|
||||||
|
MutexLocker locker(m_access_lock);
|
||||||
|
SpinlockLocker scan_locker(m_scan_lock);
|
||||||
|
auto domain_number = controller->domain_number();
|
||||||
|
|
||||||
|
VERIFY(!m_host_controllers.contains(domain_number));
|
||||||
|
// Note: We need to register the new controller as soon as possible, and
|
||||||
|
// definitely before enumerating devices behing that.
|
||||||
|
m_host_controllers.set(domain_number, move(controller));
|
||||||
|
m_host_controllers.get(domain_number).value()->enumerate_attached_devices([&](DeviceIdentifier const& device_identifier) -> void {
|
||||||
|
m_device_identifiers.append(device_identifier);
|
||||||
|
callback(device_identifier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
UNMAP_AFTER_INIT void Access::add_host_controller(NonnullOwnPtr<HostController> controller)
|
UNMAP_AFTER_INIT void Access::add_host_controller(NonnullOwnPtr<HostController> controller)
|
||||||
{
|
{
|
||||||
auto domain_number = controller->domain_number();
|
auto domain_number = controller->domain_number();
|
||||||
|
|
|
@ -38,6 +38,8 @@ public:
|
||||||
Spinlock const& scan_lock() const { return m_scan_lock; }
|
Spinlock const& scan_lock() const { return m_scan_lock; }
|
||||||
Mutex const& access_lock() const { return m_access_lock; }
|
Mutex const& access_lock() const { return m_access_lock; }
|
||||||
|
|
||||||
|
void add_host_controller_and_enumerate_attached_devices(NonnullOwnPtr<HostController>, Function<void(DeviceIdentifier const&)> callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u8 read8_field(Address address, RegisterOffset field);
|
u8 read8_field(Address address, RegisterOffset field);
|
||||||
u16 read16_field(Address address, RegisterOffset field);
|
u16 read16_field(Address address, RegisterOffset field);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace Kernel::PCI {
|
namespace Kernel::PCI {
|
||||||
|
|
||||||
class MemoryBackedHostBridge final : public HostBridge {
|
class MemoryBackedHostBridge : public HostBridge {
|
||||||
public:
|
public:
|
||||||
static NonnullOwnPtr<MemoryBackedHostBridge> must_create(Domain const&, PhysicalAddress);
|
static NonnullOwnPtr<MemoryBackedHostBridge> must_create(Domain const&, PhysicalAddress);
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ public:
|
||||||
virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||||
virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
MemoryBackedHostBridge(PCI::Domain const&, PhysicalAddress);
|
MemoryBackedHostBridge(PCI::Domain const&, PhysicalAddress);
|
||||||
|
|
||||||
// Memory-mapped access operations
|
// Memory-mapped access operations
|
||||||
|
|
86
Kernel/Bus/PCI/Controller/VolumeManagementDevice.cpp
Normal file
86
Kernel/Bus/PCI/Controller/VolumeManagementDevice.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/ByteReader.h>
|
||||||
|
#include <Kernel/Arch/x86/IO.h>
|
||||||
|
#include <Kernel/Bus/PCI/API.h>
|
||||||
|
#include <Kernel/Bus/PCI/Access.h>
|
||||||
|
#include <Kernel/Bus/PCI/Controller/VolumeManagementDevice.h>
|
||||||
|
|
||||||
|
namespace Kernel::PCI {
|
||||||
|
|
||||||
|
static Atomic<u32> s_vmd_pci_domain_number = 0x10000;
|
||||||
|
|
||||||
|
NonnullOwnPtr<VolumeManagementDevice> VolumeManagementDevice::must_create(PCI::DeviceIdentifier const& device_identifier)
|
||||||
|
{
|
||||||
|
u8 start_bus = 0;
|
||||||
|
switch ((PCI::read16(device_identifier.address(), static_cast<PCI::RegisterOffset>(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(device_identifier.address(), static_cast<PCI::RegisterOffset>(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.address())).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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Kernel/Bus/PCI/Controller/VolumeManagementDevice.h
Normal file
35
Kernel/Bus/PCI/Controller/VolumeManagementDevice.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Bitmap.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h>
|
||||||
|
#include <Kernel/Locking/Spinlock.h>
|
||||||
|
|
||||||
|
namespace Kernel::PCI {
|
||||||
|
|
||||||
|
class VolumeManagementDevice final : public MemoryBackedHostBridge {
|
||||||
|
public:
|
||||||
|
static NonnullOwnPtr<VolumeManagementDevice> must_create(PCI::DeviceIdentifier const& device_identifier);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VolumeManagementDevice(PCI::Domain const&, PhysicalAddress);
|
||||||
|
|
||||||
|
virtual void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) override;
|
||||||
|
virtual void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) override;
|
||||||
|
virtual void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) override;
|
||||||
|
virtual u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||||
|
virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||||
|
virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||||
|
|
||||||
|
// Note: All read and writes must be done with a spinlock because
|
||||||
|
// Linux says that CPU might deadlock otherwise if access is not serialized.
|
||||||
|
Spinlock m_config_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ set(KERNEL_SOURCES
|
||||||
AddressSanitizer.cpp
|
AddressSanitizer.cpp
|
||||||
Bus/PCI/Controller/HostBridge.cpp
|
Bus/PCI/Controller/HostBridge.cpp
|
||||||
Bus/PCI/Controller/MemoryBackedHostBridge.cpp
|
Bus/PCI/Controller/MemoryBackedHostBridge.cpp
|
||||||
|
Bus/PCI/Controller/VolumeManagementDevice.cpp
|
||||||
Bus/PCI/Access.cpp
|
Bus/PCI/Access.cpp
|
||||||
Bus/PCI/API.cpp
|
Bus/PCI/API.cpp
|
||||||
Bus/PCI/Device.cpp
|
Bus/PCI/Device.cpp
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <AK/UUID.h>
|
#include <AK/UUID.h>
|
||||||
#include <Kernel/Bus/PCI/API.h>
|
#include <Kernel/Bus/PCI/API.h>
|
||||||
#include <Kernel/Bus/PCI/Access.h>
|
#include <Kernel/Bus/PCI/Access.h>
|
||||||
|
#include <Kernel/Bus/PCI/Controller/VolumeManagementDevice.h>
|
||||||
#include <Kernel/CommandLine.h>
|
#include <Kernel/CommandLine.h>
|
||||||
#include <Kernel/Devices/BlockDevice.h>
|
#include <Kernel/Devices/BlockDevice.h>
|
||||||
#include <Kernel/FileSystem/Ext2FileSystem.h>
|
#include <Kernel/FileSystem/Ext2FileSystem.h>
|
||||||
|
@ -55,6 +56,24 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
static constexpr PCI::HardwareID vmd_device = { 0x8086, 0x9a0b };
|
||||||
|
if (device_identifier.hardware_id() == vmd_device) {
|
||||||
|
auto controller = PCI::VolumeManagementDevice::must_create(device_identifier);
|
||||||
|
PCI::Access::the().add_host_controller_and_enumerate_attached_devices(move(controller), [this](PCI::DeviceIdentifier const& device_identifier) -> void {
|
||||||
|
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||||
|
if (subclass_code == SubclassID::NVMeController) {
|
||||||
|
auto controller = NVMeController::try_initialize(device_identifier);
|
||||||
|
if (controller.is_error()) {
|
||||||
|
dmesgln("Unable to initialize NVMe controller: {}", controller.error());
|
||||||
|
} else {
|
||||||
|
m_controllers.append(controller.release_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||||
if (subclass_code == SubclassID::IDEController && kernel_command_line().is_ide_enabled()) {
|
if (subclass_code == SubclassID::IDEController && kernel_command_line().is_ide_enabled()) {
|
||||||
m_controllers.append(IDEController::initialize(device_identifier, force_pio));
|
m_controllers.append(IDEController::initialize(device_identifier, force_pio));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue