2007-11-25 01:33:28 +03: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 ) 2007 by Ralf Baechle
*/
2007-11-28 18:07:42 +03:00
# include <linux/clocksource.h>
# include <linux/init.h>
2015-03-07 21:30:24 +03:00
# include <linux/sched_clock.h>
2007-11-28 18:07:42 +03:00
# include <asm/time.h>
2007-11-25 01:33:28 +03:00
2016-12-21 22:32:01 +03:00
static u64 c0_hpt_read ( struct clocksource * cs )
2007-11-25 01:33:28 +03:00
{
return read_c0_count ( ) ;
}
static struct clocksource clocksource_mips = {
. name = " MIPS " ,
. read = c0_hpt_read ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2016-07-22 06:46:31 +03:00
static u64 __maybe_unused notrace r4k_read_sched_clock ( void )
2015-03-07 21:30:24 +03:00
{
return read_c0_count ( ) ;
}
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
static inline unsigned int rdhwr_count ( void )
{
unsigned int count ;
__asm__ __volatile__ (
" .set push \n "
" .set mips32r2 \n "
" rdhwr %0, $2 \n "
" .set pop \n "
: " =r " ( count ) ) ;
return count ;
}
static bool rdhwr_count_usable ( void )
{
unsigned int prev , curr , i ;
/*
* Older QEMUs have a broken implementation of RDHWR for the CP0 count
* which always returns a constant value . Try to identify this and don ' t
* use it in the VDSO if it is broken . This workaround can be removed
* once the fix has been in QEMU stable for a reasonable amount of time .
*/
for ( i = 0 , prev = rdhwr_count ( ) ; i < 100 ; i + + ) {
curr = rdhwr_count ( ) ;
if ( curr ! = prev )
return true ;
prev = curr ;
}
pr_warn ( " Not using R4K clocksource in VDSO due to broken RDHWR \n " ) ;
return false ;
}
2008-12-21 11:26:22 +03:00
int __init init_r4k_clocksource ( void )
2007-11-25 01:33:28 +03:00
{
2008-03-12 16:58:10 +03:00
if ( ! cpu_has_counter | | ! mips_hpt_frequency )
return - ENXIO ;
2008-11-03 14:31:54 +03:00
/* Calculate a somewhat reasonable rating value */
2007-11-25 01:33:28 +03:00
clocksource_mips . rating = 200 + mips_hpt_frequency / 10000000 ;
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
/*
* R2 onwards makes the count accessible to user mode so it can be used
* by the VDSO ( HWREna is configured by configure_hwrena ( ) ) .
*/
if ( cpu_has_mips_r2_r6 & & rdhwr_count_usable ( ) )
clocksource_mips . archdata . vdso_clock_mode = VDSO_CLOCK_R4K ;
2010-04-27 07:23:11 +04:00
clocksource_register_hz ( & clocksource_mips , mips_hpt_frequency ) ;
2008-03-12 16:58:10 +03:00
2016-07-22 06:46:31 +03:00
# ifndef CONFIG_CPU_FREQ
2015-03-07 21:30:24 +03:00
sched_clock_register ( r4k_read_sched_clock , 32 , mips_hpt_frequency ) ;
2016-07-22 06:46:31 +03:00
# endif
2015-03-07 21:30:24 +03:00
2008-03-12 16:58:10 +03:00
return 0 ;
2007-11-25 01:33:28 +03:00
}