diff options
author | Marco Cutecchia <marco.cutecchia@outlook.it> | 2023-03-23 21:31:01 +0100 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2023-04-02 12:43:17 -0600 |
commit | 5fe6c6fc2431fcc1f1690d5af949a425f6c89884 (patch) | |
tree | f06805c0eed79da0dcca7016283f47b5d0cb51de /Kernel/Storage | |
parent | 47cae8005f1f9a43154d7d830d7ff6edc0f6f301 (diff) | |
download | serenity-5fe6c6fc2431fcc1f1690d5af949a425f6c89884.zip |
Kernel: Add support for SD host controllers on the PCI bus
Diffstat (limited to 'Kernel/Storage')
-rw-r--r-- | Kernel/Storage/SD/PCISDHostController.cpp | 37 | ||||
-rw-r--r-- | Kernel/Storage/SD/PCISDHostController.h | 50 | ||||
-rw-r--r-- | Kernel/Storage/StorageManagement.cpp | 32 |
3 files changed, 114 insertions, 5 deletions
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 <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(); +} + +} 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 <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; +}; + +} 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 <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); + } })); } } |