diff --git a/repos/dde_linux/lib/import/import-lx_emul_common.inc b/repos/dde_linux/lib/import/import-lx_emul_common.inc index 3bfa059b1a..ba867dee29 100644 --- a/repos/dde_linux/lib/import/import-lx_emul_common.inc +++ b/repos/dde_linux/lib/import/import-lx_emul_common.inc @@ -19,6 +19,7 @@ SRC_CC += lx_emul/time.cc SRC_CC += lx_emul/irq_flags.cc SRC_C += lx_emul/clocksource.c +SRC_C += lx_emul/irqchip.c SRC_C += lx_emul/shadow/fs/exec.c SRC_C += lx_emul/shadow/kernel/cpu.c SRC_C += lx_emul/shadow/kernel/exit.c @@ -27,8 +28,8 @@ SRC_C += lx_emul/shadow/kernel/irq_work.c SRC_C += lx_emul/shadow/kernel/locking/spinlock.c SRC_C += lx_emul/shadow/kernel/pid.c SRC_C += lx_emul/shadow/kernel/printk/printk.c -SRC_C += lx_emul/shadow/kernel/sched/cputime.c SRC_C += lx_emul/shadow/kernel/sched/core.c +SRC_C += lx_emul/shadow/kernel/sched/cputime.c SRC_C += lx_emul/shadow/kernel/sched/fair.c SRC_C += lx_emul/shadow/kernel/sched/sched.c SRC_C += lx_emul/shadow/kernel/smp.c @@ -103,7 +104,6 @@ endif SHADOW_INC_DIR := $(DDE_LINUX_DIR)/src/include/lx_emul/shadow/include SPEC_SHADOW_INC_DIR := $(DDE_LINUX_DIR)/src/include/lx_emul/shadow/arch/$(LX_ARCH)/include -SRC_C += lx_emul/spec/$(GEN_ARCH)/irqchip.c SRC_C += lx_emul/spec/$(GEN_ARCH)/start.c SRC_S += lx_kit/spec/$(SPEC_ARCH)/setjmp.S diff --git a/repos/dde_linux/src/include/lx_emul/irq.h b/repos/dde_linux/src/include/lx_emul/irq.h index 12ab064fdf..911d6ffdb7 100644 --- a/repos/dde_linux/src/include/lx_emul/irq.h +++ b/repos/dde_linux/src/include/lx_emul/irq.h @@ -25,7 +25,7 @@ void lx_emul_irq_unmask(unsigned int irq); void lx_emul_irq_mask(unsigned int irq); -void lx_emul_irq_eoi(unsigned int irq); +void lx_emul_irq_ack(unsigned int irq); int lx_emul_irq_task_function(void * data); diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h index 0a1c85fc18..d54dcea977 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; @@ -64,18 +63,21 @@ class Lx_kit::Device : List::Element { using Index = Platform::Device::Irq::Index; + enum State { IDLE, PENDING, MASKED, MASKED_PENDING }; + Index idx; - Pending_irq number; + unsigned number; Io_signal_handler handler; - bool masked { true }; - bool occured { false }; + State state { MASKED }; 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 +171,7 @@ class Lx_kit::Device : List::Element bool irq_unmask(unsigned irq); void irq_mask(unsigned irq); void irq_ack(unsigned irq); + int pending_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 310bd1dd2a..584122cf26 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 c7bed0e446..0000000000 --- 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 677e892e55..c87bcfb2a3 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 c9151754bb..cd8b2656ac 100644 --- a/repos/dde_linux/src/lib/lx_emul/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/irq.cc @@ -32,7 +32,7 @@ extern "C" void lx_emul_irq_mask(unsigned int irq) } -extern "C" void lx_emul_irq_eoi(unsigned int irq) +extern "C" void lx_emul_irq_ack(unsigned int irq) { Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { d.irq_ack(irq); }); @@ -43,8 +43,10 @@ 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; } diff --git a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c b/repos/dde_linux/src/lib/lx_emul/irqchip.c similarity index 91% rename from repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c rename to repos/dde_linux/src/lib/lx_emul/irqchip.c index 083e9f0648..2952b77b66 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/irqchip.c @@ -1,6 +1,8 @@ /* * \brief Linux DDE interrupt controller * \author Stefan Kalkowski + * \author Josef Soentgen + * \author Christian Helmuth * \date 2021-03-10 */ @@ -19,17 +21,10 @@ #include #include <../kernel/irq/internals.h> -static int dde_irq_set_wake(struct irq_data *d, unsigned int on) -{ - lx_emul_trace_and_stop(__func__); - return 0; -} - -static void dde_irq_unmask(struct irq_data *d) +static void dde_irq_ack(struct irq_data *d) { - lx_emul_irq_eoi(d->hwirq); - lx_emul_irq_unmask(d->hwirq); + lx_emul_irq_ack(d->hwirq); } @@ -39,9 +34,9 @@ static void dde_irq_mask(struct irq_data *d) } -static void dde_irq_eoi(struct irq_data *d) +static void dde_irq_unmask(struct irq_data *d) { - lx_emul_irq_eoi(d->hwirq); + lx_emul_irq_unmask(d->hwirq); } @@ -55,14 +50,16 @@ static int dde_irq_set_type(struct irq_data *d, unsigned int type) struct irq_chip dde_irqchip_data_chip = { .name = "dde-irqs", - .irq_eoi = dde_irq_eoi, + .irq_disable = dde_irq_mask, + .irq_ack = dde_irq_ack, .irq_mask = dde_irq_mask, .irq_unmask = dde_irq_unmask, - .irq_set_wake = dde_irq_set_wake, + .irq_eoi = dde_irq_ack, .irq_set_type = dde_irq_set_type, }; +#ifdef CONFIG_OF #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY static int dde_domain_translate(struct irq_domain * d, struct irq_fwspec * fwspec, @@ -126,6 +123,7 @@ static const struct irq_domain_ops dde_irqchip_data_domain_ops = { struct irq_domain *dde_irq_domain; + int lx_emul_irq_init(struct device_node *node, struct device_node *parent) { dde_irq_domain = irq_domain_create_tree(&node->fwnode, @@ -167,6 +165,18 @@ IRQCHIP_DECLARE(dde_gic_a9, "arm,cortex-a9-gic", lx_emul_irq_init); IRQCHIP_DECLARE(dde_gic_400, "arm,gic-400", lx_emul_irq_init); +static int map_irq(int irq) +{ + return dde_irq_domain ? irq_find_mapping(dde_irq_domain, irq) : irq; +} + +#else + +static int map_irq(int irq) { return irq; } + +#endif /* CONFIG_OF */ + + int lx_emul_irq_task_function(void * data) { int irq; @@ -183,9 +193,7 @@ int lx_emul_irq_task_function(void * data) local_irq_save(flags); irq_enter(); - irq = dde_irq_domain ? irq_find_mapping(dde_irq_domain, - irq) - : irq; + irq = map_irq(irq); if (!irq) { ack_bad_irq(irq); diff --git a/repos/dde_linux/src/lib/lx_emul/pci.cc b/repos/dde_linux/src/lib/lx_emul/pci.cc index 9655dd3511..713492293a 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 2c838f161e..2b477d3b4a 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 deleted file mode 100644 index 09fd3405e5..0000000000 --- a/repos/dde_linux/src/lib/lx_emul/spec/x86/irqchip.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * \brief Linux DDE x86 interrupt controller - * \author Josef Soentgen - * \date 2022-01-20 - */ - -/* - * Copyright (C) 2022 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#include -#include -#include -#include -#include <../kernel/irq/internals.h> - - -static void dde_irq_unmask(struct irq_data *d) -{ - lx_emul_irq_unmask(d->hwirq); -} - - -static void dde_irq_mask(struct irq_data *d) -{ - lx_emul_irq_mask(d->hwirq); -} - - -int lx_emul_irq_init(struct device_node *node, struct device_node *parent) -{ - return 0; -} - - -struct irq_chip dde_irqchip_data_chip = { - .name = "dde-irqs", - .irq_mask = dde_irq_mask, - .irq_disable = dde_irq_mask, - .irq_unmask = dde_irq_unmask, - .irq_mask_ack = dde_irq_mask, -}; - - -int lx_emul_irq_task_function(void * data) -{ - unsigned long flags; - int irq; - - for (;;) { - lx_emul_task_schedule(true); - - for (;;) { - - irq = lx_emul_pending_irq(); - if (irq == -1) - break; - - 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); - } - } - - return 0; -} - - -struct task_struct irq_task = { - .__state = 0, - .usage = REFCOUNT_INIT(2), - .flags = PF_KTHREAD, - .prio = MAX_PRIO - 20, - .static_prio = MAX_PRIO - 20, - .normal_prio = MAX_PRIO - 20, - .policy = SCHED_NORMAL, - .cpus_ptr = &irq_task.cpus_mask, - .cpus_mask = CPU_MASK_ALL, - .nr_cpus_allowed = 1, - .mm = NULL, - .active_mm = NULL, - .tasks = LIST_HEAD_INIT(irq_task.tasks), - .real_parent = &irq_task, - .parent = &irq_task, - .children = LIST_HEAD_INIT(irq_task.children), - .sibling = LIST_HEAD_INIT(irq_task.sibling), - .group_leader = &irq_task, - .comm = "kirqd", - .thread = INIT_THREAD, - .pending = { - .list = LIST_HEAD_INIT(irq_task.pending.list), - .signal = {{0}} - }, - .blocked = {{0}}, -}; -void * lx_emul_irq_task_struct = &irq_task; 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 da338afaf5..3fb8cf3ead 100644 --- a/repos/dde_linux/src/lib/lx_emul/virt/irq.cc +++ b/repos/dde_linux/src/lib/lx_emul/virt/irq.cc @@ -22,15 +22,7 @@ extern "C" void lx_emul_irq_unmask(unsigned int ) { } extern "C" void lx_emul_irq_mask(unsigned int ) { } -extern "C" void lx_emul_irq_eoi(unsigned int ) { } +extern "C" void lx_emul_irq_ack(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 5ecb072571..b6f4a9b334 100644 --- a/repos/dde_linux/src/lib/lx_kit/device.cc +++ b/repos/dde_linux/src/lib/lx_kit/device.cc @@ -38,25 +38,65 @@ bool Device::Io_port::match(uint16_t addr) } -/**************** - ** Device::Irq** - ****************/ +/***************** + ** Device::Irq ** + *****************/ void Device::Irq::_handle() { - handle(); + switch (state) { + case IDLE: state = PENDING; break; + case PENDING: state = PENDING; break; + case MASKED: state = MASKED_PENDING; break; + case MASKED_PENDING: state = MASKED_PENDING; break; + } + + 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; + switch (state) { + case IDLE: state = IDLE; break; + case PENDING: state = IDLE; break; + case MASKED: state = MASKED; break; + case MASKED_PENDING: state = MASKED; break; + } +} - env().scheduler.unblock_irq_handler(number); + +void Device::Irq::mask() +{ + switch (state) { + case IDLE: state = MASKED; break; + case MASKED: state = MASKED; break; + case PENDING: state = MASKED_PENDING; break; + case MASKED_PENDING: state = MASKED_PENDING; break; + } +} + + +void Device::Irq::unmask(Platform::Device &dev) +{ + if (!session.constructed()) { + session.construct(dev, idx); + session->sigh_omit_initial_signal(handler); + session->ack(); + } + + switch (state) { + case IDLE: state = IDLE; break; + case MASKED: state = IDLE; break; + case PENDING: state = PENDING; break; + case MASKED_PENDING: state = PENDING; break; + } + + env().scheduler.unblock_irq_handler(); } @@ -139,25 +179,33 @@ 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.state == Irq::PENDING) + result = irq.number; + }); + + return result; +} + + 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 +218,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 +228,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 2232c55cb4..136623c896 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(); }