diff --git a/repos/dde_linux/src/include/lx_emul/irq.h b/repos/dde_linux/src/include/lx_emul/irq.h index 6914a8bc1e..12ab064fdf 100644 --- a/repos/dde_linux/src/include/lx_emul/irq.h +++ b/repos/dde_linux/src/include/lx_emul/irq.h @@ -31,7 +31,7 @@ int lx_emul_irq_task_function(void * data); extern void * lx_emul_irq_task_struct; -unsigned int lx_emul_irq_last(void); +int lx_emul_pending_irq(void); int lx_emul_irq_init(struct device_node *node, struct device_node *parent); diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h index 593b7b25be..7368d95dbf 100644 --- a/repos/dde_linux/src/include/lx_kit/device.h +++ b/repos/dde_linux/src/include/lx_kit/device.h @@ -23,6 +23,8 @@ #include #include +#include + namespace Lx_kit { using namespace Genode; @@ -63,7 +65,7 @@ class Lx_kit::Device : List::Element using Index = Platform::Device::Irq::Index; Index idx; - unsigned number; + Pending_irq number; Io_signal_handler handler; bool masked { true }; bool occured { false }; diff --git a/repos/dde_linux/src/include/lx_kit/env.h b/repos/dde_linux/src/include/lx_kit/env.h index a4b4e21af8..cfab2c7025 100644 --- a/repos/dde_linux/src/include/lx_kit/env.h +++ b/repos/dde_linux/src/include/lx_kit/env.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Lx_kit { @@ -50,7 +51,6 @@ struct Lx_kit::Env Scheduler scheduler { env.ep() }; Device_list devices { env.ep(), heap, platform }; Lx_kit::Timeout timeout { timer, scheduler }; - unsigned int last_irq { 0 }; Env(Genode::Env & env) : env(env) { } }; diff --git a/repos/dde_linux/src/include/lx_kit/pending_irq.h b/repos/dde_linux/src/include/lx_kit/pending_irq.h new file mode 100644 index 0000000000..c7bed0e446 --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/pending_irq.h @@ -0,0 +1,34 @@ +/* + * \brief Lx_kit pending interrupt utility + * \author Josef Soentgen + * \date 2023-06-22 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__PENDING_IRQ_H_ +#define _LX_KIT__PENDING_IRQ_H_ + +#include + +namespace Lx_kit { + + using namespace Genode; + + struct Pending_irq; +} + + +struct Lx_kit::Pending_irq : Genode::Fifo::Element +{ + unsigned value; + + Pending_irq(unsigned value) : value (value) { } +}; + +#endif /* _LX_KIT__PENDING_IRQ_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/scheduler.h b/repos/dde_linux/src/include/lx_kit/scheduler.h index d0ba22f2e5..a657d4153f 100644 --- a/repos/dde_linux/src/include/lx_kit/scheduler.h +++ b/repos/dde_linux/src/include/lx_kit/scheduler.h @@ -15,8 +15,10 @@ */ #include +#include #include #include +#include namespace Lx_kit { class Scheduler; @@ -45,6 +47,8 @@ class Lx_kit::Scheduler Signal_handler _execute_schedule; + Genode::Fifo _pending_irqs { }; + public: Task & current(); @@ -60,7 +64,13 @@ class Lx_kit::Scheduler void execute(); - void unblock_irq_handler(); + void unblock_irq_handler(Pending_irq &); + template void pending_irq(FN const &fn) + { + _pending_irqs.dequeue([&] (Pending_irq const &pirq) { + fn(pirq.value); }); + } + void unblock_time_handler(); Task & task(void * t); diff --git a/repos/dde_linux/src/lib/lx_emul/irq.cc b/repos/dde_linux/src/lib/lx_emul/irq.cc index 960621c735..c9151754bb 100644 --- a/repos/dde_linux/src/lib/lx_emul/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/irq.cc @@ -39,7 +39,12 @@ extern "C" void lx_emul_irq_eoi(unsigned int irq) } -extern "C" unsigned int lx_emul_irq_last() +extern "C" int lx_emul_pending_irq() { - return Lx_kit::env().last_irq; + int pending_irq = -1; + + Lx_kit::env().scheduler.pending_irq([&] (unsigned int irq) { + pending_irq = (int)irq; }); + + return pending_irq; } diff --git a/repos/dde_linux/src/lib/lx_emul/pci.cc b/repos/dde_linux/src/lib/lx_emul/pci.cc index 713492293a..9655dd3511 100644 --- a/repos/dde_linux/src/lib/lx_emul/pci.cc +++ b/repos/dde_linux/src/lib/lx_emul/pci.cc @@ -60,7 +60,7 @@ lx_emul_pci_for_each_device(void * bus, lx_emul_add_device_callback_t fn) env().devices.for_each([&] (Device & d) { unsigned irq = 0; d.for_each_irq([&] (Device::Irq & i) { - if (!irq) irq = i.number; }); + if (!irq) irq = i.number.value; }); d.for_pci_config([&] (Device::Pci_config & cfg) { fn(bus, num++, d.name().string(), cfg.vendor_id, cfg.device_id, diff --git a/repos/dde_linux/src/lib/lx_emul/pin.cc b/repos/dde_linux/src/lib/lx_emul/pin.cc index 2a78f67975..2c838f161e 100644 --- a/repos/dde_linux/src/lib/lx_emul/pin.cc +++ b/repos/dde_linux/src/lib/lx_emul/pin.cc @@ -30,6 +30,8 @@ namespace { Lx_kit::Env &_env; + Lx_kit::Pending_irq _pending_irq { 0 }; + public: struct Number { unsigned value; }; @@ -38,11 +40,9 @@ namespace { void trigger_irq(Number number) { - /* - * Mirrored from 'Lx_kit::Device::Irq::handle' - */ - _env.last_irq = number.value; - _env.scheduler.unblock_irq_handler(); + _pending_irq.value = number.value; + + _env.scheduler.unblock_irq_handler(_pending_irq); _env.scheduler.schedule(); } }; diff --git a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c index 3643dd622a..bee4f5d034 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c @@ -171,22 +171,28 @@ int lx_emul_irq_task_function(void * data) for (;;) { lx_emul_task_schedule(true); - local_irq_save(flags); - irq_enter(); + for (;;) { + irq = lx_emul_pending_irq(); + if (irq == -1) + break; - irq = dde_irq_domain ? irq_find_mapping(dde_irq_domain, - lx_emul_irq_last()) - : lx_emul_irq_last(); + local_irq_save(flags); + irq_enter(); - if (!irq) { - ack_bad_irq(irq); - WARN_ONCE(true, "Unexpected interrupt %d received!\n", lx_emul_irq_last()); - } else { - generic_handle_irq(irq); + irq = dde_irq_domain ? irq_find_mapping(dde_irq_domain, + irq) + : irq; + + if (!irq) { + ack_bad_irq(irq); + WARN_ONCE(true, "Unexpected interrupt %d received!\n", irq); + } else { + generic_handle_irq(irq); + } + + irq_exit(); + local_irq_restore(flags); } - - irq_exit(); - local_irq_restore(flags); } return 0; diff --git a/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c b/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c index ebb5b94a57..09fd3405e5 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c @@ -53,22 +53,27 @@ int lx_emul_irq_task_function(void * data) for (;;) { lx_emul_task_schedule(true); - local_irq_save(flags); - irq_enter(); + for (;;) { - irq = lx_emul_irq_last(); + irq = lx_emul_pending_irq(); + if (irq == -1) + break; - if (!irq) { - ack_bad_irq(irq); - WARN_ONCE(true, "Unexpected interrupt %d received!\n", - lx_emul_irq_last()); - } else { - generic_handle_irq(irq); - lx_emul_irq_eoi(irq); + local_irq_save(flags); + irq_enter(); + + if (!irq) { + ack_bad_irq(irq); + WARN_ONCE(true, "Unexpected interrupt %d received!\n", + irq); + } else { + generic_handle_irq(irq); + lx_emul_irq_eoi(irq); + } + + irq_exit(); + local_irq_restore(flags); } - - irq_exit(); - local_irq_restore(flags); } return 0; diff --git a/repos/dde_linux/src/lib/lx_emul/virt/irq.cc b/repos/dde_linux/src/lib/lx_emul/virt/irq.cc index 786be5fc19..da338afaf5 100644 --- a/repos/dde_linux/src/lib/lx_emul/virt/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/virt/irq.cc @@ -25,7 +25,12 @@ extern "C" void lx_emul_irq_mask(unsigned int ) { } extern "C" void lx_emul_irq_eoi(unsigned int ) { } -extern "C" unsigned int lx_emul_irq_last() +extern "C" int lx_emul_pending_irq() { - return Lx_kit::env().last_irq; + int pending_irq = -1; + + Lx_kit::env().scheduler.pending_irq([&] (unsigned int irq) { + pending_irq = (int)irq; }); + + return pending_irq; } diff --git a/repos/dde_linux/src/lib/lx_kit/device.cc b/repos/dde_linux/src/lib/lx_kit/device.cc index e3b2928ac8..5ecb072571 100644 --- a/repos/dde_linux/src/lib/lx_kit/device.cc +++ b/repos/dde_linux/src/lib/lx_kit/device.cc @@ -56,8 +56,7 @@ void Device::Irq::handle() if (masked) return; - env().last_irq = number; - env().scheduler.unblock_irq_handler(); + env().scheduler.unblock_irq_handler(number); } @@ -65,7 +64,8 @@ Device::Irq::Irq(Entrypoint & ep, unsigned idx, unsigned number) : idx{idx}, number(number), - handler(ep, *this, &Irq::_handle) { } + handler(ep, *this, &Irq::_handle) +{ } /************ @@ -144,7 +144,7 @@ bool Device::irq_unmask(unsigned number) bool ret = false; for_each_irq([&] (Irq & irq) { - if (irq.number != number) + if (irq.number.value != number) return; ret = true; @@ -170,7 +170,7 @@ void Device::irq_mask(unsigned number) return; for_each_irq([&] (Irq & irq) { - if (irq.number == number) irq.masked = true; }); + if (irq.number.value == number) irq.masked = true; }); } @@ -181,7 +181,7 @@ void Device::irq_ack(unsigned number) return; for_each_irq([&] (Irq & irq) { - if (irq.number != number || !irq.occured || !irq.session.constructed()) + if (irq.number.value != number || !irq.occured || !irq.session.constructed()) return; irq.occured = false; irq.session->ack(); diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc index 001cc039e4..712c5e23ad 100644 --- a/repos/dde_linux/src/lib/lx_kit/scheduler.cc +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -74,8 +74,10 @@ void Scheduler::remove(Task & task) } -void Scheduler::unblock_irq_handler() +void Scheduler::unblock_irq_handler(Pending_irq &pirq) { + _pending_irqs.enqueue(pirq); + for (Task * t = _present_list.first(); t; t = t->next()) { if (t->type() == Task::IRQ_HANDLER) t->unblock(); }