summaryrefslogtreecommitdiff
path: root/Kernel/Storage
diff options
context:
space:
mode:
authorMarco Cutecchia <marco.cutecchia@outlook.it>2023-03-23 21:31:01 +0100
committerAndrew Kaster <andrewdkaster@gmail.com>2023-04-02 12:43:17 -0600
commit5fe6c6fc2431fcc1f1690d5af949a425f6c89884 (patch)
treef06805c0eed79da0dcca7016283f47b5d0cb51de /Kernel/Storage
parent47cae8005f1f9a43154d7d830d7ff6edc0f6f301 (diff)
downloadserenity-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.cpp37
-rw-r--r--Kernel/Storage/SD/PCISDHostController.h50
-rw-r--r--Kernel/Storage/StorageManagement.cpp32
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);
+ }
}));
}
}