From 5fe6c6fc2431fcc1f1690d5af949a425f6c89884 Mon Sep 17 00:00:00 2001 From: Marco Cutecchia Date: Thu, 23 Mar 2023 21:31:01 +0100 Subject: [PATCH] Kernel: Add support for SD host controllers on the PCI bus --- Kernel/Bus/PCI/Definitions.h | 9 ++++ Kernel/CMakeLists.txt | 1 + Kernel/Storage/SD/PCISDHostController.cpp | 37 +++++++++++++++++ Kernel/Storage/SD/PCISDHostController.h | 50 +++++++++++++++++++++++ Kernel/Storage/StorageManagement.cpp | 32 ++++++++++++--- 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 Kernel/Storage/SD/PCISDHostController.cpp create mode 100644 Kernel/Storage/SD/PCISDHostController.h diff --git a/Kernel/Bus/PCI/Definitions.h b/Kernel/Bus/PCI/Definitions.h index 58744cecc6..8a5bf8d8dd 100644 --- a/Kernel/Bus/PCI/Definitions.h +++ b/Kernel/Bus/PCI/Definitions.h @@ -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 { diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 16a5636161..03aa968da2 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -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 diff --git a/Kernel/Storage/SD/PCISDHostController.cpp b/Kernel/Storage/SD/PCISDHostController.cpp new file mode 100644 index 0000000000..4b383aa7d4 --- /dev/null +++ b/Kernel/Storage/SD/PCISDHostController.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Kernel { + +ErrorOr> 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(slot_information_register.first_bar_number)) + }; + m_registers = Memory::map_typed_writable(physical_address_of_sdhc_registers).release_value_but_fixme_should_propagate_errors(); +} + +} diff --git a/Kernel/Storage/SD/PCISDHostController.h b/Kernel/Storage/SD/PCISDHostController.h new file mode 100644 index 0000000000..b629b945d6 --- /dev/null +++ b/Kernel/Storage/SD/PCISDHostController.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Kernel { + +class PCISDHostController : public PCI::Device + , public SDHostController { +public: + static ErrorOr> 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 read_slot_information() const + { + SpinlockLocker locker(device_identifier().operation_lock()); + return bit_cast(PCI::Access::the().read8_field(device_identifier(), 0x40)); + } + + Memory::TypedMapping m_registers; +}; + +} diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index 5df9a741ef..3d982bc78a 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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(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(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); + } })); } }