diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 15:40:39 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 15:40:39 -0800 |
commit | ea14fad0d416354a4e9bb1a04f32acba706f9548 (patch) | |
tree | 2c8acc5331f189aef1d40ddce3f40d6be9314e77 /include/asm-arm/cnt32_to_63.h | |
parent | 6ee7e78e7c78d871409ad4df30551c9355be7d0e (diff) | |
parent | 6705cda24fad1cb0ac82ac4f312df8ec735b39b0 (diff) | |
download | op-kernel-dev-ea14fad0d416354a4e9bb1a04f32acba706f9548.zip op-kernel-dev-ea14fad0d416354a4e9bb1a04f32acba706f9548.tar.gz |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (76 commits)
[ARM] 4002/1: S3C24XX: leave parent IRQs unmasked
[ARM] 4001/1: S3C24XX: shorten reboot time
[ARM] 3983/2: remove unused argument to __bug()
[ARM] 4000/1: Osiris: add third serial port in
[ARM] 3999/1: RX3715: suspend to RAM support
[ARM] 3998/1: VR1000: LED platform devices
[ARM] 3995/1: iop13xx: add iop13xx support
[ARM] 3968/1: iop13xx: add iop13xx_defconfig
[ARM] Update mach-types
[ARM] Allow gcc to optimise arm_add_memory a little more
[ARM] 3991/1: i.MX/MX1 high resolution time source
[ARM] 3990/1: i.MX/MX1 more precise PLL decode
[ARM] 3986/1: H1940: suspend to RAM support
[ARM] 3985/1: ixp4xx clocksource cleanup
[ARM] 3984/1: ixp4xx/nslu2: Fix disk LED numbering (take 2)
[ARM] 3994/1: ixp23xx: fix handling of pci master aborts
[ARM] 3981/1: sched_clock for PXA2xx
[ARM] 3980/1: extend the ARM Versatile sched_clock implementation from 32 to 63 bit
[ARM] 3979/1: extend the SA11x0 sched_clock implementation from 32 to 63 bit period
[ARM] 3978/1: macro to provide a 63-bit value from a 32-bit hardware counter
...
Diffstat (limited to 'include/asm-arm/cnt32_to_63.h')
-rw-r--r-- | include/asm-arm/cnt32_to_63.h | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/include/asm-arm/cnt32_to_63.h b/include/asm-arm/cnt32_to_63.h new file mode 100644 index 0000000..480c873 --- /dev/null +++ b/include/asm-arm/cnt32_to_63.h @@ -0,0 +1,78 @@ +/* + * include/asm/cnt32_to_63.h -- extend a 32-bit counter to 63 bits + * + * Author: Nicolas Pitre + * Created: December 3, 2006 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#ifndef __INCLUDE_CNT32_TO_63_H__ +#define __INCLUDE_CNT32_TO_63_H__ + +#include <linux/compiler.h> +#include <asm/types.h> +#include <asm/byteorder.h> + +/* + * Prototype: u64 cnt32_to_63(u32 cnt) + * Many hardware clock counters are only 32 bits wide and therefore have + * a relatively short period making wrap-arounds rather frequent. This + * is a problem when implementing sched_clock() for example, where a 64-bit + * non-wrapping monotonic value is expected to be returned. + * + * To overcome that limitation, let's extend a 32-bit counter to 63 bits + * in a completely lock free fashion. Bits 0 to 31 of the clock are provided + * by the hardware while bits 32 to 62 are stored in memory. The top bit in + * memory is used to synchronize with the hardware clock half-period. When + * the top bit of both counters (hardware and in memory) differ then the + * memory is updated with a new value, incrementing it when the hardware + * counter wraps around. + * + * Because a word store in memory is atomic then the incremented value will + * always be in synch with the top bit indicating to any potential concurrent + * reader if the value in memory is up to date or not with regards to the + * needed increment. And any race in updating the value in memory is harmless + * as the same value would simply be stored more than once. + * + * The only restriction for the algorithm to work properly is that this + * code must be executed at least once per each half period of the 32-bit + * counter to properly update the state bit in memory. This is usually not a + * problem in practice, but if it is then a kernel timer could be scheduled + * to manage for this code to be executed often enough. + * + * Note that the top bit (bit 63) in the returned value should be considered + * as garbage. It is not cleared here because callers are likely to use a + * multiplier on the returned value which can get rid of the top bit + * implicitly by making the multiplier even, therefore saving on a runtime + * clear-bit instruction. Otherwise caller must remember to clear the top + * bit explicitly. + */ + +/* this is used only to give gcc a clue about good code generation */ +typedef union { + struct { +#if defined(__LITTLE_ENDIAN) + u32 lo, hi; +#elif defined(__BIG_ENDIAN) + u32 hi, lo; +#endif + }; + u64 val; +} cnt32_to_63_t; + +#define cnt32_to_63(cnt_lo) \ +({ \ + static volatile u32 __m_cnt_hi = 0; \ + cnt32_to_63_t __x; \ + __x.hi = __m_cnt_hi; \ + __x.lo = (cnt_lo); \ + if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \ + __m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \ + __x.val; \ +}) + +#endif |