forked from Bananymous/banan-os
Kernel: Fix interrupt system
I had not understood how MSIs work and I was unnecessarily routing them through IOAPIC. This is not necessary and should not be done :D Also MSIs were reserving interrupts that IOAPIC was capable of generating. Now IOAPIC and MSIs use different set of interrupts so IOAPIC can use more interrupts if needed.
This commit is contained in:
@@ -703,10 +703,9 @@ acpi_release_global_lock:
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
set_irq(irq);
|
||||
enable_interrupt();
|
||||
InterruptController::get().enable_irq(irq);
|
||||
|
||||
Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ namespace Kernel
|
||||
| ICR_LO_level_assert
|
||||
| ICR_LO_trigger_mode_level
|
||||
| ICR_LO_destination_shorthand_none
|
||||
| (IRQ_VECTOR_BASE + IRQ_IPI)
|
||||
| IRQ_IPI
|
||||
);
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ namespace Kernel
|
||||
| ICR_LO_level_assert
|
||||
| ICR_LO_trigger_mode_level
|
||||
| ICR_LO_destination_shorthand_all_excluding_self
|
||||
| (IRQ_VECTOR_BASE + IRQ_IPI)
|
||||
| IRQ_IPI
|
||||
);
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ namespace Kernel
|
||||
|
||||
dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz);
|
||||
|
||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | (IRQ_VECTOR_BASE + IRQ_TIMER));
|
||||
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | IRQ_TIMER);
|
||||
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100);
|
||||
}
|
||||
|
||||
@@ -536,9 +536,9 @@ namespace Kernel
|
||||
BAN::Optional<uint8_t> APIC::get_free_irq()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
for (int irq = 0; irq <= 0xFF; irq++)
|
||||
for (uint8_t irq = 0; irq < m_irq_count; irq++)
|
||||
{
|
||||
uint32_t gsi = m_irq_overrides[irq];
|
||||
const uint8_t gsi = m_irq_overrides[irq];
|
||||
|
||||
IOAPIC* ioapic = nullptr;
|
||||
for (IOAPIC& io : m_io_apics)
|
||||
@@ -553,8 +553,8 @@ namespace Kernel
|
||||
if (!ioapic)
|
||||
continue;
|
||||
|
||||
int byte = gsi / 8;
|
||||
int bit = gsi % 8;
|
||||
const uint8_t byte = gsi / 8;
|
||||
const uint8_t bit = gsi % 8;
|
||||
if (m_reserved_gsis[byte] & (1 << bit))
|
||||
continue;
|
||||
m_reserved_gsis[byte] |= 1 << bit;
|
||||
|
||||
@@ -10,7 +10,15 @@
|
||||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
#define IRQ_LIST_X X( 0) X( 1) X( 2) X( 3) X( 4) X( 5) X( 6) X( 7) X( 8) X( 9) X( 10) X( 11) X( 12) X( 13) X( 14) X( 15) X( 16) X( 17) X( 18) X( 19) X( 20) X( 21) X( 22) X( 23) X( 24) X( 25) X( 26) X( 27) X( 28) X( 29) X( 30) X( 31) \
|
||||
X( 32) X( 33) X( 34) X( 35) X( 36) X( 37) X( 38) X( 39) X( 40) X( 41) X( 42) X( 43) X( 44) X( 45) X( 46) X( 47) X( 48) X( 49) X( 50) X( 51) X( 52) X( 53) X( 54) X( 55) X( 56) X( 57) X( 58) X( 59) X( 60) X( 61) X( 62) X( 63) \
|
||||
X( 64) X( 65) X( 66) X( 67) X( 68) X( 69) X( 70) X( 71) X( 72) X( 73) X( 74) X( 75) X( 76) X( 77) X( 78) X( 79) X( 80) X( 81) X( 82) X( 83) X( 84) X( 85) X( 86) X( 87) X( 88) X( 89) X( 90) X( 91) X( 92) X( 93) X( 94) X( 95) \
|
||||
X( 96) X( 97) X( 98) X( 99) X(100) X(101) X(102) X(103) X(104) X(105) X(106) X(107) X(108) X(109) X(110) X(111) X(112) X(113) X(114) X(115) X(116) X(117) X(118) X(119) X(120) X(121) X(122) X(123) X(124) X(125) X(126) X(127) \
|
||||
X(128) X(129) X(130) X(131) X(132) X(133) X(134) X(135) X(136) X(137) X(138) X(139) X(140) X(141) X(142) X(143) X(144) X(145) X(146) X(147) X(148) X(149) X(150) X(151) X(152) X(153) X(154) X(155) X(156) X(157) X(158) X(159) \
|
||||
X(160) X(161) X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) \
|
||||
X(192) X(193) X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207)
|
||||
|
||||
static_assert(Kernel::IRQ_SYSCALL == Kernel::IRQ_VECTOR_BASE + 208);
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -321,15 +329,15 @@ done:
|
||||
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
|
||||
{
|
||||
// yield is raised through kernel software interrupt
|
||||
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD));
|
||||
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD - IRQ_VECTOR_BASE));
|
||||
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
|
||||
Processor::scheduler().reschedule(interrupt_stack, interrupt_registers);
|
||||
}
|
||||
|
||||
extern "C" void cpp_ipi_handler()
|
||||
{
|
||||
ASSERT(InterruptController::get().is_in_service(IRQ_IPI));
|
||||
InterruptController::get().eoi(IRQ_IPI);
|
||||
ASSERT(InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE));
|
||||
InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE);
|
||||
Processor::handle_ipi();
|
||||
}
|
||||
|
||||
@@ -343,8 +351,8 @@ done:
|
||||
asm volatile("cli; 1: hlt; jmp 1b");
|
||||
}
|
||||
|
||||
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER));
|
||||
InterruptController::get().eoi(IRQ_TIMER);
|
||||
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
|
||||
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
|
||||
|
||||
if (Processor::current_is_bsb())
|
||||
Process::update_alarm_queue();
|
||||
@@ -452,11 +460,10 @@ done:
|
||||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_YIELD, asm_yield_handler);
|
||||
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_IPI, asm_ipi_handler);
|
||||
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_TIMER, asm_timer_handler);
|
||||
|
||||
idt->register_syscall_handler(0x80, asm_syscall_handler);
|
||||
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
|
||||
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
|
||||
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
|
||||
idt->register_syscall_handler(IRQ_SYSCALL, asm_syscall_handler);
|
||||
|
||||
return idt;
|
||||
}
|
||||
|
||||
@@ -342,13 +342,13 @@ namespace Kernel::Input
|
||||
if (m_devices[0])
|
||||
{
|
||||
m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
|
||||
m_devices[0]->enable_interrupt();
|
||||
InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
|
||||
config |= PS2::Config::INTERRUPT_FIRST_PORT;
|
||||
}
|
||||
if (m_devices[1])
|
||||
{
|
||||
m_devices[1]->set_irq(PS2::IRQ::DEVICE1);
|
||||
m_devices[1]->enable_interrupt();
|
||||
InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
|
||||
config |= PS2::Config::INTERRUPT_SECOND_PORT;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,4 @@ namespace Kernel
|
||||
Processor::idt().register_irq_handler(irq, this);
|
||||
}
|
||||
|
||||
void Interruptable::enable_interrupt()
|
||||
{
|
||||
ASSERT(m_irq != -1);
|
||||
InterruptController::get().enable_irq(m_irq);
|
||||
}
|
||||
|
||||
void Interruptable::disable_interrupt()
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -245,9 +245,8 @@ namespace Kernel
|
||||
write32(REG_IMS, IMC_RxQ0);
|
||||
read32(REG_ICR);
|
||||
|
||||
TRY(m_pci_device.reserve_irqs(1));
|
||||
set_irq(m_pci_device.get_irq(0));
|
||||
Interruptable::enable_interrupt();
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -161,9 +161,8 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<void> RTL8169::enable_interrupt()
|
||||
{
|
||||
TRY(m_pci_device.reserve_irqs(1));
|
||||
set_irq(m_pci_device.get_irq(0));
|
||||
Interruptable::enable_interrupt();
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
|
||||
m_io_bar_region->write16(RTL8169_IO_IMR,
|
||||
RTL8169_IR_ROK
|
||||
|
||||
@@ -175,6 +175,23 @@ namespace Kernel::PCI
|
||||
}
|
||||
}
|
||||
|
||||
BAN::Optional<uint8_t> PCIManager::reserve_msi()
|
||||
{
|
||||
SpinLockGuard _(m_reserved_msi_lock);
|
||||
|
||||
for (uint8_t i = 0; i < m_msi_count; i++)
|
||||
{
|
||||
const uint8_t byte = i / 8;
|
||||
const uint8_t bit = i % 8;
|
||||
if (m_reserved_msi_bitmap[byte] & (1 << bit))
|
||||
continue;
|
||||
m_reserved_msi_bitmap[byte] |= 1 << bit;
|
||||
return IRQ_MSI_BASE - IRQ_VECTOR_BASE + i;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void PCIManager::initialize_devices(bool disable_usb)
|
||||
{
|
||||
for_each_device(
|
||||
@@ -360,63 +377,24 @@ namespace Kernel::PCI
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PCI::Device::reserve_irqs(uint8_t count)
|
||||
uint8_t PCI::Device::get_interrupt(uint8_t index) const
|
||||
{
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic());
|
||||
ASSERT(index < m_reserved_interrupt_count);
|
||||
|
||||
uint8_t count_found = 0;
|
||||
for (uint32_t irq = 0; irq < 0x100; irq++)
|
||||
{
|
||||
if (count > 1)
|
||||
{
|
||||
dwarnln("PIC: could not allocate {} interrupts, (currently) only {} supported", count, 1);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
enable_pin_interrupts();
|
||||
}
|
||||
else if (m_offset_msi_x.has_value())
|
||||
{
|
||||
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||
if (count > (msg_ctrl & 0x7FF) + 1)
|
||||
{
|
||||
dwarnln("MSI-X: could not allocate {} interrupts, only {} supported", count, (msg_ctrl & 0x7FF) + 1);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
msg_ctrl |= 1 << 15; // Enable
|
||||
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
|
||||
disable_pin_interrupts();
|
||||
}
|
||||
else if (m_offset_msi.has_value())
|
||||
{
|
||||
if (count > 1)
|
||||
{
|
||||
dwarnln("MSI: could not allocate {} interrupts, (currently) only {} supported", count, 1);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
|
||||
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
|
||||
msg_ctrl |= 1u << 0; // Enable
|
||||
write_word(*m_offset_msi + 0x02, msg_ctrl);
|
||||
disable_pin_interrupts();
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarnln("Could not reserve interrupt for PCI device. No MSI, MSI-X or interrupt line is used");
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
const uint8_t byte = irq / 8;
|
||||
const uint8_t bit = irq % 8;
|
||||
|
||||
if (m_reserved_interrupts[byte] & (1 << bit))
|
||||
count_found++;
|
||||
if (index + 1 == count_found)
|
||||
return irq;
|
||||
}
|
||||
|
||||
for (; m_reserved_irq_count < count; m_reserved_irq_count++)
|
||||
{
|
||||
auto irq = InterruptController::get().get_free_irq();
|
||||
if (!irq.has_value())
|
||||
{
|
||||
dwarnln("Could not reserve interrupt for PCI {}:{}.{}", m_bus, m_dev, m_func);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
ASSERT(*irq < 32);
|
||||
ASSERT(!(m_reserved_irqs & (1 << *irq)));
|
||||
m_reserved_irqs |= 1 << *irq;
|
||||
}
|
||||
|
||||
return {};
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static constexpr uint64_t msi_message_address()
|
||||
@@ -429,79 +407,145 @@ namespace Kernel::PCI
|
||||
return (IRQ_VECTOR_BASE + irq) & 0xFF;
|
||||
}
|
||||
|
||||
uint8_t PCI::Device::get_irq(uint8_t index)
|
||||
void PCI::Device::enable_interrupt(uint8_t index, Interruptable& interruptable)
|
||||
{
|
||||
ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic());
|
||||
ASSERT(index < m_reserved_irq_count);
|
||||
const uint8_t irq = get_interrupt(index);
|
||||
interruptable.set_irq(irq);
|
||||
|
||||
uint8_t count_found = 0;
|
||||
uint8_t irq = 0xFF;
|
||||
for (uint8_t i = 0; i < 32; i++)
|
||||
switch (m_interrupt_mechanism)
|
||||
{
|
||||
if (m_reserved_irqs & (1 << i))
|
||||
count_found++;
|
||||
if (count_found > index)
|
||||
case InterruptMechanism::NONE:
|
||||
ASSERT_NOT_REACHED();
|
||||
case InterruptMechanism::PIN:
|
||||
enable_pin_interrupts();
|
||||
write_byte(PCI_REG_IRQ_LINE, irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
break;
|
||||
case InterruptMechanism::MSI:
|
||||
{
|
||||
irq = i;
|
||||
disable_pin_interrupts();
|
||||
|
||||
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
|
||||
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
|
||||
msg_ctrl |= 1u << 0; // Enable
|
||||
write_word(*m_offset_msi + 0x02, msg_ctrl);
|
||||
|
||||
const uint64_t msg_addr = msi_message_address();
|
||||
const uint32_t msg_data = msi_message_data(irq);
|
||||
|
||||
if (msg_ctrl & (1 << 7))
|
||||
{
|
||||
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||
write_dword(*m_offset_msi + 0x08, msg_addr >> 32);
|
||||
write_word(*m_offset_msi + 0x12, msg_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||
write_word(*m_offset_msi + 0x08, msg_data);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case InterruptMechanism::MSIX:
|
||||
{
|
||||
disable_pin_interrupts();
|
||||
|
||||
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||
msg_ctrl |= 1 << 15; // Enable
|
||||
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
|
||||
|
||||
const uint32_t dword1 = read_dword(*m_offset_msi_x + 0x04);
|
||||
const uint32_t offset = dword1 & ~7u;
|
||||
const uint8_t bir = dword1 & 7u;
|
||||
|
||||
const uint64_t msg_addr = msi_message_address();
|
||||
const uint32_t msg_data = msi_message_data(irq);
|
||||
|
||||
auto bar = MUST(allocate_bar_region(bir));
|
||||
ASSERT(bar->type() == BarType::MEM);
|
||||
|
||||
auto& msi_x_entry = reinterpret_cast<volatile MSIXEntry*>(bar->vaddr() + offset)[index];
|
||||
msi_x_entry.msg_addr_low = msg_addr & 0xFFFFFFFF;
|
||||
msi_x_entry.msg_addr_high = msg_addr >> 32;;
|
||||
msi_x_entry.msg_data = msg_data;
|
||||
msi_x_entry.vector_ctrl = msi_x_entry.vector_ctrl & ~1u;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(irq != 0xFF);
|
||||
}
|
||||
|
||||
// Legacy PIC just uses the interrupt line field
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
{
|
||||
write_byte(PCI_REG_IRQ_LINE, irq);
|
||||
return irq;
|
||||
}
|
||||
BAN::ErrorOr<void> PCI::Device::reserve_interrupts(uint8_t count)
|
||||
{
|
||||
// FIXME: Allow "late" interrupt reserving
|
||||
ASSERT(m_reserved_interrupt_count == 0);
|
||||
|
||||
if (m_offset_msi_x.has_value())
|
||||
{
|
||||
uint32_t dword0 = read_dword(*m_offset_msi_x);
|
||||
ASSERT((dword0 & 0xFF) == 0x11);
|
||||
|
||||
uint32_t dword1 = read_dword(*m_offset_msi_x + 0x04);
|
||||
uint32_t offset = dword1 & ~7u;
|
||||
uint8_t bir = dword1 & 7u;
|
||||
|
||||
uint64_t msg_addr = msi_message_address();
|
||||
uint32_t msg_data = msi_message_data(irq);
|
||||
|
||||
auto bar = MUST(allocate_bar_region(bir));
|
||||
ASSERT(bar->type() == BarType::MEM);
|
||||
auto& msi_x_entry = reinterpret_cast<volatile MSIXEntry*>(bar->vaddr() + offset)[index];
|
||||
msi_x_entry.msg_addr_low = msg_addr & 0xFFFFFFFF;
|
||||
msi_x_entry.msg_addr_high = msg_addr >> 32;;
|
||||
msi_x_entry.msg_data = msg_data;
|
||||
msi_x_entry.vector_ctrl = msi_x_entry.vector_ctrl & ~1u;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (m_offset_msi.has_value())
|
||||
{
|
||||
uint32_t dword0 = read_dword(*m_offset_msi);
|
||||
ASSERT((dword0 & 0xFF) == 0x05);
|
||||
|
||||
uint64_t msg_addr = msi_message_address();
|
||||
uint32_t msg_data = msi_message_data(irq);
|
||||
|
||||
if (dword0 & (1 << 23))
|
||||
const auto mechanism =
|
||||
[&]() -> InterruptMechanism
|
||||
{
|
||||
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||
write_dword(*m_offset_msi + 0x08, msg_addr >> 32);
|
||||
write_word(*m_offset_msi + 0x12, msg_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||
write_word(*m_offset_msi + 0x08, msg_data);
|
||||
}
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
{
|
||||
// FIXME: support multiple PIN interrupts
|
||||
if (count == 1)
|
||||
return InterruptMechanism::PIN;
|
||||
|
||||
return irq;
|
||||
// MSI cannot be used without LAPIC
|
||||
return InterruptMechanism::NONE;
|
||||
}
|
||||
|
||||
if (m_offset_msi_x.has_value())
|
||||
{
|
||||
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||
if (count <= (msg_ctrl & 0x7FF) + 1)
|
||||
return InterruptMechanism::MSIX;
|
||||
}
|
||||
|
||||
if (m_offset_msi.has_value())
|
||||
{
|
||||
if (count == 1)
|
||||
return InterruptMechanism::MSI;
|
||||
// FIXME: support multiple message
|
||||
}
|
||||
|
||||
// FIXME: support ioapic
|
||||
|
||||
return InterruptMechanism::NONE;
|
||||
}();
|
||||
|
||||
auto get_interrupt_func =
|
||||
[mechanism]() -> BAN::Optional<uint8_t>
|
||||
{
|
||||
switch (mechanism)
|
||||
{
|
||||
case InterruptMechanism::NONE:
|
||||
return {};
|
||||
case InterruptMechanism::PIN:
|
||||
return InterruptController::get().get_free_irq();
|
||||
case InterruptMechanism::MSI:
|
||||
case InterruptMechanism::MSIX:
|
||||
return PCIManager::get().reserve_msi();
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < count; i++)
|
||||
{
|
||||
const auto irq = get_interrupt_func();
|
||||
if (!irq.has_value())
|
||||
{
|
||||
dwarnln("Could not reserve {} MSI(-X) interrupts", count);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
const uint8_t byte = irq.value() / 8;
|
||||
const uint8_t bit = irq.value() % 8;
|
||||
m_reserved_interrupts[byte] |= 1 << bit;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
m_interrupt_mechanism = mechanism;
|
||||
m_reserved_interrupt_count = count;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void PCI::Device::set_command_bits(uint16_t mask)
|
||||
|
||||
@@ -368,7 +368,7 @@ namespace Kernel
|
||||
// NOTE: This is offset by 2 pointers since interrupt without PL change
|
||||
// does not push SP and SS. This allows accessing "whole" interrupt stack.
|
||||
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
|
||||
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD)
|
||||
[yield]"i"(IRQ_YIELD)
|
||||
: "memory", "rcx"
|
||||
);
|
||||
#elif ARCH(i686)
|
||||
@@ -380,7 +380,7 @@ namespace Kernel
|
||||
// NOTE: This is offset by 2 pointers since interrupt without PL change
|
||||
// does not push SP and SS. This allows accessing "whole" interrupt stack.
|
||||
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
|
||||
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD)
|
||||
[yield]"i"(IRQ_YIELD)
|
||||
: "memory", "ecx"
|
||||
);
|
||||
#else
|
||||
|
||||
@@ -25,9 +25,8 @@ namespace Kernel
|
||||
|
||||
// Enable interrupts and bus mastering
|
||||
m_pci_device.enable_bus_mastering();
|
||||
TRY(m_pci_device.reserve_irqs(1));
|
||||
set_irq(m_pci_device.get_irq(0));
|
||||
enable_interrupt();
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
|
||||
|
||||
m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1;
|
||||
|
||||
@@ -25,14 +25,13 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
bus->set_irq(irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
TRY(bus->initialize());
|
||||
return bus;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ATABus::initialize()
|
||||
{
|
||||
enable_interrupt();
|
||||
|
||||
BAN::Vector<uint16_t> identify_buffer;
|
||||
MUST(identify_buffer.resize(256));
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
// One for aq and one for ioq
|
||||
TRY(m_pci_device.reserve_irqs(2));
|
||||
TRY(m_pci_device.reserve_interrupts(2));
|
||||
|
||||
auto& cc = m_controller_registers->cc;
|
||||
|
||||
@@ -237,12 +237,12 @@ namespace Kernel
|
||||
m_controller_registers->acq = completion_queue->paddr();
|
||||
m_controller_registers->asq = submission_queue->paddr();
|
||||
|
||||
uint8_t irq = m_pci_device.get_irq(0);
|
||||
dprintln_if(DEBUG_NVMe, " admin queue using irq {}", irq);
|
||||
dprintln_if(DEBUG_NVMe, " admin queue using irq {}", m_pci_device.get_interrupt(0));
|
||||
|
||||
auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL);
|
||||
|
||||
m_admin_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, admin_queue_depth, irq));
|
||||
m_admin_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, admin_queue_depth));
|
||||
m_pci_device.enable_interrupt(0, *m_admin_queue);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -290,14 +290,14 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t irq = m_pci_device.get_irq(1);
|
||||
dprintln_if(DEBUG_NVMe, " io queue using irq {}", irq);
|
||||
dprintln_if(DEBUG_NVMe, " io queue using irq {}", m_pci_device.get_interrupt(1));
|
||||
|
||||
const uint32_t doorbell_stride = 1 << (2 + m_controller_registers->cap.dstrd);
|
||||
const uint32_t doorbell_offset = 2 * doorbell_stride;
|
||||
auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL + doorbell_offset);
|
||||
|
||||
m_io_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, queue_elems, irq));
|
||||
m_io_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, queue_elems));
|
||||
m_pci_device.enable_interrupt(1, *m_io_queue);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Kernel
|
||||
static constexpr uint64_t s_nvme_command_timeout_ms = 1000;
|
||||
static constexpr uint64_t s_nvme_command_poll_timeout_ms = 20;
|
||||
|
||||
NVMeQueue::NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth, uint8_t irq)
|
||||
NVMeQueue::NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth)
|
||||
: m_completion_queue(BAN::move(cq))
|
||||
, m_submission_queue(BAN::move(sq))
|
||||
, m_doorbell(db)
|
||||
@@ -17,8 +17,6 @@ namespace Kernel
|
||||
{
|
||||
for (uint32_t i = qdepth; i < m_mask_bits; i++)
|
||||
m_used_mask |= (size_t)1 << i;
|
||||
set_irq(irq);
|
||||
enable_interrupt();
|
||||
}
|
||||
|
||||
void NVMeQueue::handle_irq()
|
||||
|
||||
@@ -188,14 +188,14 @@ namespace Kernel
|
||||
IO::outb(COM1_PORT + 1, 1);
|
||||
TRY(InterruptController::get().reserve_irq(COM1_IRQ));
|
||||
tty->set_irq(COM1_IRQ);
|
||||
tty->enable_interrupt();
|
||||
InterruptController::get().enable_irq(COM1_IRQ);
|
||||
}
|
||||
else if (serial.port() == COM2_PORT)
|
||||
{
|
||||
IO::outb(COM2_PORT + 1, 1);
|
||||
TRY(InterruptController::get().reserve_irq(COM2_IRQ));
|
||||
tty->set_irq(COM2_IRQ);
|
||||
tty->enable_interrupt();
|
||||
InterruptController::get().enable_irq(COM2_IRQ);
|
||||
}
|
||||
|
||||
auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty);
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace Kernel
|
||||
|
||||
TRY(InterruptController::get().reserve_irq(0));
|
||||
set_irq(0);
|
||||
enable_interrupt();
|
||||
InterruptController::get().enable_irq(0);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Kernel
|
||||
|
||||
MUST(InterruptController::get().reserve_irq(PIT_IRQ));
|
||||
set_irq(PIT_IRQ);
|
||||
enable_interrupt();
|
||||
InterruptController::get().enable_irq(PIT_IRQ);
|
||||
}
|
||||
|
||||
void PIT::handle_irq()
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter()
|
||||
{
|
||||
TRY(m_pci_device.reserve_irqs(1));
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
|
||||
auto& runtime = runtime_regs();
|
||||
|
||||
@@ -227,8 +227,7 @@ namespace Kernel
|
||||
|
||||
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
|
||||
|
||||
set_irq(m_pci_device.get_irq(0));
|
||||
enable_interrupt();
|
||||
m_pci_device.enable_interrupt(0, *this);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user