![]() |
|
|||
0001 /* SPDX-License-Identifier: GPL-2.0-only */ 0002 /* 0003 * Extend a 32-bit counter to 63 bits 0004 * 0005 * Author: Nicolas Pitre 0006 * Created: December 3, 2006 0007 * Copyright: MontaVista Software, Inc. 0008 */ 0009 0010 #ifndef __LINUX_CNT32_TO_63_H__ 0011 #define __LINUX_CNT32_TO_63_H__ 0012 0013 #include <linux/compiler.h> 0014 #include <linux/types.h> 0015 #include <asm/byteorder.h> 0016 0017 /* this is used only to give gcc a clue about good code generation */ 0018 union cnt32_to_63 { 0019 struct { 0020 #if defined(__LITTLE_ENDIAN) 0021 u32 lo, hi; 0022 #elif defined(__BIG_ENDIAN) 0023 u32 hi, lo; 0024 #endif 0025 }; 0026 u64 val; 0027 }; 0028 0029 0030 /** 0031 * cnt32_to_63 - Expand a 32-bit counter to a 63-bit counter 0032 * @cnt_lo: The low part of the counter 0033 * 0034 * Many hardware clock counters are only 32 bits wide and therefore have 0035 * a relatively short period making wrap-arounds rather frequent. This 0036 * is a problem when implementing sched_clock() for example, where a 64-bit 0037 * non-wrapping monotonic value is expected to be returned. 0038 * 0039 * To overcome that limitation, let's extend a 32-bit counter to 63 bits 0040 * in a completely lock free fashion. Bits 0 to 31 of the clock are provided 0041 * by the hardware while bits 32 to 62 are stored in memory. The top bit in 0042 * memory is used to synchronize with the hardware clock half-period. When 0043 * the top bit of both counters (hardware and in memory) differ then the 0044 * memory is updated with a new value, incrementing it when the hardware 0045 * counter wraps around. 0046 * 0047 * Because a word store in memory is atomic then the incremented value will 0048 * always be in synch with the top bit indicating to any potential concurrent 0049 * reader if the value in memory is up to date or not with regards to the 0050 * needed increment. And any race in updating the value in memory is harmless 0051 * as the same value would simply be stored more than once. 0052 * 0053 * The restrictions for the algorithm to work properly are: 0054 * 0055 * 1) this code must be called at least once per each half period of the 0056 * 32-bit counter; 0057 * 0058 * 2) this code must not be preempted for a duration longer than the 0059 * 32-bit counter half period minus the longest period between two 0060 * calls to this code; 0061 * 0062 * Those requirements ensure proper update to the state bit in memory. 0063 * This is usually not a problem in practice, but if it is then a kernel 0064 * timer should be scheduled to manage for this code to be executed often 0065 * enough. 0066 * 0067 * And finally: 0068 * 0069 * 3) the cnt_lo argument must be seen as a globally incrementing value, 0070 * meaning that it should be a direct reference to the counter data which 0071 * can be evaluated according to a specific ordering within the macro, 0072 * and not the result of a previous evaluation stored in a variable. 0073 * 0074 * For example, this is wrong: 0075 * 0076 * u32 partial = get_hw_count(); 0077 * u64 full = cnt32_to_63(partial); 0078 * return full; 0079 * 0080 * This is fine: 0081 * 0082 * u64 full = cnt32_to_63(get_hw_count()); 0083 * return full; 0084 * 0085 * Note that the top bit (bit 63) in the returned value should be considered 0086 * as garbage. It is not cleared here because callers are likely to use a 0087 * multiplier on the returned value which can get rid of the top bit 0088 * implicitly by making the multiplier even, therefore saving on a runtime 0089 * clear-bit instruction. Otherwise caller must remember to clear the top 0090 * bit explicitly. 0091 */ 0092 #define cnt32_to_63(cnt_lo) \ 0093 ({ \ 0094 static u32 __m_cnt_hi; \ 0095 union cnt32_to_63 __x; \ 0096 __x.hi = __m_cnt_hi; \ 0097 smp_rmb(); \ 0098 __x.lo = (cnt_lo); \ 0099 if (unlikely((s32)(__x.hi ^ __x.lo) < 0)) \ 0100 __m_cnt_hi = __x.hi = (__x.hi ^ 0x80000000) + (__x.hi >> 31); \ 0101 __x.val; \ 0102 }) 0103 0104 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |