⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtl_time.c

📁 rtlinux3.0 的源代码
💻 C
字号:
/* * rtl_time.c * * PPC-specific clock support * * Copyright (C) 1999 Cort Dougan <cort@fsmlabs.com> */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/timex.h>#include <linux/mc146818rtc.h>#include <asm/smp.h>#include <asm/system.h>#include <asm/io.h>#include <asm/time.h>#include <rtl_core.h>#include <rtl_time.h>#include <rtl.h>static void _decr_uninit (clockid_t clock);static int _decr_init (clockid_t clock);static hrtime_t _decr_gettime (struct rtl_clock *);static int _decr_settimer (struct rtl_clock *, hrtime_t interval);static int _decr_settimermode (struct rtl_clock *, int mode);unsigned int decr_intercept(struct pt_regs *);unsigned long linux_decrs = 0;unsigned long linux_decrementer_count = 0, rtl_decrementer_count;unsigned long last_tb = 0;/* * Handle >=2.4.0 vs. earlier differences * --- * decrementer_count changed to tb_ticks_per_jiffy in 2.4.0 * * The interrupt handler in linux/ppc is more complicated with later * versions so we have a flag to just tell it to not touch the decr. * This should prevent others from messing with the code without * understanding it, too. *   -- Cort <cort@fsmlabs.com> */#if LINUX_2_4_0_FINAL_OR_LATER#define decrementer_count tb_ticks_per_jiffyextern unsigned long disarm_decr;#else /* LINUX_2_4_0_FINAL_OR_LATER */extern unsigned long decrementer_count;#endif /* LINUX_2_4_0_FINAL_OR_LATER */void default_handler(struct pt_regs *regs);MODULE_AUTHOR("Cort Dougan <cort@fsmlabs.com>");MODULE_DESCRIPTION("RTLinux PPC Timer Module");struct rtl_clock decr_clock ={	_decr_init, _decr_uninit,	_decr_gettime,	NULL, /* sethrtime */	_decr_settimer,	_decr_settimermode,	default_handler, /* handler */	RTL_CLOCK_MODE_ONESHOT, /* mode */};hrtime_t _decr_gettime (struct rtl_clock *clock){	unsigned long tbu, tbl, tbu1;	hrtime_t tb, ret;	/*	 * Possible bug pointed out by Niklaus Giger where	 * the timebase goes from ~0x0 to 0x0.  This	 * catches that case now.  -- Cort	 */	do {		asm volatile("mftbu	%2\n\t"			     "mftb 	%0\n\t"			     "mftbu	%1\n\t"			     : "=r" (tbl), "=r" (tbu), "=r" (tbu1) );	} while (tbu != tbu1);	tb = (hrtime_t)tbl + ((hrtime_t)tbu<<32);	/*	 * Changed this calculation so we take into account the	 * fact that decrementer ticks are not even multiples of	 * ns's.	 *	 * First we get the number of linux ticks that have occurred	 * so far, which is an even multiple of ns's (NSECS_PER_SEC/HZ).	 * Then, get the next fraction of a linux tick and compute	 * the number of ns as best we can with 64-bit arithmetic.	 *   -- Cort	 */	ret = (tb / linux_decrementer_count) * ((hrtime_t)NSECS_PER_SEC/HZ);	ret += ((tb % linux_decrementer_count) * ((hrtime_t)NSECS_PER_SEC/HZ))		/ linux_decrementer_count;	return ret;}static int _decr_settimer(struct rtl_clock *clock, hrtime_t interval){	unsigned long t;	if (interval)	{		/*		 * ns to decr ticks, rounds down -- Cort		 * fixed to round up as required by posix -- Michael		 * fixed to compute ticks with 64-bit arithmetic so		 * we don't lose precision.  We need this precision		 * because PPC decrementer ticks are not always multiples		 * of ns's.  Still rounds up.		 *  -- Cort		 */		t = (ulong)((interval * (hrtime_t)linux_decrementer_count) / ((hrtime_t)NSECS_PER_SEC/(hrtime_t)HZ)) + 1;		if (decr_clock.mode == RTL_CLOCK_MODE_PERIODIC)			clock->resolution = interval;		else			clock->resolution = 1;		/* sanity check to make sure we're not setting a bad value */		if (t < 1)			t = 1;		/*		 * If next tick is set for a time beyond when Linux wants a tick		 * then just set it for when Linux wants it.  This skips the		 * case when we're already overdue for a Linux tick.		 *   -- Cort		 */		else if ( (linux_decrs < linux_decrementer_count) &&			  (t > (linux_decrementer_count - linux_decrs)) )		{			t = linux_decrementer_count - linux_decrs;		}				rtl_decrementer_count = t;	}		/*	 * actually setup the decrementer, taking into account the	 * time that has elapsed since the decrementer crossed 0	 */	{		unsigned long dval;		dval = get_dec();		set_dec(rtl_decrementer_count);		decr_clock.arch.istimerset = 1;	}	return 0;}static int _decr_settimermode(struct rtl_clock *clock, int mode){	clock->mode = mode;	return 0;}clockid_t rtl_getbestclock (unsigned int cpu){        return &decr_clock;}hrtime_t gethrtime(void){	return _decr_gettime(&decr_clock);}hrtime_t gethrtimeres(void){	return (NSECS_PER_SEC/HZ)/linux_decrementer_count;}int init_module (void){	/* keep a copy of the decrementer count that Linux wants */	linux_decrementer_count = decrementer_count;	rtl_init_standard_clocks();	return 0;}void cleanup_module(void){	rtl_cleanup_standard_clocks();	decrementer_count = linux_decrementer_count;}unsigned int decr_intercept(struct pt_regs *regs){	unsigned long dval;	int d;	void (*handler)( struct pt_regs *regs) = decr_clock.handler;		/*	 * Compute the # ticks since last interrupt so	 * we can keep track of how many Linux has accrued	 */	{		unsigned long diff, tb;		asm volatile("mftb 	%0" : "=r" (tb) );		diff = tb - last_tb;		last_tb = tb;		linux_decrs += diff;	}		/*	 * If it's one-shot clear the handler and reset the 	 * timer.	 */	if ( decr_clock.mode == RTL_CLOCK_MODE_ONESHOT )	{		decr_clock.arch.istimerset = 0;	} else {		dval = get_dec();		while ((d = (int)get_dec()) == dval)			;		if ( (int)(d + rtl_decrementer_count) < 500 )		{			printk("_decr_intercept(): d %08x decr_count %08lx too low: time overrun likely\n",			       d, rtl_decrementer_count);			set_dec(rtl_decrementer_count);		}		else			set_dec(d + rtl_decrementer_count);	}		/*	 * Give Linux a timer interrupt if one is due.	 *	 * Linux/ppc >=2.4.0 handles all pending interrupts in a single	 * call to the interrupt handler by looking at the timebase	 * so for it we just give it one pend.  For earlier versions	 * of Linux we have to give it a timer interrupt for each	 * on that it has missed.	 *   -- Cort <cort@fsmlabs.com>	 */#if LINUX_2_4_0_FINAL_OR_LATER	if ( linux_decrs >= linux_decrementer_count )	{		rtl_local_pend_vec(0,0);		while ( linux_decrs >= linux_decrementer_count )			linux_decrs -= linux_decrementer_count;	}#else	  	if ( linux_decrs >= linux_decrementer_count )	{		if ( !rtl_local_ispending_irq(0) )		{			rtl_local_pend_vec(0,0);			linux_decrs -= linux_decrementer_count;		}	}#endif /* LINUX_2_4_0_FINAL_OR_LATER */		if ( handler != default_handler )		handler(regs);	if (!decr_clock.arch.istimerset)	{		/* setup the next tick to be when Linux wants one		 * since we don't have anything pending		 */		if ( linux_decrementer_count > linux_decrs)			set_dec(linux_decrementer_count - linux_decrs);		else			set_dec(linux_decrementer_count);		decr_clock.arch.istimerset = 1;	}		return 0;}static int _decr_init (clockid_t clock){	rtl_decrementer_count = linux_decrementer_count;	/* we're taking over control of the decr so tell linux to leave it alone */#if LINUX_2_4_0_FINAL_OR_LATER	disarm_decr = 1;#else	decrementer_count = 0;#endif		asm volatile("mftb 	%0" : "=r" (last_tb) );	if ( rtl_request_local_irq(0, decr_intercept, 0) )	{		printk("Failed getting local timer irq\n");		return -1;	}	set_dec(rtl_decrementer_count);	  	return 0;}static void _decr_uninit (clockid_t clock){	rtl_free_local_irq(0,0);		/* give decr control back to linux */#if LINUX_2_4_0_FINAL_OR_LATER	disarm_decr = 0;#else	decrementer_count = linux_decrementer_count;#endif		clock->handler = RTL_CLOCK_DEFAULTS.handler;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -