From fb00f4ab4802d18baa189ff124c9d6ffb96c9b20 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Mon, 25 Mar 2024 09:43:22 +0100 Subject: [PATCH] WIP dde_linux: fix IRQ masking/unmasking Unmasking of a pending interrupt did not lead to immediate IRQ handler execution in all cases. Issue #5164 --- repos/dde_linux/src/include/lx_emul/irq.h | 2 + repos/dde_linux/src/include/lx_kit/device.h | 11 ++- repos/dde_linux/src/include/lx_kit/env.h | 1 - .../src/include/lx_kit/pending_irq.h | 34 -------- .../dde_linux/src/include/lx_kit/scheduler.h | 11 +-- repos/dde_linux/src/lib/lx_emul/irq.cc | 13 ++- repos/dde_linux/src/lib/lx_emul/pci.cc | 2 +- repos/dde_linux/src/lib/lx_emul/pin.cc | 9 +-- .../src/lib/lx_emul/spec/x86/irqchip.c | 12 ++- repos/dde_linux/src/lib/lx_emul/virt/irq.cc | 10 +-- repos/dde_linux/src/lib/lx_kit/device.cc | 81 +++++++++++++------ repos/dde_linux/src/lib/lx_kit/scheduler.cc | 4 +- 12 files changed, 92 insertions(+), 98 deletions(-) delete mode 100644 repos/dde_linux/src/include/lx_kit/pending_irq.h diff --git a/repos/dde_linux/src/include/lx_emul/irq.h b/repos/dde_linux/src/include/lx_emul/irq.h index 12ab064fdf2..bd7cfd18e22 100644 --- a/repos/dde_linux/src/include/lx_emul/irq.h +++ b/repos/dde_linux/src/include/lx_emul/irq.h @@ -33,6 +33,8 @@ extern void * lx_emul_irq_task_struct; int lx_emul_pending_irq(void); +void lx_emul_reset_pending_irq(unsigned int irq); + int lx_emul_irq_init(struct device_node *node, struct device_node *parent); unsigned long lx_emul_irq_enable(void); diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h index 0a1c85fc183..c64e85942d8 100644 --- a/repos/dde_linux/src/include/lx_kit/device.h +++ b/repos/dde_linux/src/include/lx_kit/device.h @@ -23,7 +23,6 @@ #include #include -#include namespace Lx_kit { using namespace Genode; @@ -65,17 +64,19 @@ class Lx_kit::Device : List::Element using Index = Platform::Device::Irq::Index; Index idx; - Pending_irq number; + unsigned number; Io_signal_handler handler; bool masked { true }; - bool occured { false }; + bool pending { false }; Constructible session {}; Irq(Entrypoint & ep, unsigned idx, unsigned number); void _handle(); - void handle(); + void mask(); + void unmask(Platform::Device &); + void ack(); }; struct Io_port : List::Element @@ -169,6 +170,8 @@ class Lx_kit::Device : List::Element bool irq_unmask(unsigned irq); void irq_mask(unsigned irq); void irq_ack(unsigned irq); + int pending_irq(); + void reset_pending(unsigned irq); bool read_config(unsigned reg, unsigned len, unsigned *val); bool write_config(unsigned reg, unsigned len, unsigned val); diff --git a/repos/dde_linux/src/include/lx_kit/env.h b/repos/dde_linux/src/include/lx_kit/env.h index 310bd1dd2a6..584122cf264 100644 --- a/repos/dde_linux/src/include/lx_kit/env.h +++ b/repos/dde_linux/src/include/lx_kit/env.h @@ -22,7 +22,6 @@ #include #include #include -#include namespace Lx_kit { diff --git a/repos/dde_linux/src/include/lx_kit/pending_irq.h b/repos/dde_linux/src/include/lx_kit/pending_irq.h deleted file mode 100644 index c7bed0e4461..00000000000 --- a/repos/dde_linux/src/include/lx_kit/pending_irq.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * \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 677e892e557..c87bcfb2a3c 100644 --- a/repos/dde_linux/src/include/lx_kit/scheduler.h +++ b/repos/dde_linux/src/include/lx_kit/scheduler.h @@ -18,7 +18,6 @@ #include #include #include -#include namespace Lx_kit { class Scheduler; @@ -45,8 +44,6 @@ class Lx_kit::Scheduler void _execute(); - Genode::Fifo _pending_irqs { }; - public: Task & current(); @@ -62,13 +59,7 @@ class Lx_kit::Scheduler void execute(); - 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_irq_handler(); 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 c9151754bb2..b4d603f5ae5 100644 --- a/repos/dde_linux/src/lib/lx_emul/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/irq.cc @@ -43,8 +43,17 @@ extern "C" int lx_emul_pending_irq() { int pending_irq = -1; - Lx_kit::env().scheduler.pending_irq([&] (unsigned int irq) { - pending_irq = (int)irq; }); + Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { + if (pending_irq == -1) + pending_irq = d.pending_irq(); + }); return pending_irq; } + + +extern "C" void lx_emul_reset_pending_irq(unsigned int irq) +{ + Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { + d.reset_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 9655dd35116..713492293a8 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.value; }); + if (!irq) irq = i.number; }); 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 2c838f161e3..2b477d3b4af 100644 --- a/repos/dde_linux/src/lib/lx_emul/pin.cc +++ b/repos/dde_linux/src/lib/lx_emul/pin.cc @@ -30,7 +30,7 @@ namespace { Lx_kit::Env &_env; - Lx_kit::Pending_irq _pending_irq { 0 }; + unsigned _pending_irq = 0; public: @@ -40,9 +40,9 @@ namespace { void trigger_irq(Number number) { - _pending_irq.value = number.value; + _pending_irq = number.value; - _env.scheduler.unblock_irq_handler(_pending_irq); + _env.scheduler.unblock_irq_handler(); _env.scheduler.schedule(); } }; @@ -223,9 +223,6 @@ extern "C" void lx_emul_pin_control(char const *pin_name, bool enabled) } -extern "C" void lx_emul_backtrace(void); - - extern "C" int lx_emul_pin_sense(char const *pin_name) { bool result = false; 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 09fd3405e5d..db9503db151 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 @@ -30,6 +30,12 @@ static void dde_irq_mask(struct irq_data *d) } +static void dde_irq_ack(struct irq_data *d) +{ + lx_emul_reset_pending_irq(d->hwirq); +} + + int lx_emul_irq_init(struct device_node *node, struct device_node *parent) { return 0; @@ -41,7 +47,7 @@ struct irq_chip dde_irqchip_data_chip = { .irq_mask = dde_irq_mask, .irq_disable = dde_irq_mask, .irq_unmask = dde_irq_unmask, - .irq_mask_ack = dde_irq_mask, + .irq_ack = dde_irq_ack, }; @@ -54,7 +60,6 @@ int lx_emul_irq_task_function(void * data) lx_emul_task_schedule(true); for (;;) { - irq = lx_emul_pending_irq(); if (irq == -1) break; @@ -64,8 +69,7 @@ int lx_emul_irq_task_function(void * data) if (!irq) { ack_bad_irq(irq); - WARN_ONCE(true, "Unexpected interrupt %d received!\n", - irq); + WARN_ONCE(true, "Unexpected interrupt %d received!\n", irq); } else { generic_handle_irq(irq); lx_emul_irq_eoi(irq); 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 da338afaf51..ee35ac2d25d 100644 --- a/repos/dde_linux/src/lib/lx_emul/virt/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/virt/irq.cc @@ -25,12 +25,4 @@ extern "C" void lx_emul_irq_mask(unsigned int ) { } extern "C" void lx_emul_irq_eoi(unsigned int ) { } -extern "C" int lx_emul_pending_irq() -{ - int pending_irq = -1; - - Lx_kit::env().scheduler.pending_irq([&] (unsigned int irq) { - pending_irq = (int)irq; }); - - return pending_irq; -} +extern "C" int lx_emul_pending_irq() { return -1; } diff --git a/repos/dde_linux/src/lib/lx_kit/device.cc b/repos/dde_linux/src/lib/lx_kit/device.cc index 5ecb072571b..f2fd8900af3 100644 --- a/repos/dde_linux/src/lib/lx_kit/device.cc +++ b/repos/dde_linux/src/lib/lx_kit/device.cc @@ -38,25 +38,43 @@ bool Device::Io_port::match(uint16_t addr) } -/**************** - ** Device::Irq** - ****************/ +/***************** + ** Device::Irq ** + *****************/ void Device::Irq::_handle() { - handle(); + pending = true; + + env().scheduler.unblock_irq_handler(); env().scheduler.schedule(); } -void Device::Irq::handle() +void Device::Irq::ack() { - occured = true; + if (session.constructed()) + session->ack(); +} - if (masked) - return; - env().scheduler.unblock_irq_handler(number); +void Device::Irq::mask() +{ + masked = true; +} + + +void Device::Irq::unmask(Platform::Device &dev) +{ + if (!session.constructed()) { + session.construct(dev, idx); + session->sigh_omit_initial_signal(handler); + session->ack(); + } + + masked = false; + + env().scheduler.unblock_irq_handler(); } @@ -139,25 +157,42 @@ void * Device::io_mem_local_addr(addr_t phys_addr, size_t size) } +int Device::pending_irq() +{ + if (!_pdev.constructed()) + return -1; + + int result = -1; + + for_each_irq([&] (Irq & irq) { + if (result == -1 && !irq.masked && irq.pending) + result = irq.number; + }); + + return result; +} + + +void Device::reset_pending(unsigned number) +{ + for_each_irq([&] (Irq & irq) { + if (irq.number == number) + irq.pending = false; + }); +} + + bool Device::irq_unmask(unsigned number) { bool ret = false; for_each_irq([&] (Irq & irq) { - if (irq.number.value != number) + if (irq.number != number) return; ret = true; enable(); - - if (!irq.session.constructed()) { - 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(); + irq.unmask(*_pdev); }); return ret; @@ -170,8 +205,7 @@ void Device::irq_mask(unsigned number) return; for_each_irq([&] (Irq & irq) { - if (irq.number.value == number) irq.masked = true; }); - + if (irq.number == number) irq.mask(); }); } @@ -181,10 +215,9 @@ void Device::irq_ack(unsigned number) return; for_each_irq([&] (Irq & irq) { - if (irq.number.value != number || !irq.occured || !irq.session.constructed()) + if (irq.number != number) return; - irq.occured = false; - irq.session->ack(); + irq.ack(); }); } diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc index 2232c55cb4a..136623c896a 100644 --- a/repos/dde_linux/src/lib/lx_kit/scheduler.cc +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -74,10 +74,8 @@ void Scheduler::remove(Task & task) } -void Scheduler::unblock_irq_handler(Pending_irq &pirq) +void Scheduler::unblock_irq_handler() { - _pending_irqs.enqueue(pirq); - for (Task * t = _present_list.first(); t; t = t->next()) { if (t->type() == Task::IRQ_HANDLER) t->unblock(); }