diff --git a/repos/base-hw/include/kernel/interface.h b/repos/base-hw/include/kernel/interface.h index b19af0a793..81744b5cb4 100644 --- a/repos/base-hw/include/kernel/interface.h +++ b/repos/base-hw/include/kernel/interface.h @@ -15,34 +15,32 @@ #define _INCLUDE__KERNEL__INTERFACE_H_ /* base-hw includes */ +#include #include namespace Kernel { - using addr_t = Genode::addr_t; - using size_t = Genode::size_t; - using capid_t = Genode::uint16_t; - - constexpr capid_t cap_id_invalid() { return 0; } - /** * Kernel names of the kernel calls */ - constexpr Call_arg call_id_pause_current_thread() { return 0; } - constexpr Call_arg call_id_resume_local_thread() { return 1; } - constexpr Call_arg call_id_yield_thread() { return 2; } - constexpr Call_arg call_id_send_request_msg() { return 3; } - constexpr Call_arg call_id_send_reply_msg() { return 4; } - constexpr Call_arg call_id_await_request_msg() { return 5; } - constexpr Call_arg call_id_kill_signal_context() { return 6; } - constexpr Call_arg call_id_submit_signal() { return 7; } - constexpr Call_arg call_id_await_signal() { return 8; } - constexpr Call_arg call_id_ack_signal() { return 9; } + constexpr Call_arg call_id_pause_current_thread() { return 0; } + constexpr Call_arg call_id_resume_local_thread() { return 1; } + constexpr Call_arg call_id_yield_thread() { return 2; } + constexpr Call_arg call_id_send_request_msg() { return 3; } + constexpr Call_arg call_id_send_reply_msg() { return 4; } + constexpr Call_arg call_id_await_request_msg() { return 5; } + constexpr Call_arg call_id_kill_signal_context() { return 6; } + constexpr Call_arg call_id_submit_signal() { return 7; } + constexpr Call_arg call_id_await_signal() { return 8; } + constexpr Call_arg call_id_ack_signal() { return 9; } constexpr Call_arg call_id_print_char() { return 10; } constexpr Call_arg call_id_update_data_region() { return 11; } constexpr Call_arg call_id_update_instr_region() { return 12; } constexpr Call_arg call_id_ack_cap() { return 13; } constexpr Call_arg call_id_delete_cap() { return 14; } + constexpr Call_arg call_id_timeout() { return 15; } + constexpr Call_arg call_id_timeout_age_us() { return 16; } + constexpr Call_arg call_id_timeout_max_us() { return 17; } /***************************************************************** @@ -81,6 +79,44 @@ namespace Kernel Call_arg arg_5); + /** + * Install timeout for calling thread + * + * \param duration_us timeout duration in microseconds + * \param sigid local name of signal context to trigger + * + * This call always overwrites the last timeout installed by the thread + * if any. + */ + inline int timeout(time_t const duration_us, capid_t const sigid) + { + return call(call_id_timeout(), duration_us, sigid); + } + + + /** + * Return time in microseconds since the caller installed its last timeout + * + * Must not be called if the installation is older than 'timeout_max_us'. + */ + inline time_t timeout_age_us() + { + return call(call_id_timeout_age_us()); + } + + + /** + * Return the constant maximum installable timeout in microseconds + * + * The return value is also the maximum delay to call 'timeout_age_us' + * for a timeout after its installation. + */ + inline time_t timeout_max_us() + { + return call(call_id_timeout_max_us()); + } + + /** * Pause execution of calling thread */ diff --git a/repos/base-hw/include/kernel/types.h b/repos/base-hw/include/kernel/types.h new file mode 100644 index 0000000000..d6be5af369 --- /dev/null +++ b/repos/base-hw/include/kernel/types.h @@ -0,0 +1,31 @@ +/* + * \brief Public kernel types + * \author Martin stein + * \date 2016-03-23 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _KERNEL__TYPES_H_ +#define _KERNEL__TYPES_H_ + +/* base-hw includes */ +#include +#include + +namespace Kernel +{ + using addr_t = Genode::addr_t; + using size_t = Genode::size_t; + using capid_t = Genode::uint16_t; + using time_t = unsigned long; + + constexpr capid_t cap_id_invalid() { return 0; } +} + +#endif /* _KERNEL__TYPES_H_ */ diff --git a/repos/base-hw/lib/mk/core.inc b/repos/base-hw/lib/mk/core.inc index 36e7bb1eea..84ebc13dc3 100644 --- a/repos/base-hw/lib/mk/core.inc +++ b/repos/base-hw/lib/mk/core.inc @@ -56,6 +56,7 @@ SRC_CC += kernel/ipc_node.cc SRC_CC += kernel/irq.cc SRC_CC += kernel/pd.cc SRC_CC += kernel/cpu.cc +SRC_CC += kernel/clock.cc SRC_CC += kernel/object.cc SRC_CC += init_main_thread.cc SRC_CC += capability.cc diff --git a/repos/base-hw/src/core/cpu_session_support.cc b/repos/base-hw/src/core/cpu_session_support.cc index e3f7f1fbe5..655b38d194 100644 --- a/repos/base-hw/src/core/cpu_session_support.cc +++ b/repos/base-hw/src/core/cpu_session_support.cc @@ -29,7 +29,7 @@ Dataspace_capability Cpu_thread_component::utcb() Cpu_session::Quota Cpu_session_component::quota() { - size_t const spu = Kernel::cpu_quota_ms * 1000; + size_t const spu = Kernel::cpu_quota_us; size_t const u = quota_lim_downscale(_quota, spu); return { spu, u }; } diff --git a/repos/base-hw/src/core/include/kernel/clock.h b/repos/base-hw/src/core/include/kernel/clock.h new file mode 100644 index 0000000000..cd2bd812e3 --- /dev/null +++ b/repos/base-hw/src/core/include/kernel/clock.h @@ -0,0 +1,107 @@ +/* + * \brief A clock manages a continuous time and timeouts on it + * \author Martin Stein + * \date 2016-03-23 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__KERNEL__CLOCK_H_ +#define _CORE__INCLUDE__KERNEL__CLOCK_H_ + +/* base-hw includes */ +#include + +/* Genode includes */ +#include + +/* Core includes */ +#include + +namespace Kernel +{ + class Timeout; + class Clock; +} + +/** + * A timeout causes a kernel pass and the call of a timeout specific handle + */ +class Kernel::Timeout : public Genode::List::Element +{ + friend class Clock; + + private: + + bool _listed = false; + time_t _start = 0; + time_t _end = 0; + + public: + + /** + * Callback handle + */ + virtual void timeout_triggered() { } + + virtual ~Timeout() { } +}; + +/** + * A clock manages a continuous time and timeouts on it + */ +class Kernel::Clock +{ + private: + + unsigned const _cpu_id; + Timer * const _timer; + time_t _time = 0; + Genode::List _timeout_list; + time_t _last_timeout_duration = 0; + + void _insert_timeout(Timeout * const timeout); + + void _remove_timeout(Timeout * const timeout); + + public: + + Clock(unsigned const cpu_id, Timer * const timer); + + /** + * Set-up timer according to the current timeout schedule + */ + void schedule_timeout(); + + /** + * Update time and work off expired timeouts + * + * \return time that passed since the last scheduling + */ + time_t update_time(); + void process_timeouts(); + + /** + * Set-up 'timeout' to trigger at time + 'duration' + */ + void set_timeout(Timeout * const timeout, time_t const duration); + + /** + * Return native time value that equals the given microseconds 'us' + */ + time_t us_to_tics(time_t const us) const; + + /** + * Return microseconds that passed since the last set-up of 'timeout' + */ + time_t timeout_age_us(Timeout const * const timeout) const; + + time_t timeout_max_us() const; +}; + +#endif /* _CORE__INCLUDE__KERNEL__CLOCK_H_ */ diff --git a/repos/base-hw/src/core/include/kernel/configuration.h b/repos/base-hw/src/core/include/kernel/configuration.h index 4c0e5af601..8400e650ae 100644 --- a/repos/base-hw/src/core/include/kernel/configuration.h +++ b/repos/base-hw/src/core/include/kernel/configuration.h @@ -25,10 +25,10 @@ namespace Kernel constexpr unsigned cpu_priorities = 4; /* super period in CPU scheduling and the overall allocatable CPU time */ - constexpr unsigned cpu_quota_ms = 1000; + constexpr time_t cpu_quota_us = 1000000; /* time slice for the round-robin mode and the idle in CPU scheduling */ - constexpr unsigned cpu_fill_ms = 10; + constexpr time_t cpu_fill_us = 10000; } #endif /* _CORE__INCLUDE__KERNEL__CONFIGURATION_H_ */ diff --git a/repos/base-hw/src/core/include/kernel/cpu.h b/repos/base-hw/src/core/include/kernel/cpu.h index 7c89f60029..4964335c25 100644 --- a/repos/base-hw/src/core/include/kernel/cpu.h +++ b/repos/base-hw/src/core/include/kernel/cpu.h @@ -16,7 +16,7 @@ #define _CORE__INCLUDE__KERNEL__CPU_H_ /* core includes */ -#include +#include #include #include #include @@ -190,6 +190,12 @@ class Kernel::Cpu_job : public Genode::Cpu::User_context, public Cpu_share */ bool own_share_active() { return Cpu_share::ready(); } + void timeout(Timeout * const timeout, time_t const duration_us); + + time_t timeout_age_us(Timeout const * const timeout) const; + + time_t timeout_max_us() const; + /*************** ** Accessors ** ***************/ @@ -227,8 +233,7 @@ class Kernel::Cpu_idle : public Cpu_job Cpu_job * helping_sink() { return this; } }; -class Kernel::Cpu : public Genode::Cpu, - public Irq::Pool +class Kernel::Cpu : public Genode::Cpu, public Irq::Pool, private Timeout { private: @@ -264,14 +269,14 @@ class Kernel::Cpu : public Genode::Cpu, }; unsigned const _id; + Clock _clock; Cpu_idle _idle; - Timer * const _timer; Cpu_scheduler _scheduler; Ipi _ipi_irq; Irq _timer_irq; /* timer irq implemented as empty event */ - unsigned _quota() const { return _timer->ms_to_tics(cpu_quota_ms); } - unsigned _fill() const { return _timer->ms_to_tics(cpu_fill_ms); } + unsigned _quota() const { return _clock.us_to_tics(cpu_quota_us); } + unsigned _fill() const { return _clock.us_to_tics(cpu_fill_us); } public: @@ -312,6 +317,11 @@ class Kernel::Cpu : public Genode::Cpu, */ Cpu_job& schedule(); + void set_timeout(Timeout * const timeout, time_t const duration_us); + + time_t timeout_age_us(Timeout const * const timeout) const; + + time_t timeout_max_us() const; /*************** ** Accessors ** diff --git a/repos/base-hw/src/core/include/kernel/thread.h b/repos/base-hw/src/core/include/kernel/thread.h index eeb98c3760..3868fd646c 100644 --- a/repos/base-hw/src/core/include/kernel/thread.h +++ b/repos/base-hw/src/core/include/kernel/thread.h @@ -78,7 +78,8 @@ class Kernel::Thread_event : public Signal_ack_handler class Kernel::Thread : public Kernel::Object, public Cpu_job, public Cpu_domain_update, - public Ipc_node, public Signal_context_killer, public Signal_handler + public Ipc_node, public Signal_context_killer, public Signal_handler, + private Timeout { friend class Thread_event; friend class Core_thread; @@ -106,6 +107,7 @@ class Kernel::Thread State _state; Signal_receiver * _signal_receiver; char const * const _label; + capid_t _timeout_sigid = 0; void _init(); @@ -245,6 +247,9 @@ class Kernel::Thread void _call_delete_obj(); void _call_ack_cap(); void _call_delete_cap(); + void _call_timeout(); + void _call_timeout_age_us(); + void _call_timeout_max_us(); template void _call_new(ARGS &&... args) @@ -345,6 +350,13 @@ class Kernel::Thread Cpu_job * helping_sink(); + /************* + ** Timeout ** + *************/ + + void timeout_triggered(); + + /*************** ** Accessors ** ***************/ diff --git a/repos/base-hw/src/core/include/spec/cortex_a9/timer.h b/repos/base-hw/src/core/include/spec/cortex_a9/timer.h index 179e7efd32..b217978fe1 100644 --- a/repos/base-hw/src/core/include/spec/cortex_a9/timer.h +++ b/repos/base-hw/src/core/include/spec/cortex_a9/timer.h @@ -14,20 +14,31 @@ #ifndef _CORE__INCLUDE__SPEC__CORTEX_A9__TIMER_H_ #define _CORE__INCLUDE__SPEC__CORTEX_A9__TIMER_H_ +/* base-hw includes */ +#include + /* Genode includes */ #include /* core includes */ #include -namespace Genode +namespace Genode { class Timer; } + +/** + * Timer driver for core + */ +class Genode::Timer : public Mmio { - /** - * Timer driver for core - */ - class Timer : public Mmio - { - enum { TICS_PER_MS = Board::CORTEX_A9_PRIVATE_TIMER_CLK / 1000 }; + private: + + using time_t = Kernel::time_t; + + enum { + TICS_PER_MS = + Board::CORTEX_A9_PRIVATE_TIMER_CLK / + Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000 + }; /** * Load value register @@ -46,6 +57,7 @@ namespace Genode { struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ + struct Prescaler : Bitfield<8,8> { }; }; /** @@ -56,54 +68,56 @@ namespace Genode struct Event : Bitfield<0,1> { }; /* if counter hit zero */ }; - public: + public: - /** - * Constructor - */ - Timer() : Mmio(Board::PRIVATE_TIMER_MMIO_BASE) - { - write(0); - } + /** + * Constructor + */ + Timer() : Mmio(Board::PRIVATE_TIMER_MMIO_BASE) + { + write(0); + } - /** - * Return kernel name of timer interrupt - */ - static unsigned interrupt_id(unsigned) { - return Board::PRIVATE_TIMER_IRQ; } + /** + * Return kernel name of timer interrupt + */ + static unsigned interrupt_id(unsigned const) { + return Board::PRIVATE_TIMER_IRQ; } - /** - * Start single timeout run - * - * \param tics delay of timer interrupt - */ - inline void start_one_shot(unsigned const tics, unsigned) - { - /* reset timer */ - write(1); - Control::access_t control = 0; - Control::Irq_enable::set(control, 1); - write(control); + /** + * Start single timeout run + * + * \param tics delay of timer interrupt + */ + void start_one_shot(time_t const tics, unsigned const) + { + enum { PRESCALER = Board::CORTEX_A9_PRIVATE_TIMER_DIV - 1 }; - /* load timer and start decrementing */ - write(tics); - write(1); - } + /* reset timer */ + write(1); + Control::access_t control = 0; + Control::Irq_enable::set(control, 1); + Control::Prescaler::set(control, PRESCALER); + write(control); - /** - * Translate 'ms' milliseconds to a native timer value - */ - static uint32_t ms_to_tics(unsigned const ms) - { - return ms * TICS_PER_MS; - } + /* load timer and start decrementing */ + write(tics); + write(1); + } - /** - * Return current native timer value - */ - unsigned value(unsigned const) { return read(); } - }; -} + time_t tics_to_us(time_t const tics) const { + return (tics / TICS_PER_MS) * 1000; } + + time_t us_to_tics(time_t const us) const { + return (us / 1000) * TICS_PER_MS; } + + /** + * Return current native timer value + */ + time_t value(unsigned const) { return read(); } + + time_t max_value() { return (Load::access_t)~0; } +}; namespace Kernel { class Timer : public Genode::Timer { }; } diff --git a/repos/base-hw/src/core/include/spec/exynos5/timer.h b/repos/base-hw/src/core/include/spec/exynos5/timer.h index 4be81e6159..7527989d04 100644 --- a/repos/base-hw/src/core/include/spec/exynos5/timer.h +++ b/repos/base-hw/src/core/include/spec/exynos5/timer.h @@ -14,6 +14,9 @@ #ifndef _CORE__INCLUDE__SPEC__EXYNOS5__TIMER_H_ #define _CORE__INCLUDE__SPEC__EXYNOS5__TIMER_H_ +/* base-hw includes */ +#include + /* core include */ #include @@ -32,6 +35,8 @@ class Genode::Timer : public Mmio { private: + using time_t = Kernel::time_t; + enum { PRESCALER = 1, DIV_MUX = 0, @@ -177,10 +182,8 @@ class Genode::Timer : public Mmio * * \param clock input clock */ - unsigned static _calc_tics_per_ms(unsigned const clock) - { - return clock / (PRESCALER + 1) / (1 << DIV_MUX) / 1000; - } + time_t static _calc_tics_per_ms(unsigned const clock) { + return clock / (PRESCALER + 1) / (1 << DIV_MUX) / 1000; } unsigned const _tics_per_ms; @@ -218,7 +221,7 @@ class Genode::Timer : public Mmio /** * Raise interrupt of CPU 'cpu' once after timeout 'tics' */ - inline void start_one_shot(unsigned const tics, unsigned const cpu) + void start_one_shot(time_t const tics, unsigned const cpu) { switch (cpu) { case 0: @@ -237,12 +240,7 @@ class Genode::Timer : public Mmio } } - /** - * Translate 'ms' milliseconds to a native timer value - */ - unsigned ms_to_tics(unsigned const ms) { return ms * _tics_per_ms; } - - unsigned value(unsigned const cpu) + time_t value(unsigned const cpu) { switch (cpu) { case 0: return read() ? 0 : read(); @@ -250,6 +248,14 @@ class Genode::Timer : public Mmio default: return 0; } } + + time_t tics_to_us(time_t const tics) const { + return (tics / _tics_per_ms) * 1000; } + + time_t us_to_tics(time_t const us) const { + return (us / 1000) * _tics_per_ms; } + + time_t max_value() { return (L0_frcnto::access_t)~0; } }; namespace Kernel { class Timer : public Genode::Timer { }; } diff --git a/repos/base-hw/src/core/include/spec/imx53/timer.h b/repos/base-hw/src/core/include/spec/imx53/timer.h index dc187d3bd5..d30663fca9 100644 --- a/repos/base-hw/src/core/include/spec/imx53/timer.h +++ b/repos/base-hw/src/core/include/spec/imx53/timer.h @@ -14,33 +14,164 @@ #ifndef _CORE__INCLUDE__SPEC__IMX53__TIMER_H_ #define _CORE__INCLUDE__SPEC__IMX53__TIMER_H_ +/* base-hw includes */ +#include + /* Genode includes */ -#include +#include /* core includes */ #include -namespace Genode -{ - /** - * Timer driver for core - */ - class Timer; -} +namespace Genode { class Timer; } -class Genode::Timer : public Epit_base +/** + * Timer driver for core + */ +class Genode::Timer : public Mmio { + private: + + using time_t = Kernel::time_t; + + enum { TICS_PER_MS = 33333 }; + + /** + * Control register + */ + struct Cr : Register<0x0, 32> + { + struct En : Bitfield<0, 1> { }; /* enable timer */ + + struct En_mod : Bitfield<1, 1> /* reload on enable */ + { + enum { RELOAD = 1 }; + }; + + struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */ + + struct Rld : Bitfield<3, 1> /* reload or roll-over */ + { + enum { RELOAD_FROM_LR = 1 }; + }; + + struct Prescaler : Bitfield<4, 12> /* clock input divisor */ + { + enum { DIVIDE_BY_1 = 0 }; + }; + + struct Swr : Bitfield<16, 1> { }; /* software reset bit */ + struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */ + struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */ + struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */ + struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */ + struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */ + + struct Om : Bitfield<22, 2> /* mode of the output pin */ + { + enum { DISCONNECTED = 0 }; + }; + + struct Clk_src : Bitfield<24, 2> /* select clock input */ + { + enum { HIGH_FREQ_REF_CLK = 2 }; + }; + + /** + * Register value that configures the timer for a one-shot run + */ + static access_t prepare_one_shot() + { + return En::bits(0) | + En_mod::bits(En_mod::RELOAD) | + Oci_en::bits(1) | + Rld::bits(Rld::RELOAD_FROM_LR) | + Prescaler::bits(Prescaler::DIVIDE_BY_1) | + Swr::bits(0) | + Iovw::bits(0) | + Dbg_en::bits(0) | + Wait_en::bits(0) | + Doz_en::bits(0) | + Stop_en::bits(0) | + Om::bits(Om::DISCONNECTED) | + Clk_src::bits(Clk_src::HIGH_FREQ_REF_CLK); + } + }; + + /** + * Status register + */ + struct Sr : Register<0x4, 32> + { + struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */ + }; + + struct Lr : Register<0x8, 32> { }; /* load value register */ + struct Cmpr : Register<0xc, 32> { }; /* compare value register */ + struct Cnt : Register<0x10, 32> { }; /* counter register */ + + /** + * Disable timer and clear its interrupt output + */ + void _reset() + { + /* wait until ongoing reset operations are finished */ + while (read()) ; + + /* disable timer */ + write(0); + + /* clear interrupt */ + write(1); + } + public: /** * Return kernel name of timer interrupt */ - static unsigned interrupt_id(unsigned) { return Board::EPIT_1_IRQ; } + static unsigned interrupt_id(unsigned const) + { + return Board::EPIT_1_IRQ; + } /** * Constructor */ - Timer() : Epit_base(Board::EPIT_1_MMIO_BASE) { } + Timer() : Mmio(Board::EPIT_1_MMIO_BASE) { } + + /** + * Start single timeout run + * + * \param tics delay of timer interrupt + */ + void start_one_shot(time_t const tics, unsigned const) + { + /* stop timer */ + _reset(); + + /* configure timer for a one-shot */ + write(Cr::prepare_one_shot()); + write(tics); + write(0); + + /* start timer */ + write(1); + } + + time_t tics_to_us(time_t const tics) const { + return (tics / TICS_PER_MS) * 1000; } + + time_t us_to_tics(time_t const us) const { + return (us / 1000) * TICS_PER_MS; } + + time_t max_value() { return (Cnt::access_t)~0; } + + /** + * Return current native timer value + */ + time_t value(unsigned const) { + return read() ? 0 : read(); } }; namespace Kernel { class Timer : public Genode::Timer { }; } diff --git a/repos/base-hw/src/core/include/spec/riscv/timer.h b/repos/base-hw/src/core/include/spec/riscv/timer.h index 56cdc680ea..d885a05cc5 100644 --- a/repos/base-hw/src/core/include/spec/riscv/timer.h +++ b/repos/base-hw/src/core/include/spec/riscv/timer.h @@ -14,6 +14,9 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +/* base-hw includes */ +#include + /* Genode includes */ #include #include @@ -30,6 +33,13 @@ struct Genode::Timer { private: + using time_t = Kernel::time_t; + + enum { + SPIKE_TIMER_HZ = 500000, + TICS_PER_MS = SPIKE_TIMER_HZ / 1000, + }; + addr_t _timeout = 0; addr_t _stime() @@ -48,48 +58,35 @@ struct Genode::Timer asm volatile ("csrs sie, %0" : : "r"(STIE)); } - enum { - SPIKE_TIMER_HZ = 500000, - MS_TICS = SPIKE_TIMER_HZ / 1000, - }; - /** * Start single timeout run * * \param tics delay of timer interrupt */ - void start_one_shot(unsigned const tics, unsigned /* cpu */) + void start_one_shot(time_t const tics, unsigned const) { _timeout = _stime() + tics; Machine::set_sys_timer(_timeout); } - /** - * Translate milliseconds to a native timer value - */ - unsigned ms_to_tics(unsigned const ms) - { - return ms * MS_TICS; - } + time_t tics_to_us(time_t const tics) const { + return (tics / TICS_PER_MS) * 1000; } - /** - * Translate native timer value to milliseconds - */ - unsigned tics_to_ms(unsigned const tics) - { - return tics / MS_TICS; - } + time_t us_to_tics(time_t const us) const { + return (us / 1000) * TICS_PER_MS; } + + time_t max_value() { return (addr_t)~0; } /** * Return current native timer value */ - unsigned value(unsigned const) + time_t value(unsigned const) { addr_t time = _stime(); return time < _timeout ? _timeout - time : 0; } - static unsigned interrupt_id(int) { return 1; } + static unsigned interrupt_id(unsigned const) { return 1; } }; namespace Kernel { class Timer : public Genode::Timer { }; } diff --git a/repos/base-hw/src/core/include/spec/rpi/timer.h b/repos/base-hw/src/core/include/spec/rpi/timer.h index 1d22037ae7..68cfc42e55 100644 --- a/repos/base-hw/src/core/include/spec/rpi/timer.h +++ b/repos/base-hw/src/core/include/spec/rpi/timer.h @@ -14,26 +14,30 @@ #ifndef _CORE__INCLUDE__SPEC__RPI__TIMER_H_ #define _CORE__INCLUDE__SPEC__RPI__TIMER_H_ +/* base-hw includes */ +#include + /* Genode includes */ #include /* core includes */ #include -namespace Genode -{ - /** - * Timer driver for core - * - * Timer channel 0 apparently doesn't work on the RPI, so we use channel 1 - */ - class Timer; -} +namespace Genode { class Timer; } +/** + * Timer driver for core + * + * Timer channel 0 apparently doesn't work on the RPI, so we use channel 1 + */ class Genode::Timer : public Mmio { private: + using time_t = Kernel::time_t; + + enum { TICS_PER_MS = Board::SYSTEM_TIMER_CLOCK / 1000 }; + struct Cs : Register<0x0, 32> { struct M1 : Bitfield<1, 1> { }; }; struct Clo : Register<0x4, 32> { }; struct Cmp : Register<0x10, 32> { }; @@ -42,9 +46,10 @@ class Genode::Timer : public Mmio Timer() : Mmio(Board::SYSTEM_TIMER_MMIO_BASE) { } - static unsigned interrupt_id(int) { return Board::SYSTEM_TIMER_IRQ; } + static unsigned interrupt_id(unsigned const) { + return Board::SYSTEM_TIMER_IRQ; } - inline void start_one_shot(uint32_t const tics, unsigned) + void start_one_shot(time_t const tics, unsigned const) { write(1); read(); @@ -52,10 +57,15 @@ class Genode::Timer : public Mmio write(read() + tics); } - static uint32_t ms_to_tics(unsigned const ms) { - return (Board::SYSTEM_TIMER_CLOCK / 1000) * ms; } + time_t tics_to_us(time_t const tics) const { + return (tics / TICS_PER_MS) * 1000; } - unsigned value(unsigned) + time_t us_to_tics(time_t const us) const { + return (us / 1000) * TICS_PER_MS; } + + time_t max_value() { return (Clo::access_t)~0; } + + time_t value(unsigned const) { Cmp::access_t const cmp = read(); Clo::access_t const clo = read(); diff --git a/repos/base-hw/src/core/include/spec/x86/timer.h b/repos/base-hw/src/core/include/spec/x86/timer.h index 9c5884dbea..a62812f262 100644 --- a/repos/base-hw/src/core/include/spec/x86/timer.h +++ b/repos/base-hw/src/core/include/spec/x86/timer.h @@ -15,6 +15,9 @@ #ifndef _CORE__INCLUDE__SPEC__X86__TIMER_H_ #define _CORE__INCLUDE__SPEC__X86__TIMER_H_ +/* base-hw includes */ +#include + /* Genode includes */ #include #include @@ -24,18 +27,17 @@ #include #include -namespace Genode -{ - /** - * LAPIC-based timer driver for core - */ - class Timer; -} +namespace Genode { class Timer; } +/** + * LAPIC-based timer driver for core + */ class Genode::Timer : public Mmio { private: + using time_t = Kernel::time_t; + enum { /* PIT constants */ PIT_TICK_RATE = 1193182ul, @@ -58,6 +60,17 @@ class Genode::Timer : public Mmio struct Tmr_initial : Register <0x380, 32> { }; struct Tmr_current : Register <0x390, 32> { }; + struct Divide_configuration : Register <0x03e0, 32> + { + struct Divide_value_0_2 : Bitfield<0, 2> { }; + struct Divide_value_2_1 : Bitfield<3, 1> { }; + struct Divide_value : + Bitset_2 + { + enum { MAX = 6 }; + }; + }; + uint32_t _tics_per_ms = 0; /* Measure LAPIC timer frequency using PIT channel 2 */ @@ -91,6 +104,9 @@ class Genode::Timer : public Mmio Timer() : Mmio(Board::MMIO_LAPIC_BASE) { + write( + Divide_configuration::Divide_value::MAX); + /* Enable LAPIC timer in one-shot mode */ write(Board::TIMER_VECTOR_KERNEL); write(0); @@ -99,39 +115,34 @@ class Genode::Timer : public Mmio /* Calculate timer frequency */ _tics_per_ms = _pit_calc_timer_freq(); - PINF("LAPIC: timer frequency %u kHz", _tics_per_ms); } /** * Disable PIT timer channel. This is necessary since BIOS sets up * channel 0 to fire periodically. */ - static void disable_pit(void) + static void disable_pit() { outb(PIT_MODE, 0x30); outb(PIT_CH0_DATA, 0); outb(PIT_CH0_DATA, 0); } - static unsigned interrupt_id(int) - { - return Board::TIMER_VECTOR_KERNEL; - } + static unsigned interrupt_id(unsigned const) { + return Board::TIMER_VECTOR_KERNEL; } - inline void start_one_shot(uint32_t const tics, unsigned) - { - write(tics); - } + void start_one_shot(time_t const tics, unsigned const) { + write(tics); } - uint32_t ms_to_tics(unsigned const ms) - { - return ms * _tics_per_ms; - } + time_t tics_to_us(time_t const tics) const { + return (tics / _tics_per_ms) * 1000; } - unsigned value(unsigned) - { - return read(); - } + time_t us_to_tics(time_t const us) const { + return (us / 1000) * _tics_per_ms; } + + time_t max_value() { return (Tmr_initial::access_t)~0; } + + time_t value(unsigned const) { return read(); } }; namespace Kernel { class Timer : public Genode::Timer { }; } diff --git a/repos/base-hw/src/core/include/spec/x86_64/muen/timer.h b/repos/base-hw/src/core/include/spec/x86_64/muen/timer.h index cb375a1b04..fe7e76b933 100644 --- a/repos/base-hw/src/core/include/spec/x86_64/muen/timer.h +++ b/repos/base-hw/src/core/include/spec/x86_64/muen/timer.h @@ -15,6 +15,7 @@ #define _CORE__INCLUDE__SPEC__X86_64__MUEN__TIMER_H_ #include +#include /* core includes */ #include @@ -32,9 +33,9 @@ class Genode::Timer { private: - enum { - TIMER_DISABLED = ~0ULL, - }; + using time_t = Kernel::time_t; + + enum { TIMER_DISABLED = ~0ULL }; uint64_t _tics_per_ms; @@ -71,22 +72,21 @@ class Genode::Timer region.address, _tics_per_ms, _timer_page->vector); } - static unsigned interrupt_id(int) - { - return Board::TIMER_VECTOR_KERNEL; - } + static unsigned interrupt_id(int) { + return Board::TIMER_VECTOR_KERNEL; } - inline void start_one_shot(uint32_t const tics, unsigned) - { - _timer_page->value = rdtsc() + tics; - } + inline void start_one_shot(time_t const tics, unsigned) { + _timer_page->value = rdtsc() + tics; } - uint32_t ms_to_tics(unsigned const ms) - { - return ms * _tics_per_ms; - } + time_t tics_to_us(time_t const tics) const { + return (tics / _tics_per_ms) * 1000; } - unsigned value(unsigned) + time_t us_to_tics(time_t const us) const { + return (us / 1000) * _tics_per_ms; } + + time_t max_value() { return (time_t)~0; } + + time_t value(unsigned) { const uint64_t now = rdtsc(); if (_timer_page->value != TIMER_DISABLED @@ -96,9 +96,6 @@ class Genode::Timer return 0; } - /* - * Dummies - */ static void disable_pit(void) { } }; diff --git a/repos/base-hw/src/core/kernel/clock.cc b/repos/base-hw/src/core/kernel/clock.cc new file mode 100644 index 0000000000..f6ddcf8418 --- /dev/null +++ b/repos/base-hw/src/core/kernel/clock.cc @@ -0,0 +1,101 @@ +/* + * \brief A clock manages a continuous time and timeouts on it + * \author Martin Stein + * \date 2016-03-23 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Core includes */ +#include + +using namespace Kernel; + + +void Clock::_insert_timeout(Timeout * const timeout) +{ + /* timeouts may get re-inserted as result of an update */ + if (timeout->_listed) { _timeout_list.remove(timeout); } + timeout->_listed = true; + + /* timeouts are ordered ascending according to their end time */ + Timeout * t1 = 0; + Timeout * t2 = _timeout_list.first(); + for (; t2 && t2->_end < timeout->_end; t1 = t2, t2 = t2->next()) ; + _timeout_list.insert(timeout, t1); +} + + +void Clock::_remove_timeout(Timeout * const timeout) +{ + timeout->_listed = false; + _timeout_list.remove(timeout); +} + + +time_t Clock::us_to_tics(time_t const us) const +{ + return _timer->us_to_tics(us); +} + + +time_t Clock::timeout_age_us(Timeout const * const timeout) const +{ + time_t const age = (time_t)_time - timeout->_start; + return _timer->tics_to_us(age); +} + + +time_t Clock::timeout_max_us() const +{ + return _timer->tics_to_us(_timer->max_value()); +} + + +void Clock::set_timeout(Timeout * const timeout, time_t const duration) +{ + timeout->_start = _time; + timeout->_end = _time + duration; + _insert_timeout(timeout); +} + + +void Clock::schedule_timeout() +{ + Timeout const * const timeout = _timeout_list.first(); + time_t const duration = (time_t)timeout->_end - _time; + _last_timeout_duration = duration; + _timer->start_one_shot(duration, _cpu_id); +} + + +time_t Clock::update_time() +{ + /* update time */ + time_t const old_value = _last_timeout_duration; + time_t const new_value = _timer->value(_cpu_id); +// PERR("%lu %lu", old_value, new_value); + time_t const duration = old_value > new_value ? old_value - new_value : 1; + _time += duration; + return duration; +} + +void Clock::process_timeouts() +{ + while (true) { + Timeout * const timeout = _timeout_list.first(); + if (!timeout || timeout->_end > _time) { break; } + _remove_timeout(timeout); + timeout->timeout_triggered(); + } +} + + +Clock::Clock(unsigned const cpu_id, Timer * const timer) +: + _cpu_id(cpu_id), _timer(timer) { } diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 40778230ce..8826f7267d 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -37,6 +37,24 @@ namespace Kernel ** Cpu_job ** *************/ +time_t Cpu_job::timeout_age_us(Timeout const * const timeout) const +{ + return _cpu->timeout_age_us(timeout); +} + + +time_t Cpu_job::timeout_max_us() const +{ + return _cpu->timeout_max_us(); +} + + +void Cpu_job::timeout(Timeout * const timeout, time_t const us) +{ + _cpu->set_timeout(timeout, us); +} + + void Cpu_job::_activate_own_share() { _cpu->schedule(this); } @@ -89,7 +107,8 @@ void Cpu_job::quota(unsigned const q) Cpu_job::Cpu_job(Cpu_priority const p, unsigned const q) -: Cpu_share(p, q), _cpu(0) { } +: + Cpu_share(p, q), _cpu(0) { } Cpu_job::~Cpu_job() @@ -113,6 +132,17 @@ void Cpu_idle::_main() { while (1) { Genode::Cpu::wait_for_interrupt(); } } ** Cpu ** *********/ +void Cpu::set_timeout(Timeout * const timeout, time_t const duration_us) { + _clock.set_timeout(timeout, _clock.us_to_tics(duration_us)); } + + +time_t Cpu::timeout_age_us(Timeout const * const timeout) const { + return _clock.timeout_age_us(timeout); } + + +time_t Cpu::timeout_max_us() const { return _clock.timeout_max_us(); } + + void Cpu::schedule(Job * const job) { if (_id == executing_id()) { _scheduler.ready(job); } @@ -131,20 +161,20 @@ bool Cpu::interrupt(unsigned const irq_id) Cpu_job & Cpu::schedule() { - /* get new job */ - Job & old_job = scheduled_job(); - /* update scheduler */ - unsigned const old_time = _scheduler.head_quota(); - unsigned const new_time = _timer->value(_id); - unsigned quota = old_time > new_time ? old_time - new_time : 1; + time_t quota = _clock.update_time(); + Job & old_job = scheduled_job(); + old_job.exception(id()); + _clock.process_timeouts(); _scheduler.update(quota); /* get new job */ Job & new_job = scheduled_job(); quota = _scheduler.head_quota(); - assert(quota); - _timer->start_one_shot(quota, _id); + + _clock.set_timeout(this, quota); + + _clock.schedule_timeout(); /* switch to new job */ switch_to(new_job); @@ -155,10 +185,11 @@ Cpu_job & Cpu::schedule() Cpu::Cpu(unsigned const id, Timer * const timer) -: _id(id), _idle(this), _timer(timer), - _scheduler(&_idle, _quota(), _fill()), - _ipi_irq(*this), - _timer_irq(_timer->interrupt_id(_id), *this) { } +: + _id(id), _clock(_id, timer), _idle(this), + _scheduler(&_idle, _quota(), _fill()), + _ipi_irq(*this), _timer_irq(timer->interrupt_id(_id), *this) +{ } /************** @@ -175,6 +206,25 @@ Cpu * Cpu_pool::cpu(unsigned const id) const Cpu_pool::Cpu_pool() { + /* + * The timer frequency should allow a good accuracy on the smallest + * timeout syscall value (1 us). + */ + assert(_timer.tics_to_us(1) < 1 || + _timer.tics_to_us(_timer.max_value()) == _timer.max_value()); + + /* + * The maximum measurable timeout is also the maximum age of a timeout + * installed by the timeout syscall. The timeout-age syscall returns a + * bogus value for older timeouts. A user that awoke from waiting for a + * timeout might not be schedulable in the same super period anymore. + * However, if the user can't manage to read the timeout age during the + * next super period, it's a bad configuration or the users fault. That + * said, the maximum timeout should be at least two times the super + * period). + */ + assert(_timer.tics_to_us(_timer.max_value()) > 2 * cpu_quota_us); + for (unsigned id = 0; id < NR_OF_CPUS; id++) { new (_cpus[id]) Cpu(id, &_timer); } } diff --git a/repos/base-hw/src/core/kernel/kernel.cc b/repos/base-hw/src/core/kernel/kernel.cc index 5fafb99416..76d1c3cc3b 100644 --- a/repos/base-hw/src/core/kernel/kernel.cc +++ b/repos/base-hw/src/core/kernel/kernel.cc @@ -21,7 +21,6 @@ extern "C" void kernel() using namespace Kernel; Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id()); - cpu->scheduled_job().exception(cpu->id()); cpu->schedule().proceed(cpu->id()); } diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index ff9ecdcc76..ede6d940a9 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -187,7 +187,7 @@ size_t Thread::_core_to_kernel_quota(size_t const quota) const { using Genode::Cpu_session; using Genode::sizet_arithm_t; - size_t const tics = cpu_pool()->timer()->ms_to_tics(Kernel::cpu_quota_ms); + size_t const tics = cpu_pool()->timer()->us_to_tics(Kernel::cpu_quota_us); return Cpu_session::quota_lim_downscale(quota, tics); } @@ -297,6 +297,34 @@ void Thread::_call_await_request_msg() } +void Thread::_call_timeout() +{ + _timeout_sigid = user_arg_2(); + Cpu_job::timeout(this, user_arg_1()); +} + + +void Thread::_call_timeout_age_us() +{ + user_arg_0(Cpu_job::timeout_age_us(this)); +} + +void Thread::_call_timeout_max_us() +{ + user_arg_0(Cpu_job::timeout_max_us()); +} + + +void Thread::timeout_triggered() +{ + Signal_context * const c = + pd()->cap_tree().find(_timeout_sigid); + if(!c || c->submit(1)) { + PWRN("%s -> %s: failed to submit timeout signal", pd_label(), label()); + } +} + + void Thread::_call_send_request_msg() { Object_identity_reference * oir = pd()->cap_tree().find(user_arg_1()); @@ -576,6 +604,9 @@ void Thread::_call() case call_id_print_char(): _call_print_char(); return; case call_id_ack_cap(): _call_ack_cap(); return; case call_id_delete_cap(): _call_delete_cap(); return; + case call_id_timeout(): _call_timeout(); return; + case call_id_timeout_age_us(): _call_timeout_age_us(); return; + case call_id_timeout_max_us(): _call_timeout_max_us(); return; default: /* check wether this is a core thread */ if (!_core()) { diff --git a/repos/base-hw/src/core/spec/smp/kernel/kernel.cc b/repos/base-hw/src/core/spec/smp/kernel/kernel.cc index 7ee06a76b5..f35a8dffbc 100644 --- a/repos/base-hw/src/core/spec/smp/kernel/kernel.cc +++ b/repos/base-hw/src/core/spec/smp/kernel/kernel.cc @@ -29,7 +29,6 @@ extern "C" void kernel() cpu_id = Cpu::executing_id(); Cpu * const cpu = cpu_pool()->cpu(cpu_id); - cpu->scheduled_job().exception(cpu_id); new_job = &cpu->schedule(); } diff --git a/repos/base/include/spec/epit/drivers/timer_base.h b/repos/base/include/spec/epit/drivers/timer_base.h deleted file mode 100644 index 4154c928c1..0000000000 --- a/repos/base/include/spec/epit/drivers/timer_base.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * \brief Driver base for the Enhanced Periodic Interrupt Timer (Freescale) - * \author Norman Feske - * \author Martin Stein - * \author Stefan Kalkowski - * \date 2012-10-25 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__SPEC__EPIT__DRIVERS__TIMER_BASE_H_ -#define _INCLUDE__SPEC__EPIT__DRIVERS__TIMER_BASE_H_ - -/* Genode includes */ -#include - -namespace Genode { class Epit_base; } - - -/** - * Core timer - */ -class Genode::Epit_base : public Mmio -{ - protected: - - enum { TICS_PER_MS = 33333 }; - - /** - * Control register - */ - struct Cr : Register<0x0, 32> - { - struct En : Bitfield<0, 1> { }; /* enable timer */ - - struct En_mod : Bitfield<1, 1> /* reload on enable */ - { - enum { RELOAD = 1 }; - }; - - struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */ - - struct Rld : Bitfield<3, 1> /* reload or roll-over */ - { - enum { RELOAD_FROM_LR = 1 }; - }; - - struct Prescaler : Bitfield<4, 12> /* clock input divisor */ - { - enum { DIVIDE_BY_1 = 0 }; - }; - - struct Swr : Bitfield<16, 1> { }; /* software reset bit */ - struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */ - struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */ - struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */ - struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */ - struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */ - - struct Om : Bitfield<22, 2> /* mode of the output pin */ - { - enum { DISCONNECTED = 0 }; - }; - - struct Clk_src : Bitfield<24, 2> /* select clock input */ - { - enum { HIGH_FREQ_REF_CLK = 2 }; - }; - - /** - * Register value that configures the timer for a one-shot run - */ - static access_t prepare_one_shot() - { - return En::bits(0) | - En_mod::bits(En_mod::RELOAD) | - Oci_en::bits(1) | - Rld::bits(Rld::RELOAD_FROM_LR) | - Prescaler::bits(Prescaler::DIVIDE_BY_1) | - Swr::bits(0) | - Iovw::bits(0) | - Dbg_en::bits(0) | - Wait_en::bits(0) | - Doz_en::bits(0) | - Stop_en::bits(0) | - Om::bits(Om::DISCONNECTED) | - Clk_src::bits(Clk_src::HIGH_FREQ_REF_CLK); - } - }; - - /** - * Status register - */ - struct Sr : Register<0x4, 32> - { - struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */ - }; - - struct Lr : Register<0x8, 32> { }; /* load value register */ - struct Cmpr : Register<0xc, 32> { }; /* compare value register */ - struct Cnt : Register<0x10, 32> { }; /* counter register */ - - /** - * Disable timer and clear its interrupt output - */ - void _reset() - { - /* wait until ongoing reset operations are finished */ - while (read()) ; - - /* disable timer */ - write(0); - - /* clear interrupt */ - write(1); - } - - void _start_one_shot(unsigned const tics) - { - /* stop timer */ - _reset(); - - /* configure timer for a one-shot */ - write(Cr::prepare_one_shot()); - write(tics); - write(0); - - /* start timer */ - write(1); - } - - public: - - /** - * Constructor - */ - Epit_base(addr_t base) : Mmio(base) { _reset(); } - - /** - * Start single timeout run - * - * \param tics delay of timer interrupt - */ - void start_one_shot(unsigned const tics, unsigned) - { - _start_one_shot(tics); - } - - /** - * Stop the timer from a one-shot run - * - * \return last native timer value of the one-shot run - */ - unsigned long stop_one_shot() - { - /* disable timer */ - write(0); - return value(0); - } - - /** - * Translate milliseconds to a native timer value - */ - unsigned ms_to_tics(unsigned const ms) - { - return TICS_PER_MS * ms; - } - - /** - * Translate native timer value to milliseconds - */ - unsigned tics_to_ms(unsigned const tics) - { - return tics / TICS_PER_MS; - } - - /** - * Return current native timer value - */ - unsigned value(unsigned const) - { - return read() ? 0 : read(); - } -}; - -#endif /* _INCLUDE__SPEC__EPIT__DRIVERS__TIMER_BASE_H_ */ diff --git a/repos/base/include/spec/imx6/drivers/board_base.h b/repos/base/include/spec/imx6/drivers/board_base.h index 07dd6ebc6b..acd6af83be 100644 --- a/repos/base/include/spec/imx6/drivers/board_base.h +++ b/repos/base/include/spec/imx6/drivers/board_base.h @@ -55,6 +55,7 @@ struct Genode::Board_base CORTEX_A9_PRIVATE_MEM_BASE = 0x00a00000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000, CORTEX_A9_PRIVATE_TIMER_CLK = 395037500, + CORTEX_A9_PRIVATE_TIMER_DIV = 170, /* L2 cache controller */ PL310_MMIO_BASE = 0x00a02000, diff --git a/repos/base/include/spec/panda/drivers/board_base.h b/repos/base/include/spec/panda/drivers/board_base.h index 8e8aa03e07..f534c60c74 100644 --- a/repos/base/include/spec/panda/drivers/board_base.h +++ b/repos/base/include/spec/panda/drivers/board_base.h @@ -59,6 +59,7 @@ struct Genode::Board_base CORTEX_A9_PRIVATE_MEM_BASE = 0x48240000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000, CORTEX_A9_PRIVATE_TIMER_CLK = 350000000, + CORTEX_A9_PRIVATE_TIMER_DIV = 175, CORTEX_A9_WUGEN_MMIO_BASE = 0x48281000, CORTEX_A9_SCU_MMIO_BASE = 0x48240000, diff --git a/repos/base/include/spec/pbxa9/drivers/board_base.h b/repos/base/include/spec/pbxa9/drivers/board_base.h index 7c593c6a83..9cd005e6f1 100644 --- a/repos/base/include/spec/pbxa9/drivers/board_base.h +++ b/repos/base/include/spec/pbxa9/drivers/board_base.h @@ -51,6 +51,7 @@ struct Genode::Board_base /* CPU */ CORTEX_A9_PRIVATE_TIMER_CLK = 100000000, + CORTEX_A9_PRIVATE_TIMER_DIV = 100, CORTEX_A9_PRIVATE_MEM_BASE = 0x1f000000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000, diff --git a/repos/base/include/spec/zynq_qemu/drivers/board_base.h b/repos/base/include/spec/zynq_qemu/drivers/board_base.h index 0dcba7a54f..8c0a61a2dd 100644 --- a/repos/base/include/spec/zynq_qemu/drivers/board_base.h +++ b/repos/base/include/spec/zynq_qemu/drivers/board_base.h @@ -23,15 +23,9 @@ namespace Genode { struct Board_base; } */ struct Genode::Board_base : Zynq::Board_base { - enum - { - /* clocks (assuming 6:2:1 mode) */ - CPU_1X_CLOCK = 111111115, - CPU_6X4X_CLOCK = 6 * CPU_1X_CLOCK, - - /* CPU */ - CORTEX_A9_CLOCK = CPU_6X4X_CLOCK, - CORTEX_A9_PRIVATE_TIMER_CLK = CORTEX_A9_CLOCK, + enum { + CORTEX_A9_PRIVATE_TIMER_CLK = 100000000, + CORTEX_A9_PRIVATE_TIMER_DIV = 100, }; }; diff --git a/repos/base/mk/spec/imx53.mk b/repos/base/mk/spec/imx53.mk index 5e85aaf946..77f6651f2c 100644 --- a/repos/base/mk/spec/imx53.mk +++ b/repos/base/mk/spec/imx53.mk @@ -5,12 +5,11 @@ # # denote wich specs are also fullfilled by this spec -SPECS += cortex_a8 imx gpio framebuffer epit +SPECS += cortex_a8 imx gpio framebuffer # add repository relative include paths REP_INC_DIR += include/spec/imx53 REP_INC_DIR += include/spec/imx -REP_INC_DIR += include/spec/epit # include implied specs include $(call select_from_repositories,mk/spec/cortex_a8.mk) diff --git a/repos/base/mk/spec/imx6.mk b/repos/base/mk/spec/imx6.mk index e972c19497..804d8efa60 100644 --- a/repos/base/mk/spec/imx6.mk +++ b/repos/base/mk/spec/imx6.mk @@ -7,12 +7,11 @@ # # denote wich specs are also fullfilled by this spec -SPECS += cortex_a9 imx6 imx epit +SPECS += cortex_a9 imx6 imx # add repository relative include paths REP_INC_DIR += include/spec/imx6 REP_INC_DIR += include/spec/imx -REP_INC_DIR += include/spec/epit # include implied specs include $(call select_from_repositories,mk/spec/cortex_a9.mk) diff --git a/repos/os/lib/mk/spec/epit/hw_timer.mk b/repos/os/lib/mk/spec/epit/hw_timer.mk deleted file mode 100644 index 35f2aa5420..0000000000 --- a/repos/os/lib/mk/spec/epit/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/epit - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/exynos5/hw_timer.mk b/repos/os/lib/mk/spec/exynos5/hw_timer.mk deleted file mode 100644 index 30e5555b3f..0000000000 --- a/repos/os/lib/mk/spec/exynos5/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/exynos5 - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/hw/timer.mk b/repos/os/lib/mk/spec/hw/timer.mk index 5d599f08f7..f796538d2a 100644 --- a/repos/os/lib/mk/spec/hw/timer.mk +++ b/repos/os/lib/mk/spec/hw/timer.mk @@ -1 +1,3 @@ -LIBS = hw_timer +INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw + +include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/omap4/hw_timer.mk b/repos/os/lib/mk/spec/omap4/hw_timer.mk deleted file mode 100644 index 149c0a2dd8..0000000000 --- a/repos/os/lib/mk/spec/omap4/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/omap4 - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/pbxa9/hw_timer.mk b/repos/os/lib/mk/spec/pbxa9/hw_timer.mk deleted file mode 100644 index 14ab762c59..0000000000 --- a/repos/os/lib/mk/spec/pbxa9/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/pbxa9 - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/riscv/hw_timer.mk b/repos/os/lib/mk/spec/riscv/hw_timer.mk deleted file mode 100644 index ba73c4faaf..0000000000 --- a/repos/os/lib/mk/spec/riscv/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/riscv - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/rpi/hw_timer.mk b/repos/os/lib/mk/spec/rpi/hw_timer.mk deleted file mode 100644 index b0a2245055..0000000000 --- a/repos/os/lib/mk/spec/rpi/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw $(REP_DIR)/src/drivers/timer/spec/hw/spec/rpi - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/x86_64/hw_timer.mk b/repos/os/lib/mk/spec/x86_64/hw_timer.mk deleted file mode 100644 index 36e437108f..0000000000 --- a/repos/os/lib/mk/spec/x86_64/hw_timer.mk +++ /dev/null @@ -1,3 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/lib/mk/spec/zynq/hw_timer.mk b/repos/os/lib/mk/spec/zynq/hw_timer.mk deleted file mode 100644 index c2c7a66fb3..0000000000 --- a/repos/os/lib/mk/spec/zynq/hw_timer.mk +++ /dev/null @@ -1,4 +0,0 @@ -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw -INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw/spec/zynq - -include $(REP_DIR)/lib/mk/timer.inc diff --git a/repos/os/src/drivers/timer/spec/hw/platform_timer.h b/repos/os/src/drivers/timer/spec/hw/platform_timer.h index 348722a55d..d0aad7fa85 100644 --- a/repos/os/src/drivers/timer/spec/hw/platform_timer.h +++ b/repos/os/src/drivers/timer/spec/hw/platform_timer.h @@ -15,115 +15,94 @@ #define _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ /* Genode includes */ -#include +#include #include -/* Local includes */ -#include +/* base-hw includes */ +#include /** * Platform timer specific for base-hw */ -class Platform_timer : public Platform_timer_base, - public Genode::Irq_connection +class Platform_timer { private: - enum { MAX_TIMER_IRQS_PER_MS = 1 }; + using time_t = Kernel::time_t; - unsigned long const _max_timeout_us; /* maximum timeout in microsecs */ - unsigned long mutable _curr_time_us; /* accumulate already measured timeouts */ - unsigned long mutable _init_value; /* mark last processed timer value */ - Genode::Lock mutable _update_curr_time_lock; /* serialize curr_time access */ - - Genode::Signal_receiver _irq_rec; - Genode::Signal_context _irq_ctx; + Genode::Signal_receiver _sigrec; + Genode::Signal_context _sigctx; + Kernel::capid_t const _sigid; + unsigned long mutable _curr_time_us; + Genode::Lock mutable _curr_time_us_lock; + unsigned long mutable _last_timeout_us; + time_t const _max_timeout_us; public: - /** - * Constructor - */ Platform_timer() : - Irq_connection(Platform_timer_base::IRQ), - _max_timeout_us(tics_to_us(max_value())), - _curr_time_us(0), _init_value(0) + _sigid(_sigrec.manage(&_sigctx).dst()), _curr_time_us(0), + _last_timeout_us(0), _max_timeout_us(Kernel::timeout_max_us()) { - Irq_connection::sigh(_irq_rec.manage(&_irq_ctx)); - Irq_connection::ack_irq(); + PINF("Maximum timeout %lu us", _max_timeout_us); + if (max_timeout() < min_timeout()) { + PERR("Minimum timeout greater then maximum timeout"); + throw Genode::Exception(); + } } - ~Platform_timer() { _irq_rec.dissolve(&_irq_ctx); } + ~Platform_timer() { _sigrec.dissolve(&_sigctx); } /** * Refresh and return our instance-own "now"-time in microseconds * - * This function has to be executed regulary, - * at least all max_timeout() us. + * This function has to be executed regulary, at least all + * max_timeout() us. */ unsigned long curr_time() const { - /* serialize updates on timeout counter */ - Genode::Lock::Guard lock(_update_curr_time_lock); - - /* get time that passed since last time we've read the timer */ - bool wrapped; - unsigned long const v = value(wrapped); - unsigned long passed_time; - if (wrapped) passed_time = _init_value + max_value() - v; - else passed_time = _init_value - v; - - /* update initial value for subsequent calculations */ - _init_value = v; - - /* refresh our timeout counter and return it */ - _curr_time_us += tics_to_us(passed_time); + Genode::Lock::Guard lock(_curr_time_us_lock); + time_t const passed_us = Kernel::timeout_age_us(); + _last_timeout_us -= passed_us; + _curr_time_us += passed_us; return _curr_time_us; } /** - * Return maximum timeout as supported by the platform + * Return maximum timeout in microseconds */ - unsigned long max_timeout() const { return _max_timeout_us; } + time_t max_timeout() const { return _max_timeout_us; } /** - * Schedule next timeout, oversized timeouts are truncated + * Return minimum timeout in microseconds + */ + static time_t min_timeout() { return 1000; } + + /** + * Schedule next timeout, bad timeouts are adapted * * \param timeout_us Timeout in microseconds */ - void schedule_timeout(unsigned long timeout_us) + void schedule_timeout(time_t timeout_us) { - /* serialize updates on timeout counter */ - Genode::Lock::Guard lock(_update_curr_time_lock); + Genode::Lock::Guard lock(_curr_time_us_lock); + if (timeout_us < min_timeout()) { timeout_us = min_timeout(); } + if (timeout_us > max_timeout()) { timeout_us = max_timeout(); } /* - * Constrain timout value with our maximum IRQ rate and the maximum - * possible timeout. - */ - if (timeout_us < 1000/MAX_TIMER_IRQS_PER_MS) - timeout_us = 1000/MAX_TIMER_IRQS_PER_MS; - if (timeout_us > _max_timeout_us) - timeout_us = _max_timeout_us; - - /* - * Once the timer runs, one can wait for its IRQ and update our + * Once the timer runs, one can wait for its signal and update our * timeout counter through 'curr_time()' (We rely on the fact that * this is done at least one time in every max-timeout period) */ - _init_value = us_to_tics(timeout_us); - run_and_wrap(_init_value); + _last_timeout_us = timeout_us; + Kernel::timeout(timeout_us, _sigid); } /** * Await the lastly scheduled timeout */ - void wait_for_timeout(Genode::Thread *) - { - _irq_rec.wait_for_signal(); - Irq_connection::ack_irq(); - } + void wait_for_timeout(Genode::Thread *) { _sigrec.wait_for_signal(); } }; #endif /* _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/sp804_base.h b/repos/os/src/drivers/timer/spec/hw/sp804_base.h deleted file mode 100644 index ad8b91d313..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/sp804_base.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * \brief Basic driver for the ARM SP804 timer - * \author Martin stein - * \date 2012-04-23 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _DRIVERS__TIMER__SPEC__HW__SP804_BASE_H_ -#define _DRIVERS__TIMER__SPEC__HW__SP804_BASE_H_ - -/* Genode includes */ -#include - -namespace Genode { template class Sp804_base; } - - -/** - * Basic driver for the ARM SP804 timer - */ -template -class Genode::Sp804_base : public Mmio -{ - enum { - TICS_PER_MS = CLK / 1000, - TICS_PER_US = TICS_PER_MS / 1000, - - AVOID_INVALID_TEMPLATE_ARGS = 1 / TICS_PER_US, - }; - - /** - * Holds value that shall be loaded to the timer value register - */ - struct Load : Register<0x0, 32> { }; - - /** - * Raw interrupt status - */ - struct Ris : Register<0x10, 1> { }; - - /** - * Background load register - */ - struct Bgload : Register<0x18, 32> { }; - - /** - * Timer value register - */ - struct Value : Register<0x4, 32> { enum { MAX_VALUE = 0xffffffff }; }; - - /** - * Timer control register - */ - struct Control : Register<0x8, 8> - { - struct Oneshot : Bitfield<0,1> { }; - struct Size : Bitfield<1,1> { }; - struct Pre : Bitfield<2,2> { }; - struct Int_en : Bitfield<5,1> { }; - struct Mode : Bitfield<6,1> { }; - struct Timer_en : Bitfield<7,1> { }; - }; - - /** - * Clears the timer interrupt - */ - struct Int_clr : Register<0xc, 1> { }; - - public: - - /** - * Constructor, clears interrupt output - */ - Sp804_base(addr_t const mmio_base) : Mmio(mmio_base) { - clear_interrupt(); } - - /** - * Run the timer in order that it raises IRQ when - * it reaches zero, then stop - * - * \param tics native timer value used to assess the delay - * of the timer interrupt as of this call - */ - void run_and_stop(unsigned long const tics) - { - /* disable and configure timer for a one-shot */ - clear_interrupt(); - write(0); - write(Control::Timer_en::bits(0) | - Control::Mode::bits(1) | - Control::Int_en::bits(1) | - Control::Pre::bits(0) | - Control::Size::bits(1) | - Control::Oneshot::bits(1)); - - /* load value and enable timer */ - write(tics); - write(1); - } - - /** - * Run the timer in order that it raises IRQ when it reaches zero, - * then wrap and continue - * - * \param tics native timer value used to assess the delay - * of the timer interrupt as of this call - */ - void run_and_wrap(unsigned long const tics) - { - /* configure the timer in order that it reloads on 0 */ - clear_interrupt(); - write(0); - write(Control::Timer_en::bits(0) | - Control::Mode::bits(1) | - Control::Int_en::bits(1) | - Control::Pre::bits(0) | - Control::Size::bits(1) | - Control::Oneshot::bits(0)); - - /* start timer with the initial value */ - write(tics); - write(1); - - /* - * Ensure that the timer loads its max value instead of the - * initial value when it reaches 0 in order that it looks like - * it wraps. - */ - write(max_value()); - } - - /** - * Current timer value - */ - unsigned long value() const { return read(); } - - /** - * Get timer value and corresponding wrapped status of timer - */ - unsigned long value(bool & wrapped) const - { - typename Value::access_t v = read(); - wrapped = (bool)read(); - if (!wrapped) return v; - return read(); - } - - /** - * Clear interrupt output line - */ - void clear_interrupt() { write(1); } - - /** - * Translate milliseconds to a native timer value - */ - static unsigned long ms_to_tics(unsigned long const ms) { - return ms * TICS_PER_MS; } - - /** - * Translate native timer value to microseconds - */ - static unsigned long tics_to_us(unsigned long const tics) { - return tics / TICS_PER_US; } - - /** - * Translate microseconds to a native timer value - */ - static unsigned long us_to_tics(unsigned long const us) { - return us * TICS_PER_US; } - - /** - * Translate native timer value to microseconds - */ - static unsigned long max_value() { return Value::MAX_VALUE; } -}; - -#endif /* _DRIVERS__TIMER__SPEC__HW__SP804_BASE_H_ */ diff --git a/repos/os/src/drivers/timer/spec/hw/spec/epit/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/epit/platform_timer_base.h deleted file mode 100644 index 12082e646c..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/epit/platform_timer_base.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * \brief Basic driver behind platform timer - * \author Stefan Kalkowski - * \date 2012-10-25 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__EPIT__PLATFORM_TIMER_BASE_H_ -#define _HW__EPIT__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include - -namespace Genode -{ - /** - * Epit timer - */ - class Epit : public Epit_base - { - private: - - /** - * Timer tics per microsecond - */ - static float tics_per_us() { - return (float)TICS_PER_MS / 1000.0; } - - /** - * Microseconds per timer tic - */ - static float us_per_tic() { return 1.0 / tics_per_us(); } - - public: - - /** - * Constructor - * - * \param base MMIO base - */ - Epit(addr_t const base) : Epit_base(base) { } - - /** - * Count down 'value', raise IRQ output, wrap counter and continue - */ - void run_and_wrap(unsigned long value) { _start_one_shot(value); } - - /** - * Maximum timeout value - */ - unsigned long max_value() const { return read(); } - - /** - * Translate timer tics to microseconds - */ - unsigned long tics_to_us(unsigned long const tics) const - { - float const us = tics * us_per_tic(); - return (unsigned long)us; - } - - /** - * Translate microseconds to timer tics - */ - unsigned long us_to_tics(unsigned long const us) - { - float const tics = us * tics_per_us(); - return (unsigned long)tics; - } - - /** - * Sample the timer counter and according wrapped status - */ - unsigned long value(bool & wrapped) const - { - unsigned long v = read(); - wrapped = (bool)read(); - return wrapped ? read() : v; - } - }; -} - -/** - * Basic driver behind platform timer - */ -class Platform_timer_base : public Genode::Io_mem_connection, - public Genode::Epit -{ - public: - - enum { IRQ = Genode::Board_base::EPIT_2_IRQ }; - - /** - * Constructor - */ - Platform_timer_base() - : Io_mem_connection(Genode::Board_base::EPIT_2_MMIO_BASE, - Genode::Board_base::EPIT_2_MMIO_SIZE), - Genode::Epit((Genode::addr_t)Genode::env()->rm_session() - ->attach(dataspace())) - { } -}; - -#endif /* _HW__EPIT__PLATFORM_TIMER_BASE_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/spec/exynos5/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/exynos5/platform_timer_base.h deleted file mode 100644 index c2d58d773f..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/exynos5/platform_timer_base.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * \brief Basic driver behind platform timer - * \author Martin stein - * \date 2013-04-04 - */ - -/* - * Copyright (C) 2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ -#define _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include -#include - -namespace Genode -{ - /** - * Exynos 5250 pulse width modulation timer - */ - class Pwm : public Mmio - { - enum { - PRESCALER = 2, - TICS_PER_US = Board_base::PWM_CLOCK / PRESCALER / 1000 / 1000, - }; - - /** - * Timer configuration 0 - */ - struct Cfg0 : Register<0x0, 32> - { - struct Prescaler0 : Bitfield<0, 8> - { - enum { DEFAULT = PRESCALER - 1 }; - }; - }; - - /** - * Timer configuration 1 - */ - struct Cfg1 : Register<0x4, 32> - { - struct Div0 : Bitfield<0, 4> { enum { DISABLE = 0 }; }; - }; - - /** - * Timer control - */ - struct Con : Register<0x8, 32> - { - struct Enable0 : Bitfield<0, 1> { }; - struct Update0 : Bitfield<1, 1> { }; - struct Invert_tout0 : Bitfield<2, 1> { }; - struct Auto_reload0 : Bitfield<3, 1> { }; - struct Deadzone_en : Bitfield<4, 1> { }; - - /** - * Initialization value - */ - static access_t init_value() - { - return Invert_tout0::bits(0) | - Auto_reload0::bits(1) | - Deadzone_en::bits(0); - } - }; - - /** - * Timer 0 count buffer - */ - struct Cntb0 : Register<0xc, 32> { }; - - /** - * Timer 0 compare buffer - */ - struct Cmpb0 : Register<0x10, 32> { }; - - /** - * Timer 0 count observation - */ - struct Cnto0 : Register<0x14, 32> { }; - - /** - * Timer IRQ control and status - */ - struct Int : Register<0x44, 32> - { - struct En0 : Bitfield<0, 1> { }; - struct En1 : Bitfield<1, 1> { }; - struct En2 : Bitfield<2, 1> { }; - struct En3 : Bitfield<3, 1> { }; - struct En4 : Bitfield<4, 1> { }; - struct Stat0 : Bitfield<5, 1> { }; - - /** - * Initialization value - */ - static access_t init_value() - { - return En0::bits(1) | - En1::bits(0) | - En2::bits(0) | - En3::bits(0) | - En4::bits(0); - } - }; - - public: - - /** - * Constructor - * - * \param base MMIO base - */ - Pwm(addr_t const base) : Mmio(base) - { - write(Cfg0::Prescaler0::DEFAULT); - write(Cfg1::Div0::DISABLE); - write(Int::init_value()); - write(Con::init_value()); - write(0); - } - - /** - * Count down 'value', raise IRQ output, wrap counter and continue - */ - void run_and_wrap(unsigned long value) - { - write(value); - write(0); - write(1); - write(0); - write(1); - write(max_value()); - write(1); - } - - /** - * Maximum timeout value - */ - unsigned long max_value() const { return (Cntb0::access_t)~0; } - - /** - * Translate timer tics to microseconds - */ - unsigned long tics_to_us(unsigned long const tics) const { - return tics / TICS_PER_US; } - - /** - * Translate microseconds to timer tics - */ - unsigned long us_to_tics(unsigned long const us) const { - return us * TICS_PER_US; } - - /** - * Sample the timer counter and according wrapped status - */ - unsigned long value(bool & wrapped) const - { - unsigned long v = read(); - wrapped = (bool)read(); - return wrapped ? read() : v; - } - }; -} - -/** - * Basic driver behind platform timer - */ -class Platform_timer_base : public Genode::Io_mem_connection, - public Genode::Pwm -{ - public: - - enum { IRQ = Genode::Board_base::PWM_IRQ_0 }; - - /** - * Constructor - */ - Platform_timer_base() - : Io_mem_connection(Genode::Board_base::PWM_MMIO_BASE, - Genode::Board_base::PWM_MMIO_SIZE), - Genode::Pwm((Genode::addr_t)Genode::env()->rm_session() - ->attach(dataspace())) - { } -}; - -#endif /* _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/spec/omap4/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/omap4/platform_timer_base.h deleted file mode 100644 index 42f50906d6..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/omap4/platform_timer_base.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * \brief Basic driver behind platform timer - * \author Martin Stein - * \date 2012-05-03 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__OMAP4__PLATFORM_TIMER_BASE_H_ -#define _HW__OMAP4__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include -#include - -namespace Genode -{ - /** - * Omap4 general purpose timer 3 through 9 and 11 - */ - class Omap4_gp_timer_1 : public Mmio - { - /** - * Timer tics per microsecond - */ - static float tics_per_us() { - return (float)Board_base::SYS_CLK / 1000000; } - - /** - * Microsecodns per timer tic - */ - static float us_per_tic() { return 1 / tics_per_us(); } - - /** - * L4 interface control - */ - struct Tiocp_cfg : Register<0x10, 32> - { - struct Softreset : Bitfield<0, 1> { }; /* SW reset active */ - struct Idlemode : Bitfield<2, 2> /* action on IDLE request */ - { - enum { FORCE_IDLE = 0 }; - }; - }; - - /** - * Timer wake-up enable register - */ - struct Twer : Register<0x20, 32> - { - struct Mat_wup_ena : Bitfield<0, 1> { }; /* wakeup on match */ - struct Ovf_wup_ena : Bitfield<1, 1> { }; /* wakeup on overflow */ - struct Tcar_wup_ena : Bitfield<2, 1> { }; /* wakeup on capture */ - - /** - * Timer initialization value - */ - static access_t init_timer() - { - return Mat_wup_ena::bits(0) | - Ovf_wup_ena::bits(0) | - Tcar_wup_ena::bits(0); - } - }; - - /** - * Timer synchronous interface control register - */ - struct Tsicr : Register<0x54, 32> - { - struct Posted : Bitfield<2, 1> { }; /* enable posted mode */ - }; - - /** - * Control timer-functionality dependent features - */ - struct Tclr : Register<0x38, 32> - { - struct St : Bitfield<0, 1> { }; /* start/stop timer */ - struct Ar : Bitfield<1, 1> { }; /* enable eutoreload */ - struct Pre : Bitfield<5, 1> { }; /* enable prescaler */ - - /** - * Run-and-wrap configuration - */ - static access_t init_run_and_wrap() - { - return St::bits(0) | - Ar::bits(1) | - Pre::bits(0); - } - }; - - /** - * Set IRQ enables - */ - struct Irqenable_set : Register<0x2c, 32> - { - struct Ovf_en_flag : Bitfield<1, 1> { }; /* enable overflow IRQ */ - }; - - /** - * IRQ status - */ - struct Irqstatus : Register<0x28, 32> - { - struct Ovf_it_flag : Bitfield<1, 1> { }; /* clear overflow IRQ */ - }; - - /** - * Timer counter register - */ - struct Tcrr : Register<0x3c, 32> - { - /** - * maximum counter value - */ - static access_t max_value() { return ~0; } - }; - - /** - * Timer load value register - */ - struct Tldr : Register<0x40, 32> { }; - - /** - * Freeze timer counter - */ - void _freeze() { write(0); } - - /** - * Unfreeze timer counter - */ - void _unfreeze() { write(1); } - - /** - * Get remaining counting amount - */ - unsigned long _value() const { return max_value() - read(); } - - /** - * Apply counting amount - */ - void _value(unsigned long const v) { write(max_value() - v); } - - public: - - /** - * Constructor - * - * \param base MMIO base - */ - Omap4_gp_timer_1(addr_t const base) : Mmio(base) - { - _freeze(); - - /* do a software reset */ - write(1); - while (read()) ; - - /* configure Idle mode */ - write(Tiocp_cfg::Idlemode::FORCE_IDLE); - - /* enable wake-up interrupt events */ - write(Twer::init_timer()); - - /* select posted mode */ - write(0); - } - - /** - * Count down 'value', raise IRQ output, wrap counter and continue - */ - void run_and_wrap(unsigned long value) - { - enum { MIN_VALUE = 1 }; - - /* stop timer */ - _freeze(); - clear_interrupt(); - value = value ? value : MIN_VALUE; - - /* configure for a run and wrap */ - write(Tclr::init_run_and_wrap()); - write(1); - - /* install value */ - _value(value); - write(0); - - /* start timer */ - _unfreeze(); - } - - /** - * Clear interrupt output - */ - void clear_interrupt() { - write(1); } - - /** - * Maximum timeout value - */ - unsigned long max_value() const { return Tcrr::max_value(); } - - /** - * Translate timer tics to microseconds - */ - unsigned long tics_to_us(unsigned long const tics) const - { - float const us = tics * us_per_tic(); - return (unsigned long)us; - } - - /** - * Translate microseconds to timer tics - */ - unsigned long us_to_tics(unsigned long const us) - { - float const tics = us * tics_per_us(); - return (unsigned long)tics; - } - - /** - * Sample the timer counter and according wrapped status - */ - unsigned long value(bool & wrapped) const - { - Tcrr::access_t const v = _value(); - wrapped = (bool)read(); - return wrapped ? _value() : v; - } - }; -} - -/** - * Basic driver behind platform timer - */ -class Platform_timer_base : public Genode::Io_mem_connection, - public Genode::Omap4_gp_timer_1 -{ - /* FIXME these should be located in a omap4-defs file */ - enum { - GP_TIMER_3_MMIO_BASE = 0x48034000, - GP_TIMER_3_MMIO_SIZE = 0x00001000, - }; - - public: - - enum { IRQ = Genode::Board_base::GP_TIMER_3_IRQ }; - - /** - * Constructor - */ - Platform_timer_base() : - Io_mem_connection(GP_TIMER_3_MMIO_BASE, GP_TIMER_3_MMIO_SIZE), - Genode::Omap4_gp_timer_1((Genode::addr_t)Genode::env()->rm_session()->attach(dataspace())) - { } -}; - -#endif /* _HW__OMAP4__PLATFORM_TIMER_BASE_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/spec/pbxa9/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/pbxa9/platform_timer_base.h deleted file mode 100644 index d1c8b047b5..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/pbxa9/platform_timer_base.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * \brief Platform-timer base specific for base-hw and PBXA9 - * \author Martin Stein - * \date 2012-05-03 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _OS__SRC__DRIVERS__TIMER__HW__PBXA9__PLATFORM_TIMER_BASE_H_ -#define _OS__SRC__DRIVERS__TIMER__HW__PBXA9__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include - -/** - * Platform-timer base specific for base-hw and PBXA9 - */ -class Platform_timer_base : - public Genode::Io_mem_connection, - public Genode::Sp804_base -{ - public: - - enum { IRQ = Genode::Board_base::SP804_0_1_IRQ }; - - /** - * Constructor - */ - Platform_timer_base() : - Io_mem_connection(Genode::Board_base::SP804_0_1_MMIO_BASE, - Genode::Board_base::SP804_0_1_MMIO_SIZE), - - Sp804_base((Genode::addr_t)Genode::env()->rm_session()-> - attach(dataspace())) - { } -}; - -#endif /* _OS__SRC__DRIVERS__TIMER__HW__PBXA9__PLATFORM_TIMER_BASE_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/spec/riscv/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/riscv/platform_timer_base.h deleted file mode 100644 index fd1f09282b..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/riscv/platform_timer_base.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * \brief Dummy platform timer - * \author Sebastian Sumpf - * \date 2016-02-10 - */ - -/* - * Copyright (C) 2016 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__RISCV__PLATFORM_TIMER_BASE_H_ -#define _HW__RISCV__PLATFORM_TIMER_BASE_H_ - -class Platform_timer_base -{ - public: - - enum { IRQ }; - - unsigned long tics_to_us(unsigned long const tics) const { return 0; } - unsigned long us_to_tics(unsigned long const us) const { return 0; } - - unsigned long max_value() const { return 0; } - unsigned long value(bool & wrapped) const { return 0; } - - void run_and_wrap(unsigned long value) { } -}; - -#endif /* _HW__RISCV__PLATFORM_TIMER_BASE_H_ */ diff --git a/repos/os/src/drivers/timer/spec/hw/spec/rpi/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/rpi/platform_timer_base.h deleted file mode 100644 index f700594f8c..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/rpi/platform_timer_base.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * \brief User-level timer driver for Raspberry Pi - * \author Norman Feske - * \date 2013-04-11 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__RPI__PLATFORM_TIMER_BASE_H_ -#define _HW__RPI__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include - -/* - * On the BCM2835, the timer is driven by the APB clock (250 MHz). The prescale - * register (not present in the normal SP804) has a reset value of 126. Hence, - * the effective timer clock is 1,984 MHz. - * - * The timer device is on the same physical page as the IRQ controller. Hence, - * we open an IO_MEM session with a range smaller than page size as argument. - * The dataspace base address will correspond to 0x2000b000. - */ -enum { TIMER_MMIO_BASE = 0x2000b400, - TIMER_MMIO_SIZE = 0x100, - TIMER_CLOCK = 1984*1000 }; - -struct Platform_timer_base -: - Genode::Attached_io_mem_dataspace, - Genode::Sp804_base -{ - enum { IRQ = Genode::Board_base::TIMER_IRQ }; - - Platform_timer_base() : - Attached_io_mem_dataspace(TIMER_MMIO_BASE, TIMER_MMIO_SIZE), - Sp804_base((Genode::addr_t)local_addr()) - { } -}; - -#endif /* _HW__RPI__PLATFORM_TIMER_BASE_H_ */ - diff --git a/repos/os/src/drivers/timer/spec/hw/spec/zynq/platform_timer_base.h b/repos/os/src/drivers/timer/spec/hw/spec/zynq/platform_timer_base.h deleted file mode 100644 index d39be024a6..0000000000 --- a/repos/os/src/drivers/timer/spec/hw/spec/zynq/platform_timer_base.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * \brief Platform-timer base specific for base-hw and zynq - * \author Johannes Schlatow - * \date 2015-03-05 - */ - -/* - * Copyright (C) 2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _HW__ZYNQ__PLATFORM_TIMER_BASE_H_ -#define _HW__ZYNQ__PLATFORM_TIMER_BASE_H_ - -/* Genode includes */ -#include -#include -#include - -/** - * Platform-timer base specific for base-hw and zynq - * - * Uses the internal timer 0 of the TTC. For more details, see Xilinx ug585 - * "Zynq 7000 Technical Reference Manual". - */ -class Platform_timer_base -: - public Genode::Io_mem_connection, - public Genode::Mmio -{ - private: - - enum - { - PRESCALER = 5, - TICS_PER_MS = (Genode::Board_base::CPU_1X_CLOCK / 1000) - >> PRESCALER - }; - - /** - * Clock control register - */ - struct Clock : Register<0x00, 8> - { - struct Prescale_en : Bitfield<0, 1> { }; - struct Prescale : Bitfield<1, 4> { }; - }; - - /** - * Counter control register - */ - struct Control : Register<0x0c, 8> - { - struct Disable : Bitfield<0, 1> { }; - struct Mode : Bitfield<1, 1> { enum { INTERVAL = 1 }; }; - struct Decrement : Bitfield<2, 1> { }; - struct Wave_en : Bitfield<5, 1> { }; - }; - - /** - * Counter value - */ - struct Value : Register<0x18, 16> { }; - struct Interval : Register<0x24, 16> { }; - struct Match1 : Register<0x30, 16> { }; - struct Match2 : Register<0x3c, 16> { }; - struct Match3 : Register<0x48, 16> { }; - struct Irq : Register<0x54, 8> { }; - struct Irqen : Register<0x60, 8> { }; - - void _disable() - { - write(0); - read(); - } - - public: - - enum { IRQ = Genode::Board_base::TTC0_IRQ_0 }; - - /** - * Constructor - */ - Platform_timer_base() - : - Io_mem_connection(Genode::Board_base::TTC0_MMIO_BASE, - Genode::Board_base::TTC0_MMIO_SIZE), - Mmio((Genode::addr_t) - Genode::env()->rm_session()->attach(dataspace())) - { - _disable(); - - /* configure prescaler */ - Clock::access_t clock = read(); - Clock::Prescale::set(clock, PRESCALER - 1); - Clock::Prescale_en::set(clock, 1); - write(clock); - - /* enable all interrupts */ - write(~0); - - /* set match registers to 0 */ - write(0); - write(0); - write(0); - } - - /** - * Count down 'value', raise IRQ output, wrap counter and continue - */ - void run_and_wrap(unsigned long const tics) - { - _disable(); - - /* configure timer for a one-shot */ - Control::access_t control = 0; - Control::Mode::set(control, Control::Mode::INTERVAL); - Control::Decrement::set(control, 1); - Control::Wave_en::set(control, 1); - write(control); - - /* load and enable timer */ - write(tics); - write(0); - } - - /** - * Get timer value and corresponding wrapped status of timer - */ - unsigned long value(bool & wrapped) const - { - unsigned long v = read(); - wrapped = (bool)read(); - return wrapped ? read() : v; - } - - /** - * Translate native timer value to microseconds - */ - static unsigned long tics_to_us(unsigned long const tics) { - return tics * 1000 / TICS_PER_MS; } - - /** - * Translate microseconds to a native timer value - */ - static unsigned long us_to_tics(unsigned long const us) { - return us * TICS_PER_MS / 1000; } - - /** - * Return maximum number of tics - */ - unsigned long max_value() const { return (Interval::access_t)~0; } -}; - -#endif /* _HW__ZYNQ__PLATFORM_TIMER_BASE_H_ */ -