mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
Kernel: Add reserve_interrupt_handlers API
MSI(x) interrupts need to reserve IRQs so that it can be programmed by the device. Add an API to reserve contiguous ranges of interrupt handlers so that it can used by PCI devices that use MSI(x) mechanism. This API needs to be implemented by aarch64 architecture.
This commit is contained in:
parent
a5ec5f07fa
commit
91da264a4c
3 changed files with 58 additions and 0 deletions
|
@ -20,6 +20,7 @@ class GenericInterruptHandler;
|
|||
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number);
|
||||
void register_generic_interrupt_handler(u8 number, GenericInterruptHandler&);
|
||||
void unregister_generic_interrupt_handler(u8 number, GenericInterruptHandler&);
|
||||
ErrorOr<u8> reserve_interrupt_handlers(u8 number_of_irqs);
|
||||
|
||||
void initialize_interrupts();
|
||||
|
||||
|
|
|
@ -220,4 +220,12 @@ void initialize_interrupts()
|
|||
}
|
||||
}
|
||||
|
||||
// Sets the reserved flag on `number_of_irqs` if it finds unused interrupt handler on
|
||||
// a contiguous range.
|
||||
ErrorOr<u8> reserve_interrupt_handlers([[maybe_unused]] u8 number_of_irqs)
|
||||
{
|
||||
TODO();
|
||||
return Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace Kernel {
|
|||
READONLY_AFTER_INIT static DescriptorTablePointer s_idtr;
|
||||
READONLY_AFTER_INIT static IDTEntry s_idt[256];
|
||||
|
||||
// This spinlock is used to reserve IRQs that can be later used by interrupt mechanism such as MSIx
|
||||
static Spinlock<LockRank::None> s_interrupt_handler_lock {};
|
||||
static GenericInterruptHandler* s_interrupt_handler[GENERIC_INTERRUPT_HANDLERS_COUNT];
|
||||
static GenericInterruptHandler* s_disabled_interrupt_handler[2];
|
||||
|
||||
|
@ -334,6 +336,53 @@ static void revert_to_unused_handler(u8 interrupt_number)
|
|||
handler->register_interrupt_handler();
|
||||
}
|
||||
|
||||
static bool is_unused_handler(GenericInterruptHandler* handler_slot)
|
||||
{
|
||||
return (handler_slot->type() == HandlerType::UnhandledInterruptHandler) && !handler_slot->reserved();
|
||||
}
|
||||
|
||||
// Sets the reserved flag on `number_of_irqs` if it finds unused interrupt handler on
|
||||
// a contiguous range.
|
||||
ErrorOr<u8> reserve_interrupt_handlers(u8 number_of_irqs)
|
||||
{
|
||||
bool found_range = false;
|
||||
u8 first_irq = 0;
|
||||
SpinlockLocker locker(s_interrupt_handler_lock);
|
||||
for (int start_irq = 0; start_irq < GENERIC_INTERRUPT_HANDLERS_COUNT; start_irq++) {
|
||||
auto*& handler_slot = s_interrupt_handler[start_irq];
|
||||
VERIFY(handler_slot != nullptr);
|
||||
|
||||
if (!is_unused_handler(handler_slot))
|
||||
continue;
|
||||
|
||||
found_range = true;
|
||||
for (auto off = 1; off < number_of_irqs; off++) {
|
||||
auto*& handler = s_interrupt_handler[start_irq + off];
|
||||
VERIFY(handler_slot != nullptr);
|
||||
|
||||
if (!is_unused_handler(handler)) {
|
||||
found_range = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_range == true) {
|
||||
first_irq = start_irq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_range)
|
||||
return Error::from_errno(EAGAIN);
|
||||
|
||||
for (auto irq = first_irq; irq < number_of_irqs; irq++) {
|
||||
auto*& handler_slot = s_interrupt_handler[irq];
|
||||
handler_slot->set_reserved();
|
||||
}
|
||||
|
||||
return first_irq;
|
||||
}
|
||||
|
||||
void register_disabled_interrupt_handler(u8 number, GenericInterruptHandler& handler)
|
||||
{
|
||||
if (number == 15) {
|
||||
|
|
Loading…
Add table
Reference in a new issue