Kernel: Add support for SD host controllers on the PCI bus
This commit is contained in:
parent
47cae8005f
commit
5fe6c6fc24
Notes:
sideshowbarker
2024-07-17 04:49:48 +09:00
Author: https://github.com/mrkct Commit: https://github.com/SerenityOS/serenity/commit/5fe6c6fc24 Pull-request: https://github.com/SerenityOS/serenity/pull/18139 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/Hendiadyoin1 Reviewed-by: https://github.com/supercomputer7 ✅
5 changed files with 124 additions and 5 deletions
|
@ -84,6 +84,7 @@ enum class ClassID {
|
|||
MassStorage = 0x1,
|
||||
Multimedia = 0x4,
|
||||
Bridge = 0x6,
|
||||
Base = 0x8,
|
||||
};
|
||||
|
||||
namespace MassStorage {
|
||||
|
@ -116,6 +117,14 @@ enum class SubclassID {
|
|||
|
||||
}
|
||||
|
||||
namespace Base {
|
||||
|
||||
enum class SubclassID {
|
||||
SDHostController = 0x5,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, CapabilityID);
|
||||
|
||||
namespace Capabilities {
|
||||
|
|
|
@ -112,6 +112,7 @@ set(KERNEL_SOURCES
|
|||
Storage/NVMe/NVMeInterruptQueue.cpp
|
||||
Storage/NVMe/NVMePollQueue.cpp
|
||||
Storage/NVMe/NVMeQueue.cpp
|
||||
Storage/SD/PCISDHostController.cpp
|
||||
Storage/SD/SDHostController.cpp
|
||||
Storage/SD/SDMemoryCard.cpp
|
||||
Storage/DiskPartition.cpp
|
||||
|
|
37
Kernel/Storage/SD/PCISDHostController.cpp
Normal file
37
Kernel/Storage/SD/PCISDHostController.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2023, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Storage/SD/PCISDHostController.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ErrorOr<NonnullRefPtr<PCISDHostController>> PCISDHostController::try_initialize(PCI::DeviceIdentifier const& device_identifier)
|
||||
{
|
||||
auto sdhc = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) PCISDHostController(device_identifier)));
|
||||
TRY(sdhc->initialize());
|
||||
|
||||
return sdhc;
|
||||
}
|
||||
|
||||
PCISDHostController::PCISDHostController(PCI::DeviceIdentifier const& device_identifier)
|
||||
: PCI::Device(device_identifier)
|
||||
, SDHostController()
|
||||
{
|
||||
auto slot_information_register = read_slot_information();
|
||||
|
||||
if (slot_information_register.slots_available() != 1) {
|
||||
// TODO: Support multiple slots
|
||||
dmesgln("SD Host Controller has {} slots, but we currently only support using only one", slot_information_register.slots_available());
|
||||
}
|
||||
|
||||
auto physical_address_of_sdhc_registers = PhysicalAddress {
|
||||
PCI::get_BAR(device_identifier, static_cast<PCI::HeaderType0BaseRegister>(slot_information_register.first_bar_number))
|
||||
};
|
||||
m_registers = Memory::map_typed_writable<SD::HostControlRegisterMap volatile>(physical_address_of_sdhc_registers).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
}
|
50
Kernel/Storage/SD/PCISDHostController.h
Normal file
50
Kernel/Storage/SD/PCISDHostController.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2023, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/Device.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
#include <Kernel/Storage/SD/SDHostController.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class PCISDHostController : public PCI::Device
|
||||
, public SDHostController {
|
||||
public:
|
||||
static ErrorOr<NonnullRefPtr<PCISDHostController>> try_initialize(PCI::DeviceIdentifier const& device_identifier);
|
||||
|
||||
// ^PCI::Device
|
||||
virtual StringView device_name() const override { return "SD Host Controller"sv; }
|
||||
|
||||
protected:
|
||||
// ^SDHostController
|
||||
virtual SD::HostControlRegisterMap volatile* get_register_map_base_address() override { return m_registers.ptr(); }
|
||||
|
||||
private:
|
||||
PCISDHostController(PCI::DeviceIdentifier const& device_identifier);
|
||||
|
||||
struct [[gnu::packed]] SlotInformationRegister {
|
||||
u8 first_bar_number : 3;
|
||||
u8 : 1;
|
||||
u8 number_of_slots : 3;
|
||||
u8 : 1;
|
||||
|
||||
u8 slots_available() const { return number_of_slots + 1; }
|
||||
};
|
||||
static_assert(AssertSize<SlotInformationRegister, 1>());
|
||||
|
||||
SlotInformationRegister read_slot_information() const
|
||||
{
|
||||
SpinlockLocker locker(device_identifier().operation_lock());
|
||||
return bit_cast<SlotInformationRegister>(PCI::Access::the().read8_field(device_identifier(), 0x40));
|
||||
}
|
||||
|
||||
Memory::TypedMapping<SD::HostControlRegisterMap volatile> m_registers;
|
||||
};
|
||||
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include <Kernel/Storage/ATA/AHCI/Controller.h>
|
||||
#include <Kernel/Storage/ATA/GenericIDE/Controller.h>
|
||||
#include <Kernel/Storage/NVMe/NVMeController.h>
|
||||
#include <Kernel/Storage/SD/PCISDHostController.h>
|
||||
#include <Kernel/Storage/SD/SDHostController.h>
|
||||
#include <Kernel/Storage/StorageManagement.h>
|
||||
#include <LibPartition/EBRPartitionTable.h>
|
||||
|
@ -88,7 +89,6 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
|||
{
|
||||
VERIFY(m_controllers.is_empty());
|
||||
|
||||
using SubclassID = PCI::MassStorage::SubclassID;
|
||||
if (!kernel_command_line().disable_physical_storage()) {
|
||||
// NOTE: Search for VMD devices before actually searching for storage controllers
|
||||
// because the VMD device is only a bridge to such (NVMe) controllers.
|
||||
|
@ -100,10 +100,8 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
|||
}
|
||||
}));
|
||||
|
||||
MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void {
|
||||
if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::MassStorage)) {
|
||||
return;
|
||||
}
|
||||
auto const& handle_mass_storage_device = [&](PCI::DeviceIdentifier const& device_identifier) {
|
||||
using SubclassID = PCI::MassStorage::SubclassID;
|
||||
|
||||
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||
#if ARCH(X86_64)
|
||||
|
@ -135,6 +133,30 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
|||
m_controllers.append(controller.release_value());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto const& handle_base_device = [&](PCI::DeviceIdentifier const& device_identifier) {
|
||||
using SubclassID = PCI::Base::SubclassID;
|
||||
|
||||
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||
if (subclass_code == SubclassID::SDHostController) {
|
||||
|
||||
auto sdhc_or_error = PCISDHostController::try_initialize(device_identifier);
|
||||
if (sdhc_or_error.is_error()) {
|
||||
dmesgln("PCI: Failed to initialize SD Host Controller ({} - {}): {}", device_identifier.address(), device_identifier.hardware_id(), sdhc_or_error.error());
|
||||
} else {
|
||||
m_controllers.append(sdhc_or_error.release_value());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void {
|
||||
auto class_code = device_identifier.class_code().value();
|
||||
if (class_code == to_underlying(PCI::ClassID::MassStorage)) {
|
||||
handle_mass_storage_device(device_identifier);
|
||||
} else if (class_code == to_underlying(PCI::ClassID::Base)) {
|
||||
handle_base_device(device_identifier);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue