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; Index idx;
unsigned number; unsigned number;
Io_signal_handler<Irq> handler; Io_signal_handler<Irq> handler;
bool masked { true };
bool occured { false };
Constructible<Platform::Device::Irq> session {}; Constructible<Platform::Device::Irq> session {};
Irq(Entrypoint & ep, unsigned idx, unsigned number); Irq(Entrypoint & ep, unsigned idx, unsigned number);
void _handle();
void handle(); void handle();
}; };

View File

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

View File

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