Kernel: Add support for SD host controllers on the PCI bus

This commit is contained in:
Marco Cutecchia 2023-03-23 21:31:01 +01:00 committed by Andrew Kaster
parent 47cae8005f
commit 5fe6c6fc24
Notes: sideshowbarker 2024-07-17 04:49:48 +09:00
5 changed files with 124 additions and 5 deletions

View file

@ -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 {

View file

@ -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

View 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();
}
}

View 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;
};
}

View file

@ -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);
}
}));
}
}