Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel: Introduce a new model for writing devicetree drivers #25192

Merged
merged 5 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions Kernel/Arch/aarch64/InterruptManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <AK/NeverDestroyed.h>
#include <Kernel/Arch/aarch64/InterruptManagement.h>
#include <Kernel/Arch/aarch64/RPi/InterruptController.h>
#include <Kernel/Library/Panic.h>

namespace Kernel {

static NeverDestroyed<Vector<DeviceTree::DeviceRecipe<NonnullLockRefPtr<IRQController>>>> s_recipes;
static InterruptManagement* s_interrupt_management;

bool InterruptManagement::initialized()
Expand All @@ -31,10 +34,25 @@ void InterruptManagement::initialize()
the().find_controllers();
}

void InterruptManagement::add_recipe(DeviceTree::DeviceRecipe<NonnullLockRefPtr<IRQController>> recipe)
{
s_recipes->append(move(recipe));
}

void InterruptManagement::find_controllers()
{
// TODO: Once device tree support is in place, find interrupt controllers using that.
m_interrupt_controllers.append(adopt_lock_ref(*new (nothrow) RPi::InterruptController));
for (auto& recipe : *s_recipes) {
auto device_or_error = recipe.create_device();
if (device_or_error.is_error()) {
dmesgln("InterruptManagement: Failed to create interrupt controller for device \"{}\" with driver {}: {}", recipe.node_name, recipe.driver_name, device_or_error.release_error());
continue;
}

m_interrupt_controllers.append(device_or_error.release_value());
}

if (m_interrupt_controllers.is_empty())
PANIC("InterruptManagement: No supported interrupt controller found in devicetree");
}

u8 InterruptManagement::acquire_mapped_interrupt_number(u8 interrupt_number)
Expand Down
3 changes: 3 additions & 0 deletions Kernel/Arch/aarch64/InterruptManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <AK/Vector.h>
#include <Kernel/Arch/aarch64/IRQController.h>
#include <Kernel/Firmware/DeviceTree/DeviceRecipe.h>
#include <Kernel/Library/LockRefPtr.h>

namespace Kernel {
Expand All @@ -18,6 +19,8 @@ class InterruptManagement {
static void initialize();
static bool initialized();

static void add_recipe(DeviceTree::DeviceRecipe<NonnullLockRefPtr<IRQController>>);

static u8 acquire_mapped_interrupt_number(u8 original_irq);

Vector<NonnullLockRefPtr<IRQController>> const& controllers();
Expand Down
25 changes: 25 additions & 0 deletions Kernel/Arch/aarch64/RPi/InterruptController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <Kernel/Arch/aarch64/InterruptManagement.h>
#include <Kernel/Arch/aarch64/RPi/InterruptController.h>
#include <Kernel/Arch/aarch64/RPi/MMIO.h>
#include <Kernel/Firmware/DeviceTree/DeviceTree.h>
#include <Kernel/Firmware/DeviceTree/Driver.h>
#include <Kernel/Firmware/DeviceTree/Management.h>
#include <Kernel/Interrupts/GenericInterruptHandler.h>

namespace Kernel::RPi {
Expand Down Expand Up @@ -65,4 +69,25 @@ u64 InterruptController::pending_interrupts() const
return ((u64)m_registers->irq_pending_2 << 32) | (u64)m_registers->irq_pending_1;
}

static constinit Array const compatibles_array = {
"brcm,bcm2836-armctrl-ic"sv,
};

DEVICETREE_DRIVER(BCM2836InterruptControllerDriver, compatibles_array);

ErrorOr<void> BCM2836InterruptControllerDriver::probe(DeviceTree::Device const& device, StringView) const
{
DeviceTree::DeviceRecipe<NonnullLockRefPtr<IRQController>> recipe {
name(),
device.node_name(),
[]() {
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) InterruptController());
},
};

InterruptManagement::add_recipe(move(recipe));

return {};
}

}
29 changes: 24 additions & 5 deletions Kernel/Arch/aarch64/RPi/Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <Kernel/Arch/aarch64/RPi/MMIO.h>
#include <Kernel/Arch/aarch64/RPi/Mailbox.h>
#include <Kernel/Arch/aarch64/RPi/Timer.h>
#include <Kernel/Firmware/DeviceTree/DeviceTree.h>
#include <Kernel/Firmware/DeviceTree/Driver.h>
#include <Kernel/Firmware/DeviceTree/Management.h>

namespace Kernel::RPi {

Expand Down Expand Up @@ -43,11 +46,6 @@ Timer::Timer()

Timer::~Timer() = default;

NonnullLockRefPtr<Timer> Timer::initialize()
{
return adopt_lock_ref(*new Timer);
}

u64 Timer::microseconds_since_boot()
{
u32 high = m_registers->counter_high;
Expand Down Expand Up @@ -182,4 +180,25 @@ u32 Timer::get_clock_rate(ClockID clock_id)
return message_queue.get_clock_rate.rate_hz;
}

static constinit Array const compatibles_array = {
"brcm,bcm2835-system-timer"sv,
};

DEVICETREE_DRIVER(BCM2835TimerDriver, compatibles_array);

ErrorOr<void> BCM2835TimerDriver::probe(DeviceTree::Device const& device, StringView) const
{
DeviceTree::DeviceRecipe<NonnullLockRefPtr<HardwareTimerBase>> recipe {
name(),
device.node_name(),
[]() {
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) Timer());
},
};

TimeManagement::add_recipe(move(recipe));

return {};
}

}
5 changes: 1 addition & 4 deletions Kernel/Arch/aarch64/RPi/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ struct TimerRegisters;

class Timer final : public HardwareTimer<IRQHandler> {
public:
Timer();
virtual ~Timer();

static NonnullLockRefPtr<Timer> initialize();

virtual HardwareTimerType timer_type() const override { return HardwareTimerType::RPiTimer; }
virtual StringView model() const override { return "RPi Timer"sv; }

Expand Down Expand Up @@ -65,8 +64,6 @@ class Timer final : public HardwareTimer<IRQHandler> {
static u32 get_clock_rate(ClockID);

private:
Timer();

enum class TimerID : u32 {
Timer0 = 0,
Timer1 = 1,
Expand Down
13 changes: 9 additions & 4 deletions Kernel/Arch/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@
# include <Kernel/Arch/riscv64/Delay.h>
#endif

#if ARCH(AARCH64) || ARCH(RISCV64)
spholz marked this conversation as resolved.
Show resolved Hide resolved
# include <Kernel/Firmware/DeviceTree/Management.h>
#endif

// Defined in the linker script
typedef void (*ctor_func_t)();
extern ctor_func_t start_heap_ctors[];
Expand Down Expand Up @@ -261,11 +265,16 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT NO_SANITIZE_COVERAGE void init([[maybe_
for (ctor_func_t* ctor = start_ctors; ctor < end_ctors; ctor++)
(*ctor)();

for (auto* init_function = driver_init_table_start; init_function != driver_init_table_end; init_function++)
(*init_function)();

#if ARCH(AARCH64) || ARCH(RISCV64)
MUST(DeviceTree::unflatten_fdt());

if (kernel_command_line().contains("dump_fdt"sv))
DeviceTree::dump_fdt();

DeviceTree::Management::initialize();
#endif

#if ARCH(RISCV64)
Expand Down Expand Up @@ -416,10 +425,6 @@ void init_stage2(void*)

AudioManagement::the().initialize();

// Initialize all USB Drivers
for (auto* init_function = driver_init_table_start; init_function != driver_init_table_end; init_function++)
(*init_function)();

StorageManagement::the().initialize(kernel_command_line().is_nvme_polling_enabled());
for (int i = 0; i < 5; ++i) {
if (StorageManagement::the().determine_boot_device(kernel_command_line().root_device()))
Expand Down
2 changes: 1 addition & 1 deletion Kernel/Bus/USB/USBDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ErrorOr<NonnullLockRefPtr<Device>> Device::try_create(USBController& controller,
// "probe" function, which initialises the local state for the device driver.
// It is currently the driver's responsibility to search the configuration/interface
// and take the appropriate action.
spholz marked this conversation as resolved.
Show resolved Hide resolved
for (auto& driver : USBManagement::the().available_drivers()) {
for (auto& driver : USBManagement::available_drivers()) {
// FIXME: Some devices have multiple configurations, for which we may have a better driver,
// than the first we find, or we have a vendor specific driver for the device,
// so we want a prioritization mechanism here
Expand Down
23 changes: 12 additions & 11 deletions Kernel/Bus/USB/USBManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <AK/NeverDestroyed.h>
#include <AK/Singleton.h>
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Bus/PCI/API.h>
Expand All @@ -18,7 +19,9 @@

namespace Kernel::USB {

static NeverDestroyed<Vector<NonnullLockRefPtr<Driver>>> s_available_drivers;
static Singleton<USBManagement> s_the;

READONLY_AFTER_INIT bool s_initialized_sys_fs_directory = false;

UNMAP_AFTER_INIT USBManagement::USBManagement()
Expand Down Expand Up @@ -91,34 +94,32 @@ UNMAP_AFTER_INIT void USBManagement::initialize()

void USBManagement::register_driver(NonnullLockRefPtr<Driver> driver)
{
if (!initialized())
return;
dbgln_if(USB_DEBUG, "Registering driver {}", driver->name());
the().m_available_drivers.append(driver);
s_available_drivers->append(driver);
}

LockRefPtr<Driver> USBManagement::get_driver_by_name(StringView name)
{
if (!initialized())
return nullptr;
auto it = the().m_available_drivers.find_if([name](auto driver) { return driver->name() == name; });
auto it = s_available_drivers->find_if([name](auto driver) { return driver->name() == name; });
return it.is_end() ? nullptr : LockRefPtr { *it };
}

void USBManagement::unregister_driver(NonnullLockRefPtr<Driver> driver)
{
if (!initialized())
return;
auto& the_instance = the();
dbgln_if(USB_DEBUG, "Unregistering driver {}", driver->name());
auto const& found_driver = the_instance.m_available_drivers.find(driver);
auto const& found_driver = s_available_drivers->find(driver);
if (!found_driver.is_end())
the_instance.m_available_drivers.remove(found_driver.index());
s_available_drivers->remove(found_driver.index());
}

USBManagement& USBManagement::the()
{
return *s_the;
}

Vector<NonnullLockRefPtr<Driver>>& USBManagement::available_drivers()
{
return *s_available_drivers;
}

}
3 changes: 1 addition & 2 deletions Kernel/Bus/USB/USBManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ class USBManagement {
static LockRefPtr<Driver> get_driver_by_name(StringView name);
static void unregister_driver(NonnullLockRefPtr<Driver> driver);

Vector<NonnullLockRefPtr<Driver>>& available_drivers() { return m_available_drivers; }
static Vector<NonnullLockRefPtr<Driver>>& available_drivers();

private:
void enumerate_controllers();

USBController::List m_controllers;
Vector<NonnullLockRefPtr<Driver>> m_available_drivers;
};

}
1 change: 1 addition & 0 deletions Kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ set(KERNEL_SOURCES
Firmware/ACPI/Parser.cpp
Firmware/ACPI/StaticParsing.cpp
Firmware/DeviceTree/DeviceTree.cpp
Firmware/DeviceTree/Management.cpp
Interrupts/GenericInterruptHandler.cpp
Interrupts/IRQHandler.cpp
Interrupts/PCIIRQHandler.cpp
Expand Down
46 changes: 46 additions & 0 deletions Kernel/Firmware/DeviceTree/Device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2024, Sönke Holz <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/Badge.h>
#include <AK/Noncopyable.h>
#include <LibDeviceTree/DeviceTree.h>

namespace Kernel::DeviceTree {

class Driver;
class Management;

class Device {
AK_MAKE_NONCOPYABLE(Device);
AK_MAKE_DEFAULT_MOVABLE(Device);

public:
Device(::DeviceTree::DeviceTreeNodeView const& node, StringView node_name)
: m_node(&node)
, m_node_name(node_name)
{
}

::DeviceTree::DeviceTreeNodeView const& node() const { return *m_node; }
StringView node_name() const { return m_node_name; }

Driver const* driver() const { return m_driver; }
void set_driver(Badge<Management>, Driver const& driver)
{
VERIFY(m_driver == nullptr);
m_driver = &driver;
}

private:
// This needs to be a pointer for the class to be movable.
::DeviceTree::DeviceTreeNodeView const* m_node;
StringView m_node_name;
Driver const* m_driver { nullptr };
};

}
20 changes: 20 additions & 0 deletions Kernel/Firmware/DeviceTree/DeviceRecipe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2024, Leon Albrecht <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/StringView.h>

namespace Kernel::DeviceTree {

template<typename DevicePtr>
struct DeviceRecipe {
StringView driver_name;
StringView node_name;
Function<ErrorOr<DevicePtr>()> create_device;
};

}
Loading
Loading