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