mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
lx_kit: support multiple pending IRQs
Decoupling the scheduler execution can lead to missed interrupts because the current implementation only handles one pending interrupt and requires immediate processing. This commit introduces a helper object that is used to capture any occuring interrupts that are then handled consecutively. Issue #4927.
This commit is contained in:
parent
caac994da8
commit
1cac134030
@ -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);
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <util/list.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <lx_kit/pending_irq.h>
|
||||
|
||||
namespace Lx_kit {
|
||||
using namespace Genode;
|
||||
|
||||
@ -63,7 +65,7 @@ class Lx_kit::Device : List<Device>::Element
|
||||
using Index = Platform::Device::Irq::Index;
|
||||
|
||||
Index idx;
|
||||
unsigned number;
|
||||
Pending_irq number;
|
||||
Io_signal_handler<Irq> handler;
|
||||
bool masked { true };
|
||||
bool occured { false };
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <lx_kit/memory.h>
|
||||
#include <lx_kit/scheduler.h>
|
||||
#include <lx_kit/timeout.h>
|
||||
#include <lx_kit/pending_irq.h>
|
||||
|
||||
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) { }
|
||||
};
|
||||
|
34
repos/dde_linux/src/include/lx_kit/pending_irq.h
Normal file
34
repos/dde_linux/src/include/lx_kit/pending_irq.h
Normal file
@ -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 <util/fifo.h>
|
||||
|
||||
namespace Lx_kit {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Pending_irq;
|
||||
}
|
||||
|
||||
|
||||
struct Lx_kit::Pending_irq : Genode::Fifo<Lx_kit::Pending_irq>::Element
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
Pending_irq(unsigned value) : value (value) { }
|
||||
};
|
||||
|
||||
#endif /* _LX_KIT__PENDING_IRQ_H_ */
|
@ -15,8 +15,10 @@
|
||||
*/
|
||||
|
||||
#include <base/entrypoint.h>
|
||||
#include <util/fifo.h>
|
||||
#include <util/list.h>
|
||||
#include <lx_kit/task.h>
|
||||
#include <lx_kit/pending_irq.h>
|
||||
|
||||
namespace Lx_kit {
|
||||
class Scheduler;
|
||||
@ -45,6 +47,8 @@ class Lx_kit::Scheduler
|
||||
|
||||
Signal_handler<Scheduler> _execute_schedule;
|
||||
|
||||
Genode::Fifo<Lx_kit::Pending_irq> _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 <typename FN> void pending_irq(FN const &fn)
|
||||
{
|
||||
_pending_irqs.dequeue([&] (Pending_irq const &pirq) {
|
||||
fn(pirq.value); });
|
||||
}
|
||||
|
||||
void unblock_time_handler();
|
||||
|
||||
Task & task(void * t);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user