Gilles Chanteperdrix wrote:
> at91_enthus wrote:
>> Hi!
>>
>> I installed the latest xenomai patch on a AT91SAM9G20 board and
>> everything looked good at a first glance: no compilation problems, low
>> latencies.
>>
>> However, when I typed cat /proc/timer_list , the resolutions in cpu0
>> and cpu1 items showed 100000 (ns).
>> (I compiled the Xenomai patched kernel with High Resolution Timers enabled.)
>>
>> I don't have this problem when I boot a real time kernel (RT_PREEMPT).
>
> You mean another real-time kernel? If RT_PREEMPT uses the sys timer
> running at 32kHz, and it tells you that it has a 1ns resolution, then it
> is lying, because 32kHz, means a 30us resolution.
>
> Xenomai uses one TC as a timer at whatever frequency your chip proposes
> over 1 MHz, this means a resolution below 1us, the downside is that this
> also means a very short wrap time. And since the TC is also used as a
> clock, this means that we must enter the timer interrupt handler before
> the counter wraps. And this is something that Linux without Xenomai
> running can not guarantee.
On the other hand, we can keep the timer ticking behind Linux' back.
Does the following patch fix the issue for you?
diff --git a/arch/arm/mach-at91/at91_ipipe_time.c
b/arch/arm/mach-at91/at91_ipipe_time.c
index b0327eb..6c6f0d7 100644
--- a/arch/arm/mach-at91/at91_ipipe_time.c
+++ b/arch/arm/mach-at91/at91_ipipe_time.c
@@ -76,9 +76,7 @@
#define TCNXCNS(timer,v) ((v) << ((timer)<<1))
#define AT91_TC_REG_MASK (0xffff)
-static unsigned long next_match;
-
-static unsigned max_delta_ticks, min_delta_ticks;
+static unsigned max_delta_ticks, min_delta_ticks, tick_pending;
static struct clock_event_device clkevt;
static int tc_timer_clock;
@@ -116,7 +114,11 @@ EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
*/
static irqreturn_t at91_timer_interrupt(int irq, void *dev_id)
{
- clkevt.event_handler(&clkevt);
+ if (__ipipe_mach_timerstolen || tick_pending) {
+ tick_pending = 0;
+ clkevt.event_handler(&clkevt);
+ }
+
return IRQ_HANDLED;
}
@@ -130,12 +132,8 @@ void __ipipe_mach_acktimer(void)
{
at91_tc_read(AT91_TC_SR);
- if (unlikely(!__ipipe_mach_timerstolen)) {
- __ipipe_tsc_update();
- next_match = (next_match + __ipipe_mach_ticks_per_jiffy)
- & AT91_TC_REG_MASK;
- write_RC(next_match);
- }
+ if (unlikely(!__ipipe_mach_timerstolen))
+ __ipipe_mach_set_dec(max_delta_ticks);
}
static void
@@ -147,7 +145,7 @@ at91_tc_set_mode(enum clock_event_mode mode, struct
clock_event_device *dev)
/* Disable all interrupts. */
at91_tc_write(AT91_TC_IDR, ~0ul);
- if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ if (mode == CLOCK_EVT_MODE_ONESHOT) {
unsigned long v;
#ifndef CONFIG_ARCH_AT91SAM9263
@@ -169,9 +167,7 @@ at91_tc_set_mode(enum clock_event_mode mode, struct
clock_event_device *dev)
/* Use the clock selected by at91_timer_init as input clock. */
at91_tc_write(AT91_TC_CMR, tc_timer_clock);
- /* Load the TC register C. */
- next_match = __ipipe_mach_ticks_per_jiffy;
- write_RC(next_match);
+ __ipipe_mach_set_dec(max_delta_ticks);
/* Enable CPCS interrupt. */
at91_tc_write(AT91_TC_IER, AT91_TC_CPCS);
@@ -181,6 +177,14 @@ at91_tc_set_mode(enum clock_event_mode mode, struct
clock_event_device *dev)
}
}
+static int
+at91_tc_set_next_event(unsigned long delta, struct clock_event_device *dev)
+{
+ tick_pending = 1;
+ __ipipe_mach_set_dec(delta);
+ return 0;
+}
+
/*
* Reprogram the timer
*/
@@ -208,10 +212,11 @@ int __ipipe_check_tickdev(const char *devname)
static struct clock_event_device clkevt = {
.name = "at91_tc" __stringify(CONFIG_IPIPE_AT91_TC),
- .features = CLOCK_EVT_FEAT_PERIODIC,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 20,
.rating = 250,
.set_mode = at91_tc_set_mode,
+ .set_next_event = at91_tc_set_next_event,
};
static struct __ipipe_tscinfo tsc_info = {
@@ -230,7 +235,7 @@ static struct __ipipe_tscinfo tsc_info = {
void __ipipe_mach_release_timer(void)
{
- __ipipe_mach_set_dec(__ipipe_mach_ticks_per_jiffy);
+ clkevt.set_next_event(__ipipe_mach_ticks_per_jiffy, &clkevt);
}
EXPORT_SYMBOL(__ipipe_mach_release_timer);
@@ -293,15 +298,16 @@ void __init at91_timer_init(void)
clkevt.max_delta_ns = wrap_ns;
clkevt.min_delta_ns = 2000;
clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&clkevt);
-
- tsc_info.freq = divided_freq;
- __ipipe_tsc_register(&tsc_info);
__ipipe_mach_ticks_per_jiffy = (divided_freq + HZ/2) / HZ;
max_delta_ticks = (wrap_ns * clkevt.mult) >> clkevt.shift;
min_delta_ticks = ((unsigned long long) clkevt.min_delta_ns
* clkevt.mult) >> clkevt.shift;
+
+ clockevents_register_device(&clkevt);
+
+ tsc_info.freq = divided_freq;
+ __ipipe_tsc_register(&tsc_info);
}
#ifdef CONFIG_ARCH_AT91RM9200
--
Gilles.
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help