Hi again! I've the presumption, there is something wrong with my timer-handling. Could you please take a look at my handling.
Thanks in advance!
__ipipe_mach_get_tsc should return the absolute timer-ticks since
bootup, right?
my current handling:
INIT:
* ns_timer_reload=ticks_per_jiffy
* timer is loaded with ns_timer_reload
* timer is configured to start counting down from ns_timer_reload to
zero and trigger an interrupt; after triggering it reloads automatically
with ns_timer_reload.
IPIPE-FUNCTIONS:
#define ns_getticksoffset(timer) \
(likely(ns_tscok) ? ns_timer_reload - TIMER_READ(timer) : 0)
/* called after each timer-interrupt */
/* never called, if interrupt is triggered manually! */
void __ipipe_mach_acktimer(void)
{
/* int -> ns_timer_reload ticks are done; timer has already reloaded
with ns_timer_reload and is counting */
__ipipe_mach_tsc+=ns_timer_reload;
ns_timer_lxlost+=ns_timer_reload;
/* ack interrupt */
TIMER_ACKINT(TIMER_USED);
}
EXPORT_SYMBOL(__ipipe_mach_acktimer);
/* get ticks since start */
unsigned long long __ipipe_mach_get_tsc(void)
{
unsigned long long result;
unsigned long flags;
spin_lock_irqsave_hw(&timer_lock, flags);
/* ticks before last interrupt + ticks since last interrupt (ack) */
result = __ipipe_mach_tsc + ns_getticksoffset(TIMER_USED);
spin_unlock_irqrestore_hw(&timer_lock, flags);
return result;
}
EXPORT_SYMBOL(__ipipe_mach_get_tsc);
/* set new timer reload */
void __ipipe_mach_set_dec(unsigned long reload)
{
unsigned long ticks;
unsigned long flags;
spin_lock_irqsave_hw(&timer_lock, flags);
/* ticks since last interrupt (since ack) */
ticks = ns_getticksoffset(TIMER_USED);
__ipipe_mach_tsc += ticks;
ns_timer_lxlost += ticks;
/* reprogramm timer */
set_dec(TIMER_USED,reload);
spin_unlock_irqrestore_hw(&timer_lock, flags);
}
EXPORT_SYMBOL(__ipipe_mach_set_dec);
/* get timer value */
unsigned long __ipipe_mach_get_dec(void)
{
return TIMER_READ(TIMER_USED);
}
EXPORT_SYMBOL(__ipipe_mach_get_dec);
whole source see attachment
- Manfred
/*
* linux/include/asm-arm/arch-ns9750/time.h
*
* Copyright (C) 2004 by FS Forth-Systeme GmbH.
* All rights reserved.
* Markus Pietrek <[EMAIL PROTECTED]>
* @References: [1] NS9750 Hardware Reference/December 2003
* [2] derived from arch-integrator/time.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/***********************************************************************
* @History:
* 2006/09/01 : Adeos/ipipe support by Schlaegl Manfred jun.
* <[EMAIL PROTECTED]>
* 2004/09/02 : implemented gettimeoffset
* 2004/08/20 : ported to kernel 2.6.8
***********************************************************************/
#include <linux/module.h> /* EXPORT_SYMBOL */
#include <linux/ioport.h> /* request_resource */
#include <linux/interrupt.h> /* irqreturn_t */
#include <asm/io.h> /* writel */
#include <asm/mach-types.h>
#include <asm/arch/ns9750_sys.h> /* NS_SYS */
#include <asm/arch/irqs.h> /* IRQ_TIMER_0 */
#include <asm/arch/time.h> /* ns_time_init */
#include <asm/arch/timex.h> /* frequency */
/* start default debug-level */
#define DEBUG_ENABLED
#define DEFAULT_DEBUG 0
/* timer used as system timer */
#define TIMER_USED 0
/* activate sequence lock while system-timer-isr (from integrator) */
#define SEQ_LOCK
/*************************************************************************************
# begin DEFINITIONS
**************************************************************************************/
#define CAT(x,y) x ## y
#define XCAT(x,y) CAT(x,y)
#define NS_SYS_TIMER_CTRL_TLCS(tlcs) XCAT(NS_SYS_TIMER_CTRL_TLCS_,tlcs)
#if 0
/* timer frequency = full clock-frequency / TLCS */
#define CFG_HZ (CPU_CLK_FREQ/TIMER_FDIV)
#endif
/* isr */
static irqreturn_t ns9750_timer_interrupt( /[EMAIL PROTECTED]@*/ int irq,
void* dev_id,
struct pt_regs* regs );
static struct irqaction ns_timer_irq = {
.name = "NS9750 Timer Tick",
.flags = SA_INTERRUPT | SA_TIMER,
.handler = ns9750_timer_interrupt
};
/* reload value for timer */
static unsigned int ns_timer_reload;
/* correct ticks */
static unsigned long ns_timer_delta_old;
static unsigned int ns_timer_jiffies_old;
/* lost ticks, saved if __ipipe_mach_set_sec while running timer */
static unsigned long ns_timer_lxlost;
/* timer ok - flag */
static int ns_tscok;
/*************************************************************************************
# begin IPIPE-SPECIFIC VARIABLES
**************************************************************************************/
#ifdef CONFIG_IPIPE
#ifdef CONFIG_NO_IDLE_HZ
#error "dynamic tick timer not yet supported with IPIPE"
#endif /* CONFIG_NO_IDLE_HZ */
/* the timer interrupt */
int __ipipe_mach_timerint = IRQ_TIMER_0 + TIMER_USED;
EXPORT_SYMBOL(__ipipe_mach_timerint);
/* ticks-counter */
static unsigned long long __ipipe_mach_tsc;
/* timer lock */
static DEFINE_SPINLOCK(timer_lock);
/* timer stolen - flag */
int __ipipe_mach_timerstolen = 0;
EXPORT_SYMBOL(__ipipe_mach_timerstolen);
/*************************************************************************************
# end IPIPE-SPECIFIC VARIABLES
**************************************************************************************/
#endif /* CONFIG_IPIPE */
/* timer-ticks per jiffy (init in ns_time_init) */
unsigned int __ipipe_mach_ticks_per_jiffy;
EXPORT_SYMBOL(__ipipe_mach_ticks_per_jiffy);
void __tm_init_timer(void);
/*************************************************************************************
# begin DEBUG-HANDLING
**************************************************************************************/
int DEBUG = DEFAULT_DEBUG;
#define MY_NAME "time.c"
/* debug messages */
#ifdef DEBUG_ENABLED
#define dbg_raw(level, fmt, arg...) \
do { \
if (level<=DEBUG) \
printk (fmt, ## arg); \
} while (0)
#else
#define dbg_raw(level, fmt, arg...)
#endif
/* debug messages with module- and function-information */
#define dbg(level, fmt, arg...) \
dbg_raw(level, "%s: %s:\t\t" fmt, MY_NAME , __FUNCTION__ , ## arg)
/*************************************************************************************
# end DEBUG-HANDLING
**************************************************************************************/
/*************************************************************************************
# begin GENERAL TIMER-FUNCTIONS
**************************************************************************************/
/* read timer value */
#define TIMER_READ(timer) \
readl(NS_SYS_TIMER_READ(timer))
/* set timer reload */
#define TIMER_SET_RELOAD(timer, reload) \
writel( reload, NS_SYS_TIMER_COUNT(timer) )
/* set timer ctrl */
#define TIMER_SET_CTRL(timer, ctrl) \
writel( ctrl, NS_SYS_TIMER_CTRL(timer) )
/* disable timer (TEN and generate interrupt) */
#define TIMER_DISABLE(timer) \
rmwl( NS_SYS_TIMER_CTRL(timer), & ~NS_SYS_TIMER_CTRL_TEN & ~NS_SYS_TIMER_CTRL_INTS);
/* enable timer (TEN and generate interrupt) */
#define TIMER_ENABLE(timer) \
rmwl( NS_SYS_TIMER_CTRL(timer), | NS_SYS_TIMER_CTRL_TEN | NS_SYS_TIMER_CTRL_INTS)
/* clear timer */
#define TIMER_CLEAR(timer) \
do { \
writel(0,NS_SYS_TIMER_CTRL(timer) ); \
TIMER_SET_RELOAD(timer,0); \
} while(0)
/* ack timer interrupt */
#define TIMER_ACKINT(timer) \
do { \
rmwl( NS_SYS_TIMER_CTRL(timer), | NS_SYS_TIMER_CTRL_INTC ); \
rmwl( NS_SYS_TIMER_CTRL(timer), & ~NS_SYS_TIMER_CTRL_INTC ); \
}while (0)
/*************************************************************************************
# end GENERAL TIMER-FUNCTIONS
**************************************************************************************/
/*************************************************************************************
# begin SPECIFIC SYSTEM-TIMER-FUNCTIONS
**************************************************************************************/
/* init system-timer */
#define TIMER_INIT(timer) \
TIMER_SET_CTRL(timer, \
NS_SYS_TIMER_CTRL_TLCS(TIMER_FDIV) | /* clockfreq / TIMER_FDIV */ \
NS_SYS_TIMER_CTRL_REN | /* periodic */ \
NS_SYS_TIMER_CTRL_TDBG | /* stop timer in debug-mode */ \
NS_SYS_TIMER_CTRL_UDS | /* down-counter */ \
NS_SYS_TIMER_CTRL_TSZ /* 32 bit */ \
)
/* reprogramm timer */
static inline void set_dec(int timer, unsigned long reload)
{
/* disable timer */
TIMER_DISABLE(timer);
/* set new reload-value */
TIMER_SET_RELOAD(timer,reload);
/* activate timer */
TIMER_ENABLE(timer);
/* save reload */
ns_timer_reload = reload;
}
/* get ticks-offset */
#define ns_getticksoffset(timer) \
(likely(ns_tscok) ? ns_timer_reload - TIMER_READ(timer) : 0)
/*
* Returns number of us since last clock interrupt. Note that interrupts
* will have been disabled by do_gettimeoffset()
*/
unsigned long ns9750_gettimeoffset(void)
{
/* get ticks */
unsigned long timer_delta = ns_getticksoffset(TIMER_USED);
#if 1 /* correction from original-implementation */
if( ns_timer_jiffies_old == jiffies && ns_timer_delta_old > timer_delta ) {
/* we are called by arm/kernel/time.c:do_gettimeofday with
* interrupts disabled.
* It may happen then that there is a timer reload after
* interrupts disable. Therefore jiffies is not incremented.
* So while jiffies has not been updated, return the old
* time. */
timer_delta = ns_timer_delta_old;
} else {
ns_timer_delta_old = timer_delta;
ns_timer_jiffies_old = jiffies;
}
#endif
/* calc */
return ( (1000 * (ns_timer_lxlost + timer_delta)) / (__ipipe_mach_ticks_per_jiffy / 10) );
}
EXPORT_SYMBOL(ns9750_gettimeoffset);
/*
* IRQ handler for the timer
*/
static irqreturn_t ns9750_timer_interrupt( /[EMAIL PROTECTED]@*/ int irq,
void* dev_id,
struct pt_regs* regs )
{
#ifdef SEQ_LOCK
write_seqlock(&xtime_lock);
#endif
#ifdef CONFIG_IPIPE
/*
* - if Linux is running natively (no ipipe), ack the timer (reprogramming automatically)
* - if Linux is running under ipipe, but it still has the control over
* the timer (no Xenomai for example), then do nothing (ipipe
* has already acked it; reprogramming automatically)
* - if some other domain has taken over the timer, then do nothing
* (ipipe has acked it, and the other domain has reprogramed it)
*/
/* save ticks since boot */
if (!__ipipe_mach_timerstolen) {
/* ticks since last int (already done in ack)*/
// __ipipe_mach_tsc += ns_timer_reload;
}
#else
/* ack_timer */
TIMER_ACKINT(TIMER_USED);
#endif
/* clear lost ticks since last timer_tick */
ns_timer_lxlost = 0;
/* linux timer tick */
timer_tick( regs );
#ifdef SEQ_LOCK
write_sequnlock(&xtime_lock);
#endif
return IRQ_HANDLED;
}
static struct resource timer_resource[ 3 ] = {
{
.name = "system timer",
.start = (NS_SYS_TIMER_CTRL( TIMER_USED ) ),
.end = (NS_SYS_TIMER_CTRL( TIMER_USED ) ) + 3,
},
{
.name = "system timer",
.start = (NS_SYS_TIMER_READ( TIMER_USED ) ),
.end = (NS_SYS_TIMER_READ( TIMER_USED ) ) + 3,
},
{
.name = "system timer",
.start = (NS_SYS_TIMER_COUNT( TIMER_USED ) ),
.end = (NS_SYS_TIMER_COUNT( TIMER_USED ) ) + 3,
}
};
/*
* Set up timer interrupt, and return the current time in seconds.
*/
void __init ns_time_init( void )
{
request_resource( &iomem_resource, &timer_resource[ 0 ] );
request_resource( &iomem_resource, &timer_resource[ 1 ] );
request_resource( &iomem_resource, &timer_resource[ 2 ] );
__ipipe_mach_ticks_per_jiffy = LATCH;
dbg(0,"\n"
" system-clock: %d Hz\n"
" timer-clock: %d Hz (=system-clock/%d) \n"
" ticks_per_jiffy: %d \n"
" jiffis per usecs %d (HZ-value)\n"
,
CPU_CLK_FREQ,
CLOCK_TICK_RATE, TIMER_FDIV,
__ipipe_mach_ticks_per_jiffy,
HZ
);
/* clear timer*/
TIMER_CLEAR(TIMER_USED);
/* set timer-isr */
setup_irq( IRQ_TIMER_0 + TIMER_USED, &ns_timer_irq );
/* init timer */
TIMER_INIT(TIMER_USED);
/* reload timer */
set_dec(TIMER_USED,__ipipe_mach_ticks_per_jiffy); /* a tick every HZ */
/* ok */
ns_tscok = 1;
}
/*************************************************************************************
# end SPECIFIC SYSTEM-TIMER-FUNCTIONS
**************************************************************************************/
#ifdef CONFIG_IPIPE
/*************************************************************************************
# begin IPIPE-FUNCTIONS
**************************************************************************************/
/* called after each timer-interrupt */
/* never called, if interrupt is triggered manually! */
void __ipipe_mach_acktimer(void)
{
/* int -> ns_timer_reload ticks done */
__ipipe_mach_tsc+=ns_timer_reload;
ns_timer_lxlost+=ns_timer_reload;
/* ack interrupt */
TIMER_ACKINT(TIMER_USED);
}
EXPORT_SYMBOL(__ipipe_mach_acktimer);
/* get ticks since start */
unsigned long long __ipipe_mach_get_tsc(void)
{
unsigned long long result;
unsigned long flags;
spin_lock_irqsave_hw(&timer_lock, flags);
result = __ipipe_mach_tsc + ns_getticksoffset(TIMER_USED);
spin_unlock_irqrestore_hw(&timer_lock, flags);
return result;
}
EXPORT_SYMBOL(__ipipe_mach_get_tsc);
/* set new timer reload */
void __ipipe_mach_set_dec(unsigned long reload)
{
unsigned long ticks;
unsigned long flags;
spin_lock_irqsave_hw(&timer_lock, flags);
/* ticks since last int */
ticks = ns_getticksoffset(TIMER_USED);
__ipipe_mach_tsc += ticks;
ns_timer_lxlost += ticks;
/* reprogramm timer */
set_dec(TIMER_USED,reload);
spin_unlock_irqrestore_hw(&timer_lock, flags);
}
EXPORT_SYMBOL(__ipipe_mach_set_dec);
/* get timer value */
unsigned long __ipipe_mach_get_dec(void)
{
return TIMER_READ(TIMER_USED);
}
EXPORT_SYMBOL(__ipipe_mach_get_dec);
/*************************************************************************************
# end IPIPE-FUNCTIONS
**************************************************************************************/
#endif /* CONFIG_IPIPE */
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Xenomai-help mailing list [email protected] https://mail.gna.org/listinfo/xenomai-help
