diff options
| author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2006-10-24 00:21:27 +0900 | 
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2006-10-31 20:13:23 +0000 | 
| commit | 16b7b2ac0148e839da86af8747b6fa4aad43a9b7 (patch) | |
| tree | 93912ae2e9c64f71a8cca028677fd918b9edf0fa | |
| parent | 70e46f48cb5933119712ee27945309a4bfc98282 (diff) | |
| download | blackbird-op-linux-16b7b2ac0148e839da86af8747b6fa4aad43a9b7.tar.gz blackbird-op-linux-16b7b2ac0148e839da86af8747b6fa4aad43a9b7.zip  | |
[MIPS] Fixup migration to GENERIC_TIME
Since we already moved to GENERIC_TIME, we should implement alternatives
of old do_gettimeoffset routines to get sub-jiffies resolution from
gettimeofday().  This patch includes:
 * MIPS clocksource support (based on works by Manish Lachwani).
 * remove unused gettimeoffset routines and related codes.
 * remove unised 64bit do_div64_32().
 * simplify mips_hpt_init. (no argument needed, __init tag)
 * simplify c0_hpt_timer_init. (no need to write to c0_count)
 * remove some hpt_init routines.
 * mips_hpt_mask variable to specify bitmask of hpt value.
 * convert jmr3927_do_gettimeoffset to jmr3927_hpt_read.
 * convert ip27_do_gettimeoffset to ip27_hpt_read.
 * convert bcm1480_do_gettimeoffset to bcm1480_hpt_read.
 * simplify sb1250 hpt functions. (no need to subtract and shift)
    
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
| -rw-r--r-- | Documentation/mips/time.README | 39 | ||||
| -rw-r--r-- | arch/mips/au1000/common/time.c | 98 | ||||
| -rw-r--r-- | arch/mips/dec/time.c | 9 | ||||
| -rw-r--r-- | arch/mips/jmr3927/rbhma3100/setup.c | 40 | ||||
| -rw-r--r-- | arch/mips/kernel/time.c | 319 | ||||
| -rw-r--r-- | arch/mips/philips/pnx8550/common/time.c | 4 | ||||
| -rw-r--r-- | arch/mips/pmc-sierra/yosemite/smp.c | 6 | ||||
| -rw-r--r-- | arch/mips/sgi-ip27/ip27-timer.c | 16 | ||||
| -rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 33 | ||||
| -rw-r--r-- | arch/mips/sibyte/sb1250/time.c | 28 | ||||
| -rw-r--r-- | include/asm-mips/div64.h | 21 | ||||
| -rw-r--r-- | include/asm-mips/sibyte/sb1250.h | 2 | ||||
| -rw-r--r-- | include/asm-mips/time.h | 10 | 
13 files changed, 103 insertions, 522 deletions
diff --git a/Documentation/mips/time.README b/Documentation/mips/time.README index e1304b6bc483..a4ce603ed3b3 100644 --- a/Documentation/mips/time.README +++ b/Documentation/mips/time.README @@ -38,19 +38,14 @@ The new time code provide the following services:    a) Implements functions required by Linux common code:  	time_init -	do_gettimeofday -	do_settimeofday    b) provides an abstraction of RTC and null RTC implementation as default.  	extern unsigned long (*rtc_get_time)(void);  	extern int (*rtc_set_time)(unsigned long); -  c) a set of gettimeoffset functions for different CPUs and different -     needs. - -  d) high-level and low-level timer interrupt routines where the timer  -     interrupt source  may or may not be the CPU timer.  The high-level  -     routine is dispatched through do_IRQ() while the low-level is  +  c) high-level and low-level timer interrupt routines where the timer +     interrupt source  may or may not be the CPU timer.  The high-level +     routine is dispatched through do_IRQ() while the low-level is       dispatched in assemably code (usually int-handler.S) @@ -73,8 +68,7 @@ the following functions or values:    c) (optional) board-specific RTC routines.    d) (optional) mips_hpt_frequency - It must be definied if the board -     is using CPU counter for timer interrupt or it is using fixed rate -     gettimeoffset(). +     is using CPU counter for timer interrupt.  PORTING GUIDE @@ -89,16 +83,6 @@ Step 1: decide how you like to implement the time services.       If the answer is no, you need a timer to provide the timer interrupt       at 100 HZ speed. -     You cannot use the fast gettimeoffset functions, i.e., - -	unsigned long fixed_rate_gettimeoffset(void); -	unsigned long calibrate_div32_gettimeoffset(void); -	unsigned long calibrate_div64_gettimeoffset(void); - -    You can use null_gettimeoffset() will gives the same time resolution as -    jiffy.  Or you can implement your own gettimeoffset (probably based on  -    some ad hoc hardware on your machine.) -    c) The following sub steps assume your CPU has counter register.       Do you plan to use the CPU counter register as the timer interrupt       or use an exnternal timer? @@ -123,8 +107,8 @@ Step 3: implement rtc routines, board_time_init() and plat_timer_setup()    board_time_init() -    	a) (optional) set up RTC routines,          b) (optional) calibrate and set the mips_hpt_frequency - 	    (only needed if you intended to use fixed_rate_gettimeoffset - 	     or use cpu counter as timer interrupt source) + 	    (only needed if you intended to use cpu counter as timer interrupt + 	     source)    plat_timer_setup() -   	a) (optional) over-write any choices made above by time_init(). @@ -154,8 +138,8 @@ for some of the functions in time.c.  For example, you may define your own timer interrupt routine, which does  some of its own processing and then calls timer_interrupt(). -You can also over-ride any of the built-in functions (gettimeoffset, -RTC routines and/or timer interrupt routine). +You can also over-ride any of the built-in functions (RTC routines +and/or timer interrupt routine).  PORTING NOTES FOR SMP @@ -187,10 +171,3 @@ You need to decide on your timer interrupt sources.  	You can also do the low-level version of those interrupt routines,  	following similar dispatching routes described above. - -Note about do_gettimeoffset(): - -  It is very likely the CPU counter registers are not sync'ed up in a SMP box. -  Therefore you cannot really use the many of the existing routines that -  are based on CPU counter.  You should wirte your own gettimeoffset rouinte -  if you want intra-jiffy resolution. diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 6768638883ea..fa1c62f05515 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -53,9 +53,6 @@ static unsigned long r4k_cur;    /* What counter should be at next timer irq */  int	no_au1xxx_32khz;  extern int allow_au1k_wait; /* default off for CP0 Counter */ -/* Cycle counter value at the previous timer interrupt.. */ -static unsigned int timerhi = 0, timerlo = 0; -  #ifdef CONFIG_PM  #if HZ < 100 || HZ > 1000  #error "unsupported HZ value! Must be in [100,1000]" @@ -90,10 +87,6 @@ void mips_timer_interrupt(void)  		goto null;  	do { -		count = read_c0_count(); -		timerhi += (count < timerlo);   /* Wrap around */ -		timerlo = count; -  		kstat_this_cpu.irqs[irq]++;  		do_timer(1);  #ifndef CONFIG_SMP @@ -297,88 +290,6 @@ unsigned long cal_r4koff(void)  	return (cpu_speed / HZ);  } -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) -#define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff) - -static unsigned long -div64_32(unsigned long v1, unsigned long v2, unsigned long v3) -{ -	unsigned long r0; -	do_div64_32(r0, v1, v2, v3); -	return r0; -} - -static unsigned long do_fast_cp0_gettimeoffset(void) -{ -	u32 count; -	unsigned long res, tmp; -	unsigned long r0; - -	/* Last jiffy when do_fast_gettimeoffset() was called. */ -	static unsigned long last_jiffies=0; -	unsigned long quotient; - -	/* -	 * Cached "1/(clocks per usec)*2^32" value. -	 * It has to be recalculated once each jiffy. -	 */ -	static unsigned long cached_quotient=0; - -	tmp = jiffies; - -	quotient = cached_quotient; - -	if (tmp && last_jiffies != tmp) { -		last_jiffies = tmp; -		if (last_jiffies != 0) { -			r0 = div64_32(timerhi, timerlo, tmp); -			quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0); -			cached_quotient = quotient; -		} -	} - -	/* Get last timer tick in absolute kernel time */ -	count = read_c0_count(); - -	/* .. relative to previous jiffy (32 bits is enough) */ -	count -= timerlo; - -	__asm__("multu\t%1,%2\n\t" -		"mfhi\t%0" -		: "=r" (res) -		: "r" (count), "r" (quotient) -		: "hi", "lo", GCC_REG_ACCUM); - -	/* -	 * Due to possible jiffies inconsistencies, we need to check -	 * the result so that we'll get a timer that is monotonic. -	 */ -	if (res >= USECS_PER_JIFFY) -		res = USECS_PER_JIFFY-1; - -	return res; -} - -#ifdef CONFIG_PM -static unsigned long do_fast_pm_gettimeoffset(void) -{ -	unsigned long pc0; -	unsigned long offset; - -	pc0 = au_readl(SYS_TOYREAD); -	au_sync(); -	offset = pc0 - last_pc0; -	if (offset > 2*MATCH20_INC) { -		printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", -				(unsigned)offset, (unsigned)last_pc0, -				(unsigned)last_match20, (unsigned)pc0); -	} -	offset = (unsigned long)((offset * 305) / 10); -	return offset; -} -#endif -  void __init plat_timer_setup(struct irqaction *irq)  {  	unsigned int est_freq; @@ -416,7 +327,6 @@ void __init plat_timer_setup(struct irqaction *irq)  		unsigned int c0_status;  		printk("WARNING: no 32KHz clock found.\n"); -		do_gettimeoffset = do_fast_cp0_gettimeoffset;  		/* Ensure we get CPO_COUNTER interrupts.  		*/ @@ -441,19 +351,11 @@ void __init plat_timer_setup(struct irqaction *irq)  		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);  		startup_match20_interrupt(counter0_irq); -		do_gettimeoffset = do_fast_pm_gettimeoffset; -  		/* We can use the real 'wait' instruction.  		*/  		allow_au1k_wait = 1;  	} -#else -	/* We have to do this here instead of in timer_init because -	 * the generic code in arch/mips/kernel/time.c will write -	 * over our function pointer. -	 */ -	do_gettimeoffset = do_fast_cp0_gettimeoffset;  #endif  } diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 4cf0c06e2414..69e424e9ab6f 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -160,11 +160,6 @@ static unsigned int dec_ioasic_hpt_read(void)  	return ioasic_read(IO_REG_FCTR);  } -static void dec_ioasic_hpt_init(unsigned int count) -{ -	ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count); -} -  void __init dec_time_init(void)  { @@ -174,11 +169,9 @@ void __init dec_time_init(void)  	mips_timer_state = dec_timer_state;  	mips_timer_ack = dec_timer_ack; -	if (!cpu_has_counter && IOASIC) { +	if (!cpu_has_counter && IOASIC)  		/* For pre-R4k systems we use the I/O ASIC's counter.  */  		mips_hpt_read = dec_ioasic_hpt_read; -		mips_hpt_init = dec_ioasic_hpt_init; -	}  	/* Set up the rate of periodic DS1287 interrupts.  */  	CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 025434054ed0..16e5dfe7aa8a 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -170,12 +170,20 @@ static void jmr3927_machine_power_off(void)  	while (1);  } +static unsigned int jmr3927_hpt_read(void) +{ +	/* We assume this function is called xtime_lock held. */ +	return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr; +} +  #define USE_RTC_DS1742  #ifdef USE_RTC_DS1742  extern void rtc_ds1742_init(unsigned long base);  #endif  static void __init jmr3927_time_init(void)  { +	mips_hpt_read = jmr3927_hpt_read; +	mips_hpt_frequency = JMR3927_TIMER_CLK;  #ifdef USE_RTC_DS1742  	if (jmr3927_have_nvram()) {  	        rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR); @@ -183,12 +191,8 @@ static void __init jmr3927_time_init(void)  #endif  } -unsigned long jmr3927_do_gettimeoffset(void); -  void __init plat_timer_setup(struct irqaction *irq)  { -	do_gettimeoffset = jmr3927_do_gettimeoffset; -  	jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ;  	jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE;  	jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; @@ -200,34 +204,6 @@ void __init plat_timer_setup(struct irqaction *irq)  #define USECS_PER_JIFFY (1000000/HZ) -unsigned long jmr3927_do_gettimeoffset(void) -{ -       unsigned long count; -       unsigned long res = 0; - -       /* MUST read TRR before TISR. */ -       count = jmr3927_tmrptr->trr; - -       if (jmr3927_tmrptr->tisr & TXx927_TMTISR_TIIS) { -               /* timer interrupt is pending.  use Max value. */ -               res = USECS_PER_JIFFY - 1; -       } else { -               /* convert to usec */ -               /* res = count / (JMR3927_TIMER_CLK / 1000000); */ -               res = (count << 7) / ((JMR3927_TIMER_CLK << 7) / 1000000); - -               /* -                * Due to possible jiffies inconsistencies, we need to check -                * the result so that we'll get a timer that is monotonic. -                */ -               if (res >= USECS_PER_JIFFY) -                       res = USECS_PER_JIFFY-1; -       } - -       return res; -} - -  //#undef DO_WRITE_THROUGH  #define DO_WRITE_THROUGH  #define DO_ENABLE_CACHE diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index debe86c2f691..e535f86efa2f 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -11,6 +11,7 @@   * Free Software Foundation;  either version 2 of the  License, or (at your   * option) any later version.   */ +#include <linux/clocksource.h>  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/init.h> @@ -67,15 +68,9 @@ int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;  int (*rtc_mips_set_mmss)(unsigned long); -/* usecs per counter cycle, shifted to left by 32 bits */ -static unsigned int sll32_usecs_per_cycle; -  /* how many counter cycles in a jiffy */  static unsigned long cycles_per_jiffy __read_mostly; -/* Cycle counter value at the previous timer interrupt.. */ -static unsigned int timerhi, timerlo; -  /* expirelo is the count value for next CPU timer interrupt */  static unsigned int expirelo; @@ -93,7 +88,7 @@ static unsigned int null_hpt_read(void)  	return 0;  } -static void null_hpt_init(unsigned int count) +static void __init null_hpt_init(void)  {  	/* nothing */  } @@ -128,186 +123,18 @@ static unsigned int c0_hpt_read(void)  	return read_c0_count();  } -/* For use solely as a high precision timer.  */ -static void c0_hpt_init(unsigned int count) -{ -	write_c0_count(read_c0_count() - count); -} -  /* For use both as a high precision timer and an interrupt source.  */ -static void c0_hpt_timer_init(unsigned int count) +static void __init c0_hpt_timer_init(void)  { -	count = read_c0_count() - count; -	expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy; -	write_c0_count(expirelo - cycles_per_jiffy); +	expirelo = read_c0_count() + cycles_per_jiffy;  	write_c0_compare(expirelo); -	write_c0_count(count);  }  int (*mips_timer_state)(void);  void (*mips_timer_ack)(void);  unsigned int (*mips_hpt_read)(void); -void (*mips_hpt_init)(unsigned int); - -/* - * Gettimeoffset routines.  These routines returns the time duration - * since last timer interrupt in usecs. - * - * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset. - * Otherwise use calibrate_gettimeoffset() - * - * If the CPU does not have the counter register, you can either supply - * your own gettimeoffset() routine, or use null_gettimeoffset(), which - * gives the same resolution as HZ. - */ - -static unsigned long null_gettimeoffset(void) -{ -	return 0; -} - - -/* The function pointer to one of the gettimeoffset funcs.  */ -unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset; - - -static unsigned long fixed_rate_gettimeoffset(void) -{ -	u32 count; -	unsigned long res; - -	/* Get last timer tick in absolute kernel time */ -	count = mips_hpt_read(); - -	/* .. relative to previous jiffy (32 bits is enough) */ -	count -= timerlo; - -	__asm__("multu	%1,%2" -		: "=h" (res) -		: "r" (count), "r" (sll32_usecs_per_cycle) -		: "lo", GCC_REG_ACCUM); - -	/* -	 * Due to possible jiffies inconsistencies, we need to check -	 * the result so that we'll get a timer that is monotonic. -	 */ -	if (res >= USECS_PER_JIFFY) -		res = USECS_PER_JIFFY - 1; - -	return res; -} - - -/* - * Cached "1/(clocks per usec) * 2^32" value. - * It has to be recalculated once each jiffy. - */ -static unsigned long cached_quotient; - -/* Last jiffy when calibrate_divXX_gettimeoffset() was called. */ -static unsigned long last_jiffies; - -/* - * This is moved from dec/time.c:do_ioasic_gettimeoffset() by Maciej. - */ -static unsigned long calibrate_div32_gettimeoffset(void) -{ -	u32 count; -	unsigned long res, tmp; -	unsigned long quotient; - -	tmp = jiffies; - -	quotient = cached_quotient; - -	if (last_jiffies != tmp) { -		last_jiffies = tmp; -		if (last_jiffies != 0) { -			unsigned long r0; -			do_div64_32(r0, timerhi, timerlo, tmp); -			do_div64_32(quotient, USECS_PER_JIFFY, -				    USECS_PER_JIFFY_FRAC, r0); -			cached_quotient = quotient; -		} -	} - -	/* Get last timer tick in absolute kernel time */ -	count = mips_hpt_read(); - -	/* .. relative to previous jiffy (32 bits is enough) */ -	count -= timerlo; - -	__asm__("multu  %1,%2" -		: "=h" (res) -		: "r" (count), "r" (quotient) -		: "lo", GCC_REG_ACCUM); - -	/* -	 * Due to possible jiffies inconsistencies, we need to check -	 * the result so that we'll get a timer that is monotonic. -	 */ -	if (res >= USECS_PER_JIFFY) -		res = USECS_PER_JIFFY - 1; - -	return res; -} - -static unsigned long calibrate_div64_gettimeoffset(void) -{ -	u32 count; -	unsigned long res, tmp; -	unsigned long quotient; - -	tmp = jiffies; - -	quotient = cached_quotient; - -	if (last_jiffies != tmp) { -		last_jiffies = tmp; -		if (last_jiffies) { -			unsigned long r0; -			__asm__(".set	push\n\t" -				".set	mips3\n\t" -				"lwu	%0,%3\n\t" -				"dsll32	%1,%2,0\n\t" -				"or	%1,%1,%0\n\t" -				"ddivu	$0,%1,%4\n\t" -				"mflo	%1\n\t" -				"dsll32	%0,%5,0\n\t" -				"or	%0,%0,%6\n\t" -				"ddivu	$0,%0,%1\n\t" -				"mflo	%0\n\t" -				".set	pop" -				: "=&r" (quotient), "=&r" (r0) -				: "r" (timerhi), "m" (timerlo), -				  "r" (tmp), "r" (USECS_PER_JIFFY), -				  "r" (USECS_PER_JIFFY_FRAC) -				: "hi", "lo", GCC_REG_ACCUM); -			cached_quotient = quotient; -		} -	} - -	/* Get last timer tick in absolute kernel time */ -	count = mips_hpt_read(); - -	/* .. relative to previous jiffy (32 bits is enough) */ -	count -= timerlo; - -	__asm__("multu	%1,%2" -		: "=h" (res) -		: "r" (count), "r" (quotient) -		: "lo", GCC_REG_ACCUM); - -	/* -	 * Due to possible jiffies inconsistencies, we need to check -	 * the result so that we'll get a timer that is monotonic. -	 */ -	if (res >= USECS_PER_JIFFY) -		res = USECS_PER_JIFFY - 1; - -	return res; -} - +void (*mips_hpt_init)(void) __initdata = null_hpt_init; +unsigned int mips_hpt_mask = 0xffffffff;  /* last time when xtime and rtc are sync'ed up */  static long last_rtc_update; @@ -334,18 +161,10 @@ void local_timer_interrupt(int irq, void *dev_id)   */  irqreturn_t timer_interrupt(int irq, void *dev_id)  { -	unsigned long j; -	unsigned int count; -  	write_seqlock(&xtime_lock); -	count = mips_hpt_read();  	mips_timer_ack(); -	/* Update timerhi/timerlo for intra-jiffy calibration. */ -	timerhi += count < timerlo;			/* Wrap around */ -	timerlo = count; -  	/*  	 * call the generic timer interrupt handling  	 */ @@ -368,47 +187,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)  		}  	} -	/* -	 * If jiffies has overflown in this timer_interrupt, we must -	 * update the timer[hi]/[lo] to make fast gettimeoffset funcs -	 * quotient calc still valid. -arca -	 * -	 * The first timer interrupt comes late as interrupts are -	 * enabled long after timers are initialized.  Therefore the -	 * high precision timer is fast, leading to wrong gettimeoffset() -	 * calculations.  We deal with it by setting it based on the -	 * number of its ticks between the second and the third interrupt. -	 * That is still somewhat imprecise, but it's a good estimate. -	 * --macro -	 */ -	j = jiffies; -	if (j < 4) { -		static unsigned int prev_count; -		static int hpt_initialized; - -		switch (j) { -		case 0: -			timerhi = timerlo = 0; -			mips_hpt_init(count); -			break; -		case 2: -			prev_count = count; -			break; -		case 3: -			if (!hpt_initialized) { -				unsigned int c3 = 3 * (count - prev_count); - -				timerhi = 0; -				timerlo = c3; -				mips_hpt_init(count - c3); -				hpt_initialized = 1; -			} -			break; -		default: -			break; -		} -	} -  	write_sequnlock(&xtime_lock);  	/* @@ -476,12 +254,11 @@ asmlinkage void ll_local_timer_interrupt(int irq)   * 1) board_time_init() -   * 	a) (optional) set up RTC routines,   *      b) (optional) calibrate and set the mips_hpt_frequency - *	    (only needed if you intended to use fixed_rate_gettimeoffset - *	     or use cpu counter as timer interrupt source) + *	    (only needed if you intended to use cpu counter as timer interrupt + *	     source)   * 2) setup xtime based on rtc_mips_get_time(). - * 3) choose a appropriate gettimeoffset routine. - * 4) calculate a couple of cached variables for later usage - * 5) plat_timer_setup() - + * 3) calculate a couple of cached variables for later usage + * 4) plat_timer_setup() -   *	a) (optional) over-write any choices made above by time_init().   *	b) machine specific code should setup the timer irqaction.   *	c) enable the timer interrupt @@ -533,13 +310,48 @@ static unsigned int __init calibrate_hpt(void)  	} while (--i);  	hpt_end = mips_hpt_read(); -	hpt_count = hpt_end - hpt_start; +	hpt_count = (hpt_end - hpt_start) & mips_hpt_mask;  	hz = HZ;  	frequency = (u64)hpt_count * (u64)hz;  	return frequency >> log_2_loops;  } +static cycle_t read_mips_hpt(void) +{ +	return (cycle_t)mips_hpt_read(); +} + +static struct clocksource clocksource_mips = { +	.name		= "MIPS", +	.read		= read_mips_hpt, +	.is_continuous	= 1, +}; + +static void __init init_mips_clocksource(void) +{ +	u64 temp; +	u32 shift; + +	if (!mips_hpt_frequency || mips_hpt_read == null_hpt_read) +		return; + +	/* Calclate a somewhat reasonable rating value */ +	clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; +	/* Find a shift value */ +	for (shift = 32; shift > 0; shift--) { +		temp = (u64) NSEC_PER_SEC << shift; +		do_div(temp, mips_hpt_frequency); +		if ((temp >> 32) == 0) +			break; +	} +	clocksource_mips.shift = shift; +	clocksource_mips.mult = (u32)temp; +	clocksource_mips.mask = mips_hpt_mask; + +	clocksource_register(&clocksource_mips); +} +  void __init time_init(void)  {  	if (board_time_init) @@ -555,41 +367,21 @@ void __init time_init(void)  	                        -xtime.tv_sec, -xtime.tv_nsec);  	/* Choose appropriate high precision timer routines.  */ -	if (!cpu_has_counter && !mips_hpt_read) { +	if (!cpu_has_counter && !mips_hpt_read)  		/* No high precision timer -- sorry.  */  		mips_hpt_read = null_hpt_read; -		mips_hpt_init = null_hpt_init; -	} else if (!mips_hpt_frequency && !mips_timer_state) { +	else if (!mips_hpt_frequency && !mips_timer_state) {  		/* A high precision timer of unknown frequency.  */ -		if (!mips_hpt_read) { +		if (!mips_hpt_read)  			/* No external high precision timer -- use R4k.  */  			mips_hpt_read = c0_hpt_read; -			mips_hpt_init = c0_hpt_init; -		} - -		if (cpu_has_mips32r1 || cpu_has_mips32r2 || -		    (current_cpu_data.isa_level == MIPS_CPU_ISA_I) || -		    (current_cpu_data.isa_level == MIPS_CPU_ISA_II)) -			/* -			 * We need to calibrate the counter but we don't have -			 * 64-bit division. -			 */ -			do_gettimeoffset = calibrate_div32_gettimeoffset; -		else -			/* -			 * We need to calibrate the counter but we *do* have -			 * 64-bit division. -			 */ -			do_gettimeoffset = calibrate_div64_gettimeoffset;  	} else {  		/* We know counter frequency.  Or we can get it.  */  		if (!mips_hpt_read) {  			/* No external high precision timer -- use R4k.  */  			mips_hpt_read = c0_hpt_read; -			if (mips_timer_state) -				mips_hpt_init = c0_hpt_init; -			else { +			if (!mips_timer_state) {  				/* No external timer interrupt -- use R4k.  */  				mips_hpt_init = c0_hpt_timer_init;  				mips_timer_ack = c0_timer_ack; @@ -598,16 +390,9 @@ void __init time_init(void)  		if (!mips_hpt_frequency)  			mips_hpt_frequency = calibrate_hpt(); -		do_gettimeoffset = fixed_rate_gettimeoffset; -  		/* Calculate cache parameters.  */  		cycles_per_jiffy = (mips_hpt_frequency + HZ / 2) / HZ; -		/* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq  */ -		do_div64_32(sll32_usecs_per_cycle, -			    1000000, mips_hpt_frequency / 2, -			    mips_hpt_frequency); -  		/* Report the high precision timer rate for a reference.  */  		printk("Using %u.%03u MHz high precision timer.\n",  		       ((mips_hpt_frequency + 500) / 1000) / 1000, @@ -619,7 +404,7 @@ void __init time_init(void)  		mips_timer_ack = null_timer_ack;  	/* This sets up the high precision timer for the first interrupt.  */ -	mips_hpt_init(mips_hpt_read()); +	mips_hpt_init();  	/*  	 * Call board specific timer interrupt setup. @@ -633,6 +418,8 @@ void __init time_init(void)  	 * is not invoked accidentally.  	 */  	plat_timer_setup(&timer_irqaction); + +	init_mips_clocksource();  }  #define FEBRUARY		2 diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/philips/pnx8550/common/time.c index 0af655b1f330..65c440e8480b 100644 --- a/arch/mips/philips/pnx8550/common/time.c +++ b/arch/mips/philips/pnx8550/common/time.c @@ -41,8 +41,8 @@ extern unsigned int mips_hpt_frequency;   * 1) board_time_init() -   * 	a) (optional) set up RTC routines,   *      b) (optional) calibrate and set the mips_hpt_frequency - *	    (only needed if you intended to use fixed_rate_gettimeoffset - *	     or use cpu counter as timer interrupt source) + *	    (only needed if you intended to use cpu counter as timer interrupt + *	     source)   */  void pnx8550_time_init(void) diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c index 65fa3a23ea5e..3cc0436db6cf 100644 --- a/arch/mips/pmc-sierra/yosemite/smp.c +++ b/arch/mips/pmc-sierra/yosemite/smp.c @@ -3,9 +3,7 @@  #include <asm/pmon.h>  #include <asm/titan_dep.h> - -extern unsigned int (*mips_hpt_read)(void); -extern void (*mips_hpt_init)(unsigned int); +#include <asm/time.h>  #define LAUNCHSTACK_SIZE 256 @@ -101,7 +99,7 @@ void prom_cpus_done(void)   */  void prom_init_secondary(void)  { -	mips_hpt_init(mips_hpt_read()); +	mips_hpt_init();  	set_c0_status(ST0_CO | ST0_IE | ST0_IM);  } diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 4e870fc4469b..c965705f3427 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -134,13 +134,6 @@ again:  	irq_exit();  } -unsigned long ip27_do_gettimeoffset(void) -{ -	unsigned long ct_cur1; -	ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY; -	return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000; -} -  /* Includes for ioc3_init().  */  #include <asm/sn/types.h>  #include <asm/sn/sn0/addrs.h> @@ -248,12 +241,17 @@ void __init plat_timer_setup(struct irqaction *irq)  	setup_irq(irqno, &rt_irqaction);  } +static unsigned int ip27_hpt_read(void) +{ +	return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); +} +  void __init ip27_time_init(void)  { +	mips_hpt_read = ip27_hpt_read; +	mips_hpt_frequency = CYCLES_PER_SEC;  	xtime.tv_sec = get_m48t35_time();  	xtime.tv_nsec = 0; - -	do_gettimeoffset = ip27_do_gettimeoffset;  }  void __init cpu_time_init(void) diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index bf12af46132e..e136bde5248e 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -47,6 +47,12 @@  #define IMR_IP3_VAL	K_BCM1480_INT_MAP_I1  #define IMR_IP4_VAL	K_BCM1480_INT_MAP_I2 +#ifdef CONFIG_SIMULATION +#define BCM1480_HPT_VALUE	50000 +#else +#define BCM1480_HPT_VALUE	1000000 +#endif +  extern int bcm1480_steal_irq(int irq);  void bcm1480_time_init(void) @@ -59,11 +65,6 @@ void bcm1480_time_init(void)  		BUG();  	} -	if (!cpu) { -		/* Use our own gettimeoffset() routine */ -		do_gettimeoffset = bcm1480_gettimeoffset; -	} -  	bcm1480_mask_irq(cpu, irq);  	/* Map the timer interrupt to ip[4] of this cpu */ @@ -74,11 +75,7 @@ void bcm1480_time_init(void)  	/* Disable the timer and set up the count */  	__raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));  	__raw_writeq( -#ifndef CONFIG_SIMULATION -		1000000/HZ -#else -		50000/HZ -#endif +		BCM1480_HPT_VALUE/HZ  		, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)));  	/* Set the timer running */ @@ -122,16 +119,16 @@ void bcm1480_timer_interrupt(void)  	}  } -/* - * We use our own do_gettimeoffset() instead of the generic one, - * because the generic one does not work for SMP case. - * In addition, since we use general timer 0 for system time, - * we can get accurate intra-jiffy offset without calibration. - */ -unsigned long bcm1480_gettimeoffset(void) +static unsigned int bcm1480_hpt_read(void)  { +	/* We assume this function is called xtime_lock held. */  	unsigned long count =  		__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); +	return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count; +} -	return 1000000/HZ - count; +void __init bcm1480_hpt_setup(void) +{ +	mips_hpt_read = bcm1480_hpt_read; +	mips_hpt_frequency = BCM1480_HPT_VALUE;  } diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 0ccf1796dd78..bcb74f2c1948 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -47,15 +47,11 @@  #define SB1250_HPT_NUM		3  #define SB1250_HPT_VALUE	M_SCD_TIMER_CNT /* max value */ -#define SB1250_HPT_SHIFT	((sizeof(unsigned int)*8)-V_SCD_TIMER_WIDTH)  extern int sb1250_steal_irq(int irq);  static unsigned int sb1250_hpt_read(void); -static void sb1250_hpt_init(unsigned int); - -static unsigned int hpt_offset;  void __init sb1250_hpt_setup(void)  { @@ -69,13 +65,9 @@ void __init sb1250_hpt_setup(void)  		__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,  			     IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); -		/* -		 * we need to fill 32 bits, so just use the upper 23 bits and pretend -		 * the timer is going 512Mhz instead of 1Mhz -		 */ -		mips_hpt_frequency = V_SCD_TIMER_FREQ << SB1250_HPT_SHIFT; -		mips_hpt_init = sb1250_hpt_init; +		mips_hpt_frequency = V_SCD_TIMER_FREQ;  		mips_hpt_read = sb1250_hpt_read; +		mips_hpt_mask = M_SCD_TIMER_INIT;  	}  } @@ -149,11 +141,7 @@ void sb1250_timer_interrupt(void)  /*   * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over - * again. There's no easy way to set to a specific value so store init value - * in hpt_offset and subtract each time. - * - * Note: Timer isn't full 32bits so shift it into the upper part making - *       it appear to run at a higher frequency. + * again.   */  static unsigned int sb1250_hpt_read(void)  { @@ -161,13 +149,5 @@ static unsigned int sb1250_hpt_read(void)  	count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); -	count = (SB1250_HPT_VALUE - count) << SB1250_HPT_SHIFT; - -	return count - hpt_offset; -} - -static void sb1250_hpt_init(unsigned int count) -{ -	hpt_offset = count; -	return; +	return SB1250_HPT_VALUE - count;  } diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h index 5f7dcf5452e7..d107832de1b6 100644 --- a/include/asm-mips/div64.h +++ b/include/asm-mips/div64.h @@ -83,27 +83,6 @@  #if (_MIPS_SZLONG == 64)  /* - * Don't use this one in new code - */ -#define do_div64_32(res, high, low, base) ({ \ -	unsigned int __quot, __mod; \ -	unsigned long __div; \ -	unsigned int __low, __high, __base; \ -	\ -	__high = (high); \ -	__low = (low); \ -	__div = __high; \ -	__div = __div << 32 | __low; \ -	__base = (base); \ -	\ -	__mod = __div % __base; \ -	__div = __div / __base; \ -	\ -	__quot = __div; \ -	(res) = __quot; \ -	__mod; }) - -/*   * Hey, we're already 64-bit, no   * need to play games..   */ diff --git a/include/asm-mips/sibyte/sb1250.h b/include/asm-mips/sibyte/sb1250.h index b09e16c93ca0..2ba6988ddc8e 100644 --- a/include/asm-mips/sibyte/sb1250.h +++ b/include/asm-mips/sibyte/sb1250.h @@ -51,8 +51,8 @@ extern void sb1250_mask_irq(int cpu, int irq);  extern void sb1250_unmask_irq(int cpu, int irq);  extern void sb1250_smp_finish(void); +extern void bcm1480_hpt_setup(void);  extern void bcm1480_time_init(void); -extern unsigned long bcm1480_gettimeoffset(void);  extern void bcm1480_mask_irq(int cpu, int irq);  extern void bcm1480_unmask_irq(int cpu, int irq);  extern void bcm1480_smp_finish(void); diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 28512ba2266e..625acd337bc3 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -48,7 +48,8 @@ extern void (*mips_timer_ack)(void);   * If mips_hpt_read is NULL, an R4k-compatible timer setup is attempted.   */  extern unsigned int (*mips_hpt_read)(void); -extern void (*mips_hpt_init)(unsigned int); +extern void (*mips_hpt_init)(void); +extern unsigned int mips_hpt_mask;  /*   * to_tm() converts system time back to (year, mon, day, hour, min, sec). @@ -58,13 +59,6 @@ extern void (*mips_hpt_init)(unsigned int);  extern void to_tm(unsigned long tim, struct rtc_time *tm);  /* - * do_gettimeoffset(). By default, this func pointer points to - * do_null_gettimeoffset(), which leads to the same resolution as HZ. - * Higher resolution versions are available, which give ~1us resolution. - */ -extern unsigned long (*do_gettimeoffset)(void); - -/*   * high-level timer interrupt routines.   */  extern irqreturn_t timer_interrupt(int irq, void *dev_id);  | 

