2012-12-07 07:51:04 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2012 MIPS Technologies , Inc . All rights reserved .
*/
2015-02-24 05:28:34 +03:00
# include <linux/clk.h>
2014-10-20 23:03:59 +04:00
# include <linux/clockchips.h>
2014-10-20 23:04:04 +04:00
# include <linux/cpu.h>
2012-12-07 07:51:04 +04:00
# include <linux/init.h>
2014-10-20 23:03:59 +04:00
# include <linux/interrupt.h>
2014-10-20 23:03:53 +04:00
# include <linux/irqchip/mips-gic.h>
2014-10-20 23:04:04 +04:00
# include <linux/notifier.h>
2014-11-12 22:43:39 +03:00
# include <linux/of_irq.h>
2014-10-20 23:03:59 +04:00
# include <linux/percpu.h>
# include <linux/smp.h>
2013-04-11 01:28:36 +04:00
# include <linux/time.h>
2012-12-07 07:51:04 +04:00
2014-10-20 23:04:00 +04:00
static DEFINE_PER_CPU ( struct clock_event_device , gic_clockevent_device ) ;
2014-10-20 23:04:04 +04:00
static int gic_timer_irq ;
2014-10-20 23:04:01 +04:00
static unsigned int gic_frequency ;
2014-10-20 23:03:59 +04:00
static int gic_next_event ( unsigned long delta , struct clock_event_device * evt )
{
u64 cnt ;
int res ;
cnt = gic_read_count ( ) ;
cnt + = ( u64 ) delta ;
gic_write_cpu_compare ( cnt , cpumask_first ( evt - > cpumask ) ) ;
res = ( ( int ) ( gic_read_count ( ) - cnt ) > = 0 ) ? - ETIME : 0 ;
return res ;
}
2014-10-20 23:04:00 +04:00
static irqreturn_t gic_compare_interrupt ( int irq , void * dev_id )
2014-10-20 23:03:59 +04:00
{
2014-10-20 23:04:03 +04:00
struct clock_event_device * cd = dev_id ;
2014-10-20 23:03:59 +04:00
gic_write_compare ( gic_read_compare ( ) ) ;
cd - > event_handler ( cd ) ;
return IRQ_HANDLED ;
}
struct irqaction gic_compare_irqaction = {
. handler = gic_compare_interrupt ,
2014-10-20 23:04:03 +04:00
. percpu_dev_id = & gic_clockevent_device ,
2014-10-20 23:03:59 +04:00
. flags = IRQF_PERCPU | IRQF_TIMER ,
. name = " timer " ,
} ;
2016-07-13 20:16:44 +03:00
static void gic_clockevent_cpu_init ( unsigned int cpu ,
struct clock_event_device * cd )
2014-10-20 23:03:59 +04:00
{
cd - > name = " MIPS GIC " ;
cd - > features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP ;
2014-10-20 23:04:06 +04:00
cd - > rating = 350 ;
2014-10-20 23:04:04 +04:00
cd - > irq = gic_timer_irq ;
2014-10-20 23:03:59 +04:00
cd - > cpumask = cpumask_of ( cpu ) ;
cd - > set_next_event = gic_next_event ;
2014-10-20 23:04:05 +04:00
clockevents_config_and_register ( cd , gic_frequency , 0x300 , 0x7fffffff ) ;
2014-10-20 23:03:59 +04:00
2014-10-20 23:04:04 +04:00
enable_percpu_irq ( gic_timer_irq , IRQ_TYPE_NONE ) ;
}
static void gic_clockevent_cpu_exit ( struct clock_event_device * cd )
{
disable_percpu_irq ( gic_timer_irq ) ;
}
2015-07-27 17:00:15 +03:00
static void gic_update_frequency ( void * data )
{
unsigned long rate = ( unsigned long ) data ;
clockevents_update_freq ( this_cpu_ptr ( & gic_clockevent_device ) , rate ) ;
}
2016-07-13 20:16:44 +03:00
static int gic_starting_cpu ( unsigned int cpu )
2014-10-20 23:04:04 +04:00
{
2016-07-13 20:16:44 +03:00
gic_clockevent_cpu_init ( cpu , this_cpu_ptr ( & gic_clockevent_device ) ) ;
return 0 ;
2014-10-20 23:04:04 +04:00
}
2015-07-27 17:00:15 +03:00
static int gic_clk_notifier ( struct notifier_block * nb , unsigned long action ,
void * data )
{
struct clk_notifier_data * cnd = data ;
if ( action = = POST_RATE_CHANGE )
on_each_cpu ( gic_update_frequency , ( void * ) cnd - > new_rate , 1 ) ;
return NOTIFY_OK ;
}
2016-07-13 20:16:44 +03:00
static int gic_dying_cpu ( unsigned int cpu )
{
gic_clockevent_cpu_exit ( this_cpu_ptr ( & gic_clockevent_device ) ) ;
return 0 ;
}
2014-10-20 23:04:04 +04:00
2015-07-27 17:00:15 +03:00
static struct notifier_block gic_clk_nb = {
. notifier_call = gic_clk_notifier ,
} ;
2014-10-20 23:04:04 +04:00
static int gic_clockevent_init ( void )
{
2015-07-27 17:00:13 +03:00
int ret ;
2016-09-13 19:56:44 +03:00
if ( ! gic_frequency )
2014-10-20 23:04:04 +04:00
return - ENXIO ;
2015-07-27 17:00:13 +03:00
ret = setup_percpu_irq ( gic_timer_irq , & gic_compare_irqaction ) ;
2016-09-13 19:56:43 +03:00
if ( ret < 0 ) {
pr_err ( " GIC timer IRQ %d setup failed: %d \n " ,
gic_timer_irq , ret ) ;
2015-07-27 17:00:13 +03:00
return ret ;
2016-09-13 19:56:43 +03:00
}
2014-10-20 23:04:04 +04:00
2016-07-13 20:16:44 +03:00
cpuhp_setup_state ( CPUHP_AP_MIPS_GIC_TIMER_STARTING ,
" AP_MIPS_GIC_TIMER_STARTING " , gic_starting_cpu ,
gic_dying_cpu ) ;
2014-10-20 23:03:59 +04:00
return 0 ;
}
2012-12-07 07:51:04 +04:00
static cycle_t gic_hpt_read ( struct clocksource * cs )
{
2013-04-11 01:28:36 +04:00
return gic_read_count ( ) ;
2012-12-07 07:51:04 +04:00
}
static struct clocksource gic_clocksource = {
MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime()
Add user-mode implementations of gettimeofday() and clock_gettime() to
the VDSO. This is currently usable with 2 clocksources: the CP0 count
register, which is accessible to user-mode via RDHWR on R2 and later
cores, or the MIPS Global Interrupt Controller (GIC) timer, which
provides a "user-mode visible" section containing a mirror of its
counter registers. This section must be mapped into user memory, which
is done below the VDSO data page.
When a supported clocksource is not in use, the VDSO functions will
return -ENOSYS, which causes libc to fall back on the standard syscall
path.
When support for neither of these clocksources is compiled into the
kernel at all, the VDSO still provides clock_gettime(), as the coarse
realtime/monotonic clocks can still be implemented. However,
gettimeofday() is not provided in this case as nothing can be done
without a suitable clocksource. This causes the symbol lookup to fail
in libc and it will then always use the standard syscall path.
This patch includes a workaround for a bug in QEMU which results in
RDHWR on the CP0 count register always returning a constant (incorrect)
value. A fix for this has been submitted, and the workaround can be
removed after the fix has been in stable releases for a reasonable
amount of time.
A simple performance test which calls gettimeofday() 1000 times in a
loop and calculates the average execution time gives the following
results on a Malta + I6400 (running at 20MHz):
- Syscall: ~31000 ns
- VDSO (GIC): ~15000 ns
- VDSO (CP0): ~9500 ns
[markos.chandras@imgtec.com:
- Minor code re-arrangements in order for mappings to be made
in the order they appear to the process' address space.
- Move do_{monotonic, realtime} outside of the MIPS_CLOCK_VSYSCALL ifdef
- Use gic_get_usm_range so we can do the GIC mapping in the
arch/mips/kernel/vdso instead of the GIC irqchip driver]
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/11338/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-10-21 11:57:44 +03:00
. name = " GIC " ,
. read = gic_hpt_read ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
. archdata = { . vdso_clock_mode = VDSO_CLOCK_GIC } ,
2012-12-07 07:51:04 +04:00
} ;
2016-06-06 18:57:25 +03:00
static int __init __gic_clocksource_init ( void )
2012-12-07 07:51:04 +04:00
{
2015-07-27 17:00:13 +03:00
int ret ;
2012-12-07 07:51:04 +04:00
/* Set clocksource mask. */
2014-10-20 23:03:49 +04:00
gic_clocksource . mask = CLOCKSOURCE_MASK ( gic_get_count_width ( ) ) ;
2012-12-07 07:51:04 +04:00
/* Calculate a somewhat reasonable rating value. */
2014-11-12 22:43:39 +03:00
gic_clocksource . rating = 200 + gic_frequency / 10000000 ;
2012-12-07 07:51:04 +04:00
2015-07-27 17:00:13 +03:00
ret = clocksource_register_hz ( & gic_clocksource , gic_frequency ) ;
if ( ret < 0 )
pr_warn ( " GIC: Unable to register clocksource \n " ) ;
2016-06-06 18:57:25 +03:00
return ret ;
2012-12-07 07:51:04 +04:00
}
2014-11-12 22:43:39 +03:00
void __init gic_clocksource_init ( unsigned int frequency )
{
gic_frequency = frequency ;
gic_timer_irq = MIPS_GIC_IRQ_BASE +
GIC_LOCAL_TO_HWIRQ ( GIC_LOCAL_INT_COMPARE ) ;
__gic_clocksource_init ( ) ;
2015-07-27 17:00:14 +03:00
gic_clockevent_init ( ) ;
/* And finally start the counter */
gic_start_count ( ) ;
2014-11-12 22:43:39 +03:00
}
2016-08-17 13:21:35 +03:00
static int __init gic_clocksource_of_init ( struct device_node * node )
2014-11-12 22:43:39 +03:00
{
2015-02-24 05:28:34 +03:00
struct clk * clk ;
2015-07-27 17:00:15 +03:00
int ret ;
2015-02-24 05:28:34 +03:00
2016-06-06 18:57:25 +03:00
if ( ! gic_present | | ! node - > parent | |
! of_device_is_compatible ( node - > parent , " mti,gic " ) ) {
pr_warn ( " No DT definition for the mips gic driver " ) ;
return - ENXIO ;
}
2014-11-12 22:43:39 +03:00
2015-02-24 05:28:34 +03:00
clk = of_clk_get ( node , 0 ) ;
if ( ! IS_ERR ( clk ) ) {
2015-07-27 17:00:12 +03:00
if ( clk_prepare_enable ( clk ) < 0 ) {
pr_err ( " GIC failed to enable clock \n " ) ;
clk_put ( clk ) ;
2016-06-06 18:57:25 +03:00
return PTR_ERR ( clk ) ;
2015-07-27 17:00:12 +03:00
}
2015-02-24 05:28:34 +03:00
gic_frequency = clk_get_rate ( clk ) ;
} else if ( of_property_read_u32 ( node , " clock-frequency " ,
& gic_frequency ) ) {
2014-11-12 22:43:39 +03:00
pr_err ( " GIC frequency not specified. \n " ) ;
2016-06-06 18:57:25 +03:00
return - EINVAL ; ;
2014-11-12 22:43:39 +03:00
}
gic_timer_irq = irq_of_parse_and_map ( node , 0 ) ;
if ( ! gic_timer_irq ) {
pr_err ( " GIC timer IRQ not specified. \n " ) ;
2016-06-06 18:57:25 +03:00
return - EINVAL ; ;
2014-11-12 22:43:39 +03:00
}
2016-06-06 18:57:25 +03:00
ret = __gic_clocksource_init ( ) ;
if ( ret )
return ret ;
2015-07-27 17:00:15 +03:00
ret = gic_clockevent_init ( ) ;
if ( ! ret & & ! IS_ERR ( clk ) ) {
if ( clk_notifier_register ( clk , & gic_clk_nb ) < 0 )
pr_warn ( " GIC: Unable to register clock notifier \n " ) ;
}
2015-07-27 17:00:14 +03:00
/* And finally start the counter */
gic_start_count ( ) ;
2016-06-06 18:57:25 +03:00
return 0 ;
2014-11-12 22:43:39 +03:00
}
2016-06-07 01:27:44 +03:00
CLOCKSOURCE_OF_DECLARE ( mips_gic_timer , " mti,gic-timer " ,
2014-11-12 22:43:39 +03:00
gic_clocksource_of_init ) ;