Kernel: Add API to reserve GSI instead of irq
This also fixes a bug with IOAPIC gsi_base != 0
This commit is contained in:
parent
ba74b352bd
commit
1c1fc65c7c
|
@ -23,6 +23,8 @@ namespace Kernel
|
||||||
virtual void broadcast_ipi() override;
|
virtual void broadcast_ipi() override;
|
||||||
virtual void enable() override;
|
virtual void enable() override;
|
||||||
|
|
||||||
|
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
|
||||||
|
|
||||||
void initialize_timer();
|
void initialize_timer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -458,7 +458,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint32_t gsi = m_irq_overrides[irq];
|
const uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
{
|
{
|
||||||
int byte = gsi / 8;
|
int byte = gsi / 8;
|
||||||
|
@ -477,9 +477,11 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
ASSERT(ioapic);
|
ASSERT(ioapic);
|
||||||
|
|
||||||
|
const uint32_t pin = gsi - ioapic->gsi_base;
|
||||||
|
|
||||||
RedirectionEntry redir;
|
RedirectionEntry redir;
|
||||||
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2);
|
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
|
||||||
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1);
|
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
|
||||||
ASSERT(redir.mask); // TODO: handle overlapping interrupts
|
ASSERT(redir.mask); // TODO: handle overlapping interrupts
|
||||||
|
|
||||||
redir.vector = IRQ_VECTOR_BASE + irq;
|
redir.vector = IRQ_VECTOR_BASE + irq;
|
||||||
|
@ -487,8 +489,8 @@ namespace Kernel
|
||||||
// FIXME: distribute IRQs more evenly?
|
// FIXME: distribute IRQs more evenly?
|
||||||
redir.destination = Kernel::Processor::bsb_id().as_u32();
|
redir.destination = Kernel::Processor::bsb_id().as_u32();
|
||||||
|
|
||||||
ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword);
|
ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword);
|
||||||
ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword);
|
ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool APIC::is_in_service(uint8_t irq)
|
bool APIC::is_in_service(uint8_t irq)
|
||||||
|
@ -504,35 +506,59 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint32_t gsi = m_irq_overrides[irq];
|
const uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
IOAPIC* ioapic = nullptr;
|
bool found_ioapic = false;
|
||||||
for (IOAPIC& io : m_io_apics)
|
for (const auto& io : m_io_apics)
|
||||||
{
|
{
|
||||||
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
||||||
{
|
{
|
||||||
ioapic = &io;
|
found_ioapic = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ioapic)
|
if (!found_ioapic)
|
||||||
{
|
{
|
||||||
dwarnln("Cannot enable irq {} for APIC", irq);
|
dwarnln("No IOAPIC for GSI {}", gsi);
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int byte = gsi / 8;
|
int byte = gsi / 8;
|
||||||
int bit = gsi % 8;
|
int bit = gsi % 8;
|
||||||
if (m_reserved_gsis[byte] & (1 << bit))
|
if (m_reserved_gsis[byte] & (1 << bit))
|
||||||
{
|
{
|
||||||
dwarnln("irq {} is already reserved", irq);
|
dwarnln("GSI {} is already reserved", gsi);
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
m_reserved_gsis[byte] |= 1 << bit;
|
m_reserved_gsis[byte] |= 1 << bit;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: rewrite gsi and vector reserving
|
||||||
|
// this is a hack to allow direct GSI reservation
|
||||||
|
BAN::ErrorOr<uint8_t> APIC::reserve_gsi(uint32_t gsi)
|
||||||
|
{
|
||||||
|
dwarnln("TRYING TO RESERVE GSI {}", gsi);
|
||||||
|
|
||||||
|
size_t irq = 0;
|
||||||
|
for (; irq < 0x100; irq++)
|
||||||
|
if (m_irq_overrides[irq] == gsi)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (irq == 0x100)
|
||||||
|
{
|
||||||
|
dwarnln("TODO: reserve GSI not accessible through overrides");
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
dwarnln(" matches IRQ {}", irq);
|
||||||
|
|
||||||
|
TRY(reserve_irq(irq));
|
||||||
|
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::Optional<uint8_t> APIC::get_free_irq()
|
BAN::Optional<uint8_t> APIC::get_free_irq()
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
Loading…
Reference in New Issue