mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-13 01:59:14 +03:00
Kernel/PCI: Add basic support for the VMD PCI bridge device
This commit is contained in:
parent
df73e8b46b
commit
eb9c8f3895
Notes:
sideshowbarker
2024-07-17 20:26:51 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/eb9c8f38950 Pull-request: https://github.com/SerenityOS/serenity/pull/12063 Reviewed-by: https://github.com/tomuta ✅
@ -108,6 +108,22 @@ UNMAP_AFTER_INIT bool Access::initialize_for_one_pci_domain()
|
||||
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)
|
||||
{
|
||||
auto domain_number = controller->domain_number();
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
Spinlock const& scan_lock() const { return m_scan_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:
|
||||
u8 read8_field(Address address, RegisterOffset field);
|
||||
u16 read16_field(Address address, RegisterOffset field);
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
namespace Kernel::PCI {
|
||||
|
||||
class MemoryBackedHostBridge final : public HostBridge {
|
||||
class MemoryBackedHostBridge : public HostBridge {
|
||||
public:
|
||||
static NonnullOwnPtr<MemoryBackedHostBridge> must_create(Domain const&, PhysicalAddress);
|
||||
|
||||
@ -25,7 +25,7 @@ public:
|
||||
virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||
virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
MemoryBackedHostBridge(PCI::Domain const&, PhysicalAddress);
|
||||
|
||||
// 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
|
||||
Bus/PCI/Controller/HostBridge.cpp
|
||||
Bus/PCI/Controller/MemoryBackedHostBridge.cpp
|
||||
Bus/PCI/Controller/VolumeManagementDevice.cpp
|
||||
Bus/PCI/Access.cpp
|
||||
Bus/PCI/API.cpp
|
||||
Bus/PCI/Device.cpp
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <AK/UUID.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/Access.h>
|
||||
#include <Kernel/Bus/PCI/Controller/VolumeManagementDevice.h>
|
||||
#include <Kernel/CommandLine.h>
|
||||
#include <Kernel/Devices/BlockDevice.h>
|
||||
#include <Kernel/FileSystem/Ext2FileSystem.h>
|
||||
@ -55,6 +56,24 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
|
||||
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());
|
||||
if (subclass_code == SubclassID::IDEController && kernel_command_line().is_ide_enabled()) {
|
||||
m_controllers.append(IDEController::initialize(device_identifier, force_pio));
|
||||
|
Loading…
Reference in New Issue
Block a user