From feb48cbc7cac31d0aeda8cb0dd062e10f175e45d Mon Sep 17 00:00:00 2001 From: Pankaj Raghav Date: Sat, 29 Apr 2023 21:50:01 +0200 Subject: [PATCH] Kernel: Introduce PCIIRQHandler PCIIRQHandler is a generic IRQ handler that the device driver can inherit to use either Pin or MSI(x) based interrupt mechanism. The PCIIRQHandler can do what the existing IRQHandler can do for pin based interrupts but also deal with MSI based interrupts. We can hopefully convert all the PCI based devices to use this handler so that MSI(x) can be used. --- Kernel/CMakeLists.txt | 1 + Kernel/Interrupts/PCIIRQHandler.cpp | 66 +++++++++++++++++++++++++++++ Kernel/Interrupts/PCIIRQHandler.h | 47 ++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 Kernel/Interrupts/PCIIRQHandler.cpp create mode 100644 Kernel/Interrupts/PCIIRQHandler.h diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 067fe7f63f..e0c66bdba0 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -220,6 +220,7 @@ set(KERNEL_SOURCES FutexQueue.cpp Interrupts/GenericInterruptHandler.cpp Interrupts/IRQHandler.cpp + Interrupts/PCIIRQHandler.cpp Interrupts/SharedIRQHandler.cpp Interrupts/UnhandledInterruptHandler.cpp KBufferBuilder.cpp diff --git a/Kernel/Interrupts/PCIIRQHandler.cpp b/Kernel/Interrupts/PCIIRQHandler.cpp new file mode 100644 index 0000000000..ada63ecc0f --- /dev/null +++ b/Kernel/Interrupts/PCIIRQHandler.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023, Pankaj R + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel { + +PCIIRQHandler::PCIIRQHandler(PCI::Device& device, u8 irq) + : GenericInterruptHandler(irq) + , device(device) +{ + auto type = device.get_interrupt_type(); + + if (type == PCI::InterruptType::PIN) + m_responsible_irq_controller = InterruptManagement::the().get_responsible_irq_controller(irq); + + if (is_registered()) + disable_irq(); +} + +bool PCIIRQHandler::eoi() +{ + dbgln_if(IRQ_DEBUG, "EOI IRQ {}", interrupt_number()); + if (m_shared_with_others) + return false; + if (!m_responsible_irq_controller.is_null()) + m_responsible_irq_controller->eoi(*this); + else + msi_signal_eoi(); + return true; +} + +void PCIIRQHandler::enable_irq() +{ + dbgln_if(IRQ_DEBUG, "Enable IRQ {}", interrupt_number()); + if (!is_registered()) + register_interrupt_handler(); + m_enabled = true; + if (m_shared_with_others) + return; + if (!m_responsible_irq_controller.is_null()) + m_responsible_irq_controller->enable(*this); + else + device.enable_interrupt(interrupt_number()); +} + +void PCIIRQHandler::disable_irq() +{ + dbgln_if(IRQ_DEBUG, "Disable IRQ {}", interrupt_number()); + m_enabled = false; + + if (m_shared_with_others) + return; + if (!m_responsible_irq_controller.is_null()) + m_responsible_irq_controller->disable(*this); + else + device.disable_interrupt(interrupt_number()); +} + +} diff --git a/Kernel/Interrupts/PCIIRQHandler.h b/Kernel/Interrupts/PCIIRQHandler.h new file mode 100644 index 0000000000..f167b88d3d --- /dev/null +++ b/Kernel/Interrupts/PCIIRQHandler.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Pankaj R + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel { + +class PCIIRQHandler : public GenericInterruptHandler { +public: + virtual ~PCIIRQHandler() = default; + + virtual bool handle_interrupt(RegisterState const& regs) override { return handle_irq(regs); } + virtual bool handle_irq(RegisterState const&) = 0; + + void enable_irq(); + void disable_irq(); + + virtual bool eoi() override; + + virtual HandlerType type() const override { return HandlerType::IRQHandler; } + virtual StringView purpose() const override { return "IRQ Handler"sv; } + virtual StringView controller() const override { return m_responsible_irq_controller.is_null() ? "PCI-MSI"sv : m_responsible_irq_controller->model(); } + + virtual size_t sharing_devices_count() const override { return 0; } + virtual bool is_shared_handler() const override { return false; } + void set_shared_with_others(bool status) { m_shared_with_others = status; } + +protected: + PCIIRQHandler(PCI::Device& device, u8 irq); + +private: + bool m_shared_with_others { false }; + bool m_enabled { false }; + LockRefPtr m_responsible_irq_controller { nullptr }; + PCI::Device& device; +}; + +}