2010-05-28 23:09:12 -04:00
/*
* Copyright 2010 Tilera Corporation . All Rights Reserved .
*
* 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 , version 2.
*
* 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 , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
*
* Support the cycle counter clocksource and tile timer clock event device .
*/
# include <linux/time.h>
# include <linux/timex.h>
# include <linux/clocksource.h>
# include <linux/clockchips.h>
# include <linux/hardirq.h>
# include <linux/sched.h>
# include <linux/smp.h>
# include <linux/delay.h>
arch/tile: various header improvements for building drivers
This change adds a number of missing headers in asm (fb.h, parport.h,
serial.h, and vga.h) using the minimal generic versions.
It also adds a number of missing interfaces that showed up as build
failures when trying to build various drivers not normally included in the
"tile" distribution: ioremap_wc(), memset_io(), io{read,write}{16,32}be(),
virt_to_bus(), bus_to_virt(), irq_canonicalize(), __pte(), __pgd(),
and __pmd(). I also added a cast in virt_to_page() since not all callers
pass a pointer.
I fixed <asm/stat.h> to properly include a __KERNEL__ guard for the
__ARCH_WANT_STAT64 symbol, and <asm/swab.h> to use __builtin_bswap32()
even for our 64-bit architecture, since the same code is produced.
I added an export for get_cycles(), since it's used in some modules.
And I made <arch/spr_def.h> properly include the __KERNEL__ guard,
even though it's not yet exported, since it likely will be soon.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
2011-05-02 16:06:42 -04:00
# include <linux/module.h>
2010-05-28 23:09:12 -04:00
# include <asm/irq_regs.h>
2010-06-25 17:04:17 -04:00
# include <asm/traps.h>
2010-05-28 23:09:12 -04:00
# include <hv/hypervisor.h>
# include <arch/interrupts.h>
# include <arch/spr_def.h>
/*
* Define the cycle counter clock source .
*/
/* How many cycles per second we are running at. */
static cycles_t cycles_per_sec __write_once ;
2010-06-25 17:04:17 -04:00
cycles_t get_clock_rate ( void )
2010-05-28 23:09:12 -04:00
{
return cycles_per_sec ;
}
# if CHIP_HAS_SPLIT_CYCLE()
2010-06-25 17:04:17 -04:00
cycles_t get_cycles ( void )
2010-05-28 23:09:12 -04:00
{
unsigned int high = __insn_mfspr ( SPR_CYCLE_HIGH ) ;
unsigned int low = __insn_mfspr ( SPR_CYCLE_LOW ) ;
unsigned int high2 = __insn_mfspr ( SPR_CYCLE_HIGH ) ;
while ( unlikely ( high ! = high2 ) ) {
low = __insn_mfspr ( SPR_CYCLE_LOW ) ;
high = high2 ;
high2 = __insn_mfspr ( SPR_CYCLE_HIGH ) ;
}
return ( ( ( cycles_t ) high ) < < 32 ) | low ;
}
arch/tile: various header improvements for building drivers
This change adds a number of missing headers in asm (fb.h, parport.h,
serial.h, and vga.h) using the minimal generic versions.
It also adds a number of missing interfaces that showed up as build
failures when trying to build various drivers not normally included in the
"tile" distribution: ioremap_wc(), memset_io(), io{read,write}{16,32}be(),
virt_to_bus(), bus_to_virt(), irq_canonicalize(), __pte(), __pgd(),
and __pmd(). I also added a cast in virt_to_page() since not all callers
pass a pointer.
I fixed <asm/stat.h> to properly include a __KERNEL__ guard for the
__ARCH_WANT_STAT64 symbol, and <asm/swab.h> to use __builtin_bswap32()
even for our 64-bit architecture, since the same code is produced.
I added an export for get_cycles(), since it's used in some modules.
And I made <arch/spr_def.h> properly include the __KERNEL__ guard,
even though it's not yet exported, since it likely will be soon.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
2011-05-02 16:06:42 -04:00
EXPORT_SYMBOL ( get_cycles ) ;
2010-05-28 23:09:12 -04:00
# endif
2010-08-13 08:24:22 -04:00
/*
* We use a relatively small shift value so that sched_clock ( )
* won ' t wrap around very often .
*/
# define SCHED_CLOCK_SHIFT 10
static unsigned long sched_clock_mult __write_once ;
2010-06-25 17:04:17 -04:00
static cycles_t clocksource_get_cycles ( struct clocksource * cs )
2010-05-28 23:09:12 -04:00
{
return get_cycles ( ) ;
}
static struct clocksource cycle_counter_cs = {
. name = " cycle counter " ,
. rating = 300 ,
. read = clocksource_get_cycles ,
. mask = CLOCKSOURCE_MASK ( 64 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
/*
* Called very early from setup_arch ( ) to set cycles_per_sec .
* We initialize it early so we can use it to set up loops_per_jiffy .
*/
void __init setup_clock ( void )
{
cycles_per_sec = hv_sysconf ( HV_SYSCONF_CPU_SPEED ) ;
2010-08-13 08:24:22 -04:00
sched_clock_mult =
clocksource_hz2mult ( cycles_per_sec , SCHED_CLOCK_SHIFT ) ;
2010-05-28 23:09:12 -04:00
}
void __init calibrate_delay ( void )
{
loops_per_jiffy = get_clock_rate ( ) / HZ ;
pr_info ( " Clock rate yields %lu.%02lu BogoMIPS (lpj=%lu) \n " ,
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 , loops_per_jiffy ) ;
}
/* Called fairly late in init/main.c, but before we go smp. */
void __init time_init ( void )
{
/* Initialize and register the clock source. */
2011-06-01 00:32:50 -07:00
clocksource_register_hz ( & cycle_counter_cs , cycles_per_sec ) ;
2010-05-28 23:09:12 -04:00
/* Start up the tile-timer interrupt source on the boot cpu. */
setup_tile_timer ( ) ;
}
/*
* Define the tile timer clock event device . The timer is driven by
* the TILE_TIMER_CONTROL register , which consists of a 31 - bit down
* counter , plus bit 31 , which signifies that the counter has wrapped
* from zero to ( 2 * * 31 ) - 1. The INT_TILE_TIMER interrupt will be
* raised as long as bit 31 is set .
2010-08-13 08:24:22 -04:00
*
* The TILE_MINSEC value represents the largest range of real - time
* we can possibly cover with the timer , based on MAX_TICK combined
* with the slowest reasonable clock rate we might run at .
2010-05-28 23:09:12 -04:00
*/
# define MAX_TICK 0x7fffffff /* we have 31 bits of countdown timer */
2010-08-13 08:24:22 -04:00
# define TILE_MINSEC 5 /* timer covers no more than 5 seconds */
2010-05-28 23:09:12 -04:00
static int tile_timer_set_next_event ( unsigned long ticks ,
struct clock_event_device * evt )
{
BUG_ON ( ticks > MAX_TICK ) ;
__insn_mtspr ( SPR_TILE_TIMER_CONTROL , ticks ) ;
2010-11-01 15:24:29 -04:00
arch_local_irq_unmask_now ( INT_TILE_TIMER ) ;
2010-05-28 23:09:12 -04:00
return 0 ;
}
/*
* Whenever anyone tries to change modes , we just mask interrupts
* and wait for the next event to get set .
*/
static void tile_timer_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * evt )
{
2010-11-01 15:24:29 -04:00
arch_local_irq_mask_now ( INT_TILE_TIMER ) ;
2010-05-28 23:09:12 -04:00
}
/*
* Set min_delta_ns to 1 microsecond , since it takes about
* that long to fire the interrupt .
*/
static DEFINE_PER_CPU ( struct clock_event_device , tile_timer ) = {
. name = " tile timer " ,
. features = CLOCK_EVT_FEAT_ONESHOT ,
. min_delta_ns = 1000 ,
. rating = 100 ,
. irq = - 1 ,
. set_next_event = tile_timer_set_next_event ,
. set_mode = tile_timer_set_mode ,
} ;
void __cpuinit setup_tile_timer ( void )
{
struct clock_event_device * evt = & __get_cpu_var ( tile_timer ) ;
/* Fill in fields that are speed-specific. */
clockevents_calc_mult_shift ( evt , cycles_per_sec , TILE_MINSEC ) ;
evt - > max_delta_ns = clockevent_delta2ns ( MAX_TICK , evt ) ;
/* Mark as being for this cpu only. */
evt - > cpumask = cpumask_of ( smp_processor_id ( ) ) ;
/* Start out with timer not firing. */
2010-11-01 15:24:29 -04:00
arch_local_irq_mask_now ( INT_TILE_TIMER ) ;
2010-05-28 23:09:12 -04:00
/* Register tile timer. */
clockevents_register_device ( evt ) ;
}
/* Called from the interrupt vector. */
void do_timer_interrupt ( struct pt_regs * regs , int fault_num )
{
struct pt_regs * old_regs = set_irq_regs ( regs ) ;
struct clock_event_device * evt = & __get_cpu_var ( tile_timer ) ;
/*
* Mask the timer interrupt here , since we are a oneshot timer
* and there are now by definition no events pending .
*/
2010-11-01 15:24:29 -04:00
arch_local_irq_mask ( INT_TILE_TIMER ) ;
2010-05-28 23:09:12 -04:00
/* Track time spent here in an interrupt context */
irq_enter ( ) ;
/* Track interrupt count. */
__get_cpu_var ( irq_stat ) . irq_timer_count + + ;
/* Call the generic timer handler */
evt - > event_handler ( evt ) ;
/*
* Track time spent against the current process again and
* process any softirqs if they are waiting .
*/
irq_exit ( ) ;
set_irq_regs ( old_regs ) ;
}
/*
* Scheduler clock - returns current time in nanosec units .
* Note that with LOCKDEP , this is called during lockdep_init ( ) , and
* we will claim that sched_clock ( ) is zero for a little while , until
* we run setup_clock ( ) , above .
*/
unsigned long long sched_clock ( void )
{
return clocksource_cyc2ns ( get_cycles ( ) ,
2010-08-13 08:24:22 -04:00
sched_clock_mult , SCHED_CLOCK_SHIFT ) ;
2010-05-28 23:09:12 -04:00
}
int setup_profiling_timer ( unsigned int multiplier )
{
return - EINVAL ;
}
2011-02-28 13:21:52 -05:00
/*
* Use the tile timer to convert nsecs to core clock cycles , relying
* on it having the same frequency as SPR_CYCLE .
*/
cycles_t ns2cycles ( unsigned long nsecs )
{
struct clock_event_device * dev = & __get_cpu_var ( tile_timer ) ;
return ( ( u64 ) nsecs * dev - > mult ) > > dev - > shift ;
}