mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 22:47:50 +00:00
hw: use kernel timer for timer driver
* Adds public timeout syscalls to kernel API * Kernel::timeout installs a timeout and binds a signal context to it that shall trigger once the timeout expired * With Kernel::timeout_max_us, one can get the maximum installable timeout * Kernel::timeout_age_us returns the time that has passed since the calling threads last timeout installation * Removes all device specific back-ends for the base-hw timer driver and implements a generic back-end taht uses the kernel timeout API * Adds assertions about the kernel timer frequency that originate from the requirements of the the kernel timeout API and adjusts all timers accordingly by using the their internal dividers * Introduces the Kernel::Clock class. As member of each Kernel::Cpu object it combines the management of the timer of the CPU with a timeout scheduler. Not only the timeout API uses the timeout scheduler but also the CPUs job scheduler for installing scheduling timeouts. * Introduces the Kernel::time_t type for timer tic values and values inherited from timer tics (like microseconds). Fixes #1972
This commit is contained in:
parent
722fd85bc1
commit
1208d14681
@ -15,34 +15,32 @@
|
||||
#define _INCLUDE__KERNEL__INTERFACE_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
#include <kernel/interface_support.h>
|
||||
|
||||
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
|
||||
*/
|
||||
|
31
repos/base-hw/include/kernel/types.h
Normal file
31
repos/base-hw/include/kernel/types.h
Normal file
@ -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 <kernel/types.h>
|
||||
#include <kernel/interface_support.h>
|
||||
|
||||
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_ */
|
@ -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
|
||||
|
@ -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<sizet_arithm_t>(_quota, spu);
|
||||
return { spu, u };
|
||||
}
|
||||
|
107
repos/base-hw/src/core/include/kernel/clock.h
Normal file
107
repos/base-hw/src/core/include/kernel/clock.h
Normal file
@ -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 <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <timer.h>
|
||||
|
||||
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<Timeout>::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> _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_ */
|
@ -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_ */
|
||||
|
@ -16,7 +16,7 @@
|
||||
#define _CORE__INCLUDE__KERNEL__CPU_H_
|
||||
|
||||
/* core includes */
|
||||
#include <timer.h>
|
||||
#include <kernel/clock.h>
|
||||
#include <cpu.h>
|
||||
#include <kernel/cpu_scheduler.h>
|
||||
#include <kernel/irq.h>
|
||||
@ -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 **
|
||||
|
@ -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 <typename T, typename... ARGS>
|
||||
void _call_new(ARGS &&... args)
|
||||
@ -345,6 +350,13 @@ class Kernel::Thread
|
||||
Cpu_job * helping_sink();
|
||||
|
||||
|
||||
/*************
|
||||
** Timeout **
|
||||
*************/
|
||||
|
||||
void timeout_triggered();
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
@ -14,20 +14,31 @@
|
||||
#ifndef _CORE__INCLUDE__SPEC__CORTEX_A9__TIMER_H_
|
||||
#define _CORE__INCLUDE__SPEC__CORTEX_A9__TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
|
||||
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<Control::Timer_enable>(0);
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Timer() : Mmio(Board::PRIVATE_TIMER_MMIO_BASE)
|
||||
{
|
||||
write<Control::Timer_enable>(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<Interrupt_status::Event>(1);
|
||||
Control::access_t control = 0;
|
||||
Control::Irq_enable::set(control, 1);
|
||||
write<Control>(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<Load>(tics);
|
||||
write<Control::Timer_enable>(1);
|
||||
}
|
||||
/* reset timer */
|
||||
write<Interrupt_status::Event>(1);
|
||||
Control::access_t control = 0;
|
||||
Control::Irq_enable::set(control, 1);
|
||||
Control::Prescaler::set(control, PRESCALER);
|
||||
write<Control>(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<Load>(tics);
|
||||
write<Control::Timer_enable>(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current native timer value
|
||||
*/
|
||||
unsigned value(unsigned const) { return read<Counter>(); }
|
||||
};
|
||||
}
|
||||
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<Counter>(); }
|
||||
|
||||
time_t max_value() { return (Load::access_t)~0; }
|
||||
};
|
||||
|
||||
namespace Kernel { class Timer : public Genode::Timer { }; }
|
||||
|
||||
|
@ -14,6 +14,9 @@
|
||||
#ifndef _CORE__INCLUDE__SPEC__EXYNOS5__TIMER_H_
|
||||
#define _CORE__INCLUDE__SPEC__EXYNOS5__TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* core include */
|
||||
#include <board.h>
|
||||
|
||||
@ -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<L0_int_cstat::Frcnt>() ? 0 : read<L0_frcnto>();
|
||||
@ -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 { }; }
|
||||
|
@ -14,33 +14,164 @@
|
||||
#ifndef _CORE__INCLUDE__SPEC__IMX53__TIMER_H_
|
||||
#define _CORE__INCLUDE__SPEC__IMX53__TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <drivers/timer_base.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
|
||||
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<Cr::Swr>()) ;
|
||||
|
||||
/* disable timer */
|
||||
write<Cr::En>(0);
|
||||
|
||||
/* clear interrupt */
|
||||
write<Sr::Ocif>(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>(Cr::prepare_one_shot());
|
||||
write<Lr>(tics);
|
||||
write<Cmpr>(0);
|
||||
|
||||
/* start timer */
|
||||
write<Cr::En>(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<Sr::Ocif>() ? 0 : read<Cnt>(); }
|
||||
};
|
||||
|
||||
namespace Kernel { class Timer : public Genode::Timer { }; }
|
||||
|
@ -14,6 +14,9 @@
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/stdint.h>
|
||||
@ -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 { }; }
|
||||
|
@ -14,26 +14,30 @@
|
||||
#ifndef _CORE__INCLUDE__SPEC__RPI__TIMER_H_
|
||||
#define _CORE__INCLUDE__SPEC__RPI__TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
|
||||
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<Cs::M1>(1);
|
||||
read<Cs>();
|
||||
@ -52,10 +57,15 @@ class Genode::Timer : public Mmio
|
||||
write<Cmp>(read<Clo>() + 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<Cmp>();
|
||||
Clo::access_t const clo = read<Clo>();
|
||||
|
@ -15,6 +15,9 @@
|
||||
#ifndef _CORE__INCLUDE__SPEC__X86__TIMER_H_
|
||||
#define _CORE__INCLUDE__SPEC__X86__TIMER_H_
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
#include <base/stdint.h>
|
||||
@ -24,18 +27,17 @@
|
||||
#include <port_io.h>
|
||||
#include <board.h>
|
||||
|
||||
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<Divide_value_0_2, Divide_value_2_1>
|
||||
{
|
||||
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>(
|
||||
Divide_configuration::Divide_value::MAX);
|
||||
|
||||
/* Enable LAPIC timer in one-shot mode */
|
||||
write<Tmr_lvt::Vector>(Board::TIMER_VECTOR_KERNEL);
|
||||
write<Tmr_lvt::Delivery>(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<Tmr_initial>(tics);
|
||||
}
|
||||
void start_one_shot(time_t const tics, unsigned const) {
|
||||
write<Tmr_initial>(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<Tmr_current>();
|
||||
}
|
||||
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<Tmr_current>(); }
|
||||
};
|
||||
|
||||
namespace Kernel { class Timer : public Genode::Timer { }; }
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define _CORE__INCLUDE__SPEC__X86_64__MUEN__TIMER_H_
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <kernel/types.h>
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
@ -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) { }
|
||||
};
|
||||
|
||||
|
101
repos/base-hw/src/core/kernel/clock.cc
Normal file
101
repos/base-hw/src/core/kernel/clock.cc
Normal file
@ -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 <kernel/clock.h>
|
||||
|
||||
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) { }
|
@ -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); }
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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<sizet_arithm_t>(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<Signal_context>(_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()) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 <util/mmio.h>
|
||||
|
||||
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<Cr::Swr>()) ;
|
||||
|
||||
/* disable timer */
|
||||
write<Cr::En>(0);
|
||||
|
||||
/* clear interrupt */
|
||||
write<Sr::Ocif>(1);
|
||||
}
|
||||
|
||||
void _start_one_shot(unsigned const tics)
|
||||
{
|
||||
/* stop timer */
|
||||
_reset();
|
||||
|
||||
/* configure timer for a one-shot */
|
||||
write<Cr>(Cr::prepare_one_shot());
|
||||
write<Lr>(tics);
|
||||
write<Cmpr>(0);
|
||||
|
||||
/* start timer */
|
||||
write<Cr::En>(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<Cr::En>(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<Sr::Ocif>() ? 0 : read<Cnt>();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__SPEC__EPIT__DRIVERS__TIMER_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,
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
@ -1 +1,3 @@
|
||||
LIBS = hw_timer
|
||||
INC_DIR += $(REP_DIR)/src/drivers/timer/spec/hw
|
||||
|
||||
include $(REP_DIR)/lib/mk/timer.inc
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
INC_DIR += $(REP_DIR)/src/drivers/timer/include_pit
|
||||
|
||||
include $(REP_DIR)/lib/mk/timer.inc
|
@ -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
|
@ -15,115 +15,94 @@
|
||||
#define _OS__SRC__DRIVERS__TIMER__HW__PLATFORM_TIMER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <irq_session/connection.h>
|
||||
#include <base/signal.h>
|
||||
#include <os/server.h>
|
||||
|
||||
/* Local includes */
|
||||
#include <platform_timer_base.h>
|
||||
/* base-hw includes */
|
||||
#include <kernel/interface.h>
|
||||
|
||||
/**
|
||||
* 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_ */
|
||||
|
||||
|
@ -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 <util/mmio.h>
|
||||
|
||||
namespace Genode { template <unsigned long> class Sp804_base; }
|
||||
|
||||
|
||||
/**
|
||||
* Basic driver for the ARM SP804 timer
|
||||
*/
|
||||
template <unsigned long CLK>
|
||||
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<typename Control::Timer_en>(0);
|
||||
write<Control>(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<Load>(tics);
|
||||
write<typename Control::Timer_en>(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<typename Control::Timer_en>(0);
|
||||
write<Control>(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<Load>(tics);
|
||||
write<typename Control::Timer_en>(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<Bgload>(max_value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Current timer value
|
||||
*/
|
||||
unsigned long value() const { return read<Value>(); }
|
||||
|
||||
/**
|
||||
* Get timer value and corresponding wrapped status of timer
|
||||
*/
|
||||
unsigned long value(bool & wrapped) const
|
||||
{
|
||||
typename Value::access_t v = read<Value>();
|
||||
wrapped = (bool)read<Ris>();
|
||||
if (!wrapped) return v;
|
||||
return read<Value>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear interrupt output line
|
||||
*/
|
||||
void clear_interrupt() { write<Int_clr>(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_ */
|
@ -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 <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <drivers/timer_base.h>
|
||||
|
||||
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<Lr>(); }
|
||||
|
||||
/**
|
||||
* 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<Cnt>();
|
||||
wrapped = (bool)read<Sr::Ocif>();
|
||||
return wrapped ? read<Cnt>() : 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_ */
|
||||
|
@ -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 <io_mem_session/connection.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
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>(Cfg0::Prescaler0::DEFAULT);
|
||||
write<Cfg1::Div0>(Cfg1::Div0::DISABLE);
|
||||
write<Int>(Int::init_value());
|
||||
write<Con>(Con::init_value());
|
||||
write<Cmpb0>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count down 'value', raise IRQ output, wrap counter and continue
|
||||
*/
|
||||
void run_and_wrap(unsigned long value)
|
||||
{
|
||||
write<Cntb0>(value);
|
||||
write<Con::Enable0>(0);
|
||||
write<Con::Update0>(1);
|
||||
write<Con::Update0>(0);
|
||||
write<Int::Stat0>(1);
|
||||
write<Cntb0>(max_value());
|
||||
write<Con::Enable0>(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<Cnto0>();
|
||||
wrapped = (bool)read<Int::Stat0>();
|
||||
return wrapped ? read<Cnto0>() : 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_ */
|
||||
|
@ -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 <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <drivers/board_base.h>
|
||||
|
||||
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<Tclr::St>(0); }
|
||||
|
||||
/**
|
||||
* Unfreeze timer counter
|
||||
*/
|
||||
void _unfreeze() { write<Tclr::St>(1); }
|
||||
|
||||
/**
|
||||
* Get remaining counting amount
|
||||
*/
|
||||
unsigned long _value() const { return max_value() - read<Tcrr>(); }
|
||||
|
||||
/**
|
||||
* Apply counting amount
|
||||
*/
|
||||
void _value(unsigned long const v) { write<Tcrr>(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<Tiocp_cfg::Softreset>(1);
|
||||
while (read<Tiocp_cfg::Softreset>()) ;
|
||||
|
||||
/* configure Idle mode */
|
||||
write<Tiocp_cfg::Idlemode>(Tiocp_cfg::Idlemode::FORCE_IDLE);
|
||||
|
||||
/* enable wake-up interrupt events */
|
||||
write<Twer>(Twer::init_timer());
|
||||
|
||||
/* select posted mode */
|
||||
write<Tsicr::Posted>(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>(Tclr::init_run_and_wrap());
|
||||
write<Irqenable_set::Ovf_en_flag>(1);
|
||||
|
||||
/* install value */
|
||||
_value(value);
|
||||
write<Tldr>(0);
|
||||
|
||||
/* start timer */
|
||||
_unfreeze();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear interrupt output
|
||||
*/
|
||||
void clear_interrupt() {
|
||||
write<Irqstatus::Ovf_it_flag>(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<Irqstatus::Ovf_it_flag>();
|
||||
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_ */
|
||||
|
@ -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 <io_mem_session/connection.h>
|
||||
#include <sp804_base.h>
|
||||
#include <drivers/board_base.h>
|
||||
|
||||
/**
|
||||
* Platform-timer base specific for base-hw and PBXA9
|
||||
*/
|
||||
class Platform_timer_base :
|
||||
public Genode::Io_mem_connection,
|
||||
public Genode::Sp804_base<Genode::Board_base::SP804_0_1_CLOCK>
|
||||
{
|
||||
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_ */
|
||||
|
@ -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_ */
|
@ -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 <os/attached_io_mem_dataspace.h>
|
||||
#include <sp804_base.h>
|
||||
#include <drivers/board_base.h>
|
||||
|
||||
/*
|
||||
* 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<TIMER_CLOCK>
|
||||
{
|
||||
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<void>())
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _HW__RPI__PLATFORM_TIMER_BASE_H_ */
|
||||
|
@ -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 <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <drivers/board_base.h>
|
||||
|
||||
/**
|
||||
* 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<Control::Disable>(0);
|
||||
read<Irq>();
|
||||
}
|
||||
|
||||
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>();
|
||||
Clock::Prescale::set(clock, PRESCALER - 1);
|
||||
Clock::Prescale_en::set(clock, 1);
|
||||
write<Clock>(clock);
|
||||
|
||||
/* enable all interrupts */
|
||||
write<Irqen>(~0);
|
||||
|
||||
/* set match registers to 0 */
|
||||
write<Match1>(0);
|
||||
write<Match2>(0);
|
||||
write<Match3>(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>(control);
|
||||
|
||||
/* load and enable timer */
|
||||
write<Interval>(tics);
|
||||
write<Control::Disable>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timer value and corresponding wrapped status of timer
|
||||
*/
|
||||
unsigned long value(bool & wrapped) const
|
||||
{
|
||||
unsigned long v = read<Value>();
|
||||
wrapped = (bool)read<Irq>();
|
||||
return wrapped ? read<Value>() : 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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user