lx_kit: do not close/re-open IRQ session

Instead of dynamically close/open IRQ session whenever an IRQ
gots masked/unmasked, track the state internally and resp.
deliver an interrupt delayed.
This commit is contained in:
Stefan Kalkowski 2022-09-30 17:15:32 +02:00 committed by Christian Helmuth
parent 00c9ac363f
commit fa124dd340
3 changed files with 27 additions and 12 deletions

View File

@ -65,11 +65,14 @@ class Lx_kit::Device : List<Device>::Element
Index idx;
unsigned number;
Io_signal_handler<Irq> handler;
bool masked { true };
bool occured { false };
Constructible<Platform::Device::Irq> session {};
Irq(Entrypoint & ep, unsigned idx, unsigned number);
void _handle();
void handle();
};

View File

@ -60,6 +60,7 @@ int lx_emul_irq_task_function(void * data)
lx_emul_irq_last());
} else {
generic_handle_irq(irq);
lx_emul_irq_eoi(irq);
}
irq_exit();

View File

@ -42,11 +42,22 @@ bool Device::Io_port::match(uint16_t addr)
** Device::Irq**
****************/
void Device::Irq::_handle()
{
handle();
env().scheduler.schedule();
}
void Device::Irq::handle()
{
occured = true;
if (masked)
return;
env().last_irq = number;
env().scheduler.unblock_irq_handler();
env().scheduler.schedule();
}
@ -54,7 +65,7 @@ Device::Irq::Irq(Entrypoint & ep, unsigned idx, unsigned number)
:
idx{idx},
number(number),
handler(ep, *this, &Irq::handle) { }
handler(ep, *this, &Irq::_handle) { }
/************
@ -139,12 +150,14 @@ bool Device::irq_unmask(unsigned number)
ret = true;
enable();
if (irq.session.constructed())
return;
if (!irq.session.constructed()) {
irq.session.construct(*_pdev, irq.idx);
irq.session->sigh_omit_initial_signal(irq.handler);
irq.session->ack();
}
irq.session.construct(*_pdev, irq.idx);
irq.session->sigh_omit_initial_signal(irq.handler);
irq.session->ack();
irq.masked = false;
if (irq.occured) irq.handle();
});
return ret;
@ -157,10 +170,7 @@ void Device::irq_mask(unsigned number)
return;
for_each_irq([&] (Irq & irq) {
if (irq.number != number)
return;
irq.session.destruct();
});
if (irq.number == number) irq.masked = true; });
}
@ -171,8 +181,9 @@ void Device::irq_ack(unsigned number)
return;
for_each_irq([&] (Irq & irq) {
if (irq.number != number || !irq.session.constructed())
if (irq.number != number || !irq.occured || !irq.session.constructed())
return;
irq.occured = false;
irq.session->ack();
});
}