2006-01-18 17:42:42 -08:00
/*
2015-11-02 16:16:37 +00:00
* Copyright ( C ) 2015 Anton Ivanov ( aivanov @ { brocade . com , kot - begemot . co . uk } )
* Copyright ( C ) 2015 Thomas Meyer ( thomas @ m3y3r . de )
* Copyright ( C ) 2012 - 2014 Cisco Systems
2007-10-16 01:27:00 -07:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-16 15:20:36 -07:00
* Licensed under the GPL
*/
2008-02-04 22:31:14 -08:00
# include <linux/clockchips.h>
2008-04-29 00:59:18 -07:00
# include <linux/init.h>
2008-02-04 22:31:14 -08:00
# include <linux/interrupt.h>
# include <linux/jiffies.h>
2015-11-02 16:16:37 +00:00
# include <linux/mm.h>
# include <linux/sched.h>
# include <linux/spinlock.h>
2008-02-04 22:31:14 -08:00
# include <linux/threads.h>
# include <asm/irq.h>
# include <asm/param.h>
2012-10-08 03:27:32 +01:00
# include <kern_util.h>
# include <os.h>
2015-11-02 16:16:37 +00:00
# include <timer-internal.h>
2005-04-16 15:20:36 -07:00
2012-08-02 00:49:17 +02:00
void timer_handler ( int sig , struct siginfo * unused_si , struct uml_pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2007-10-16 01:27:24 -07:00
unsigned long flags ;
local_irq_save ( flags ) ;
2007-10-16 01:27:25 -07:00
do_IRQ ( TIMER_IRQ , regs ) ;
2007-10-16 01:27:24 -07:00
local_irq_restore ( flags ) ;
2005-04-16 15:20:36 -07:00
}
2015-07-16 16:56:31 +05:30
static int itimer_shutdown ( struct clock_event_device * evt )
2006-01-18 17:42:42 -08:00
{
2015-11-02 16:16:37 +00:00
os_timer_disable ( ) ;
2015-07-16 16:56:31 +05:30
return 0 ;
}
2007-10-16 01:27:24 -07:00
2015-07-16 16:56:31 +05:30
static int itimer_set_periodic ( struct clock_event_device * evt )
{
2015-11-02 16:16:37 +00:00
os_timer_set_interval ( NULL , NULL ) ;
2015-07-16 16:56:31 +05:30
return 0 ;
2006-01-18 17:42:42 -08:00
}
2007-10-16 01:27:25 -07:00
static int itimer_next_event ( unsigned long delta ,
struct clock_event_device * evt )
{
2015-11-02 16:16:37 +00:00
return os_timer_one_shot ( delta ) ;
2007-10-16 01:27:25 -07:00
}
2015-11-02 16:16:37 +00:00
static int itimer_one_shot ( struct clock_event_device * evt )
{
os_timer_one_shot ( 1 ) ;
return 0 ;
}
static struct clock_event_device timer_clockevent = {
. name = " posix-timer " ,
2015-07-16 16:56:31 +05:30
. rating = 250 ,
. cpumask = cpu_all_mask ,
. features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT ,
. set_state_shutdown = itimer_shutdown ,
. set_state_periodic = itimer_set_periodic ,
2015-11-02 16:16:37 +00:00
. set_state_oneshot = itimer_one_shot ,
2015-07-16 16:56:31 +05:30
. set_next_event = itimer_next_event ,
2015-11-02 16:16:37 +00:00
. shift = 0 ,
. max_delta_ns = 0xffffffff ,
. min_delta_ns = TIMER_MIN_DELTA , //microsecond resolution should be enough for anyone, same as 640K RAM
2015-07-16 16:56:31 +05:30
. irq = 0 ,
2015-11-02 16:16:37 +00:00
. mult = 1 ,
2007-10-16 01:27:24 -07:00
} ;
static irqreturn_t um_timer ( int irq , void * dev )
2005-04-16 15:20:36 -07:00
{
2015-11-02 16:16:37 +00:00
if ( get_current ( ) - > mm ! = NULL )
{
/* userspace - relay signal, results in correct userspace timers */
os_alarm_process ( get_current ( ) - > mm - > context . id . u . pid ) ;
}
( * timer_clockevent . event_handler ) ( & timer_clockevent ) ;
2006-01-18 17:42:42 -08:00
2006-06-30 01:55:56 -07:00
return IRQ_HANDLED ;
2005-04-16 15:20:36 -07:00
}
2015-11-02 16:16:37 +00:00
static cycle_t timer_read ( struct clocksource * cs )
2007-10-16 01:27:25 -07:00
{
2015-11-02 16:16:37 +00:00
return os_nsecs ( ) / TIMER_MULTIPLIER ;
2007-10-16 01:27:25 -07:00
}
2015-11-02 16:16:37 +00:00
static struct clocksource timer_clocksource = {
. name = " timer " ,
2007-10-16 01:27:25 -07:00
. rating = 300 ,
2015-11-02 16:16:37 +00:00
. read = timer_read ,
2007-10-16 01:27:25 -07:00
. mask = CLOCKSOURCE_MASK ( 64 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2015-11-02 16:16:37 +00:00
static void __init timer_setup ( void )
2006-07-10 04:45:05 -07:00
{
int err ;
2015-11-02 16:16:37 +00:00
err = request_irq ( TIMER_IRQ , um_timer , IRQF_TIMER , " hr timer " , NULL ) ;
2007-10-16 01:27:00 -07:00
if ( err ! = 0 )
2006-09-25 23:33:05 -07:00
printk ( KERN_ERR " register_timer : request_irq failed - "
2006-07-10 04:45:05 -07:00
" errno = %d \n " , - err ) ;
2015-11-02 16:16:37 +00:00
err = os_timer_create ( NULL ) ;
if ( err ! = 0 ) {
printk ( KERN_ERR " creation of timer failed - errno = %d \n " , - err ) ;
return ;
}
err = clocksource_register_hz ( & timer_clocksource , NSEC_PER_SEC / TIMER_MULTIPLIER ) ;
2007-10-16 01:27:25 -07:00
if ( err ) {
2010-04-26 20:25:16 -07:00
printk ( KERN_ERR " clocksource_register_hz returned %d \n " , err ) ;
2007-10-16 01:27:25 -07:00
return ;
}
2015-11-02 16:16:37 +00:00
clockevents_register_device ( & timer_clockevent ) ;
2006-07-10 04:45:05 -07:00
}
2010-07-13 17:56:24 -07:00
void read_persistent_clock ( struct timespec * ts )
{
2015-11-02 16:16:37 +00:00
long long nsecs = os_persistent_clock_emulation ( ) ;
2010-08-03 20:34:48 +02:00
2010-07-13 17:56:24 -07:00
set_normalized_timespec ( ts , nsecs / NSEC_PER_SEC ,
nsecs % NSEC_PER_SEC ) ;
}
2007-10-16 01:27:24 -07:00
void __init time_init ( void )
2006-07-10 04:45:05 -07:00
{
2015-11-02 16:16:37 +00:00
timer_set_signal_handler ( ) ;
late_time_init = timer_setup ;
2005-04-16 15:20:36 -07:00
}