ktime.h revision 270710
1270710Shselasky/*-
2270710Shselasky * Copyright (c) 2014 Mellanox Technologies, Ltd.
3270710Shselasky * All rights reserved.
4270710Shselasky *
5270710Shselasky * Redistribution and use in source and binary forms, with or without
6270710Shselasky * modification, are permitted provided that the following conditions
7270710Shselasky * are met:
8270710Shselasky * 1. Redistributions of source code must retain the above copyright
9270710Shselasky *    notice unmodified, this list of conditions, and the following
10270710Shselasky *    disclaimer.
11270710Shselasky * 2. Redistributions in binary form must reproduce the above copyright
12270710Shselasky *    notice, this list of conditions and the following disclaimer in the
13270710Shselasky *    documentation and/or other materials provided with the distribution.
14270710Shselasky *
15270710Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16270710Shselasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17270710Shselasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18270710Shselasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19270710Shselasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20270710Shselasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21270710Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22270710Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23270710Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24270710Shselasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25270710Shselasky */
26270710Shselasky
27270710Shselasky#ifndef _LINUX_KTIME_H
28270710Shselasky#define _LINUX_KTIME_H
29270710Shselasky
30270710Shselasky#include <sys/time.h>
31270710Shselasky#include <linux/types.h>
32270710Shselasky#include <linux/jiffies.h>
33270710Shselasky
34270710Shselasky
35270710Shselasky/* Get the monotonic time in timespec format: */
36270710Shselasky#define ktime_get_ts getnanouptime
37270710Shselasky
38270710Shselasky#define NSEC_PER_USEC   1000L
39270710Shselasky#define NSEC_PER_SEC    1000000000L
40270710Shselasky
41270710Shselasky/*
42270710Shselasky * ktime_t:
43270710Shselasky *
44270710Shselasky * On 64-bit CPUs a single 64-bit variable is used to store the hrtimers
45270710Shselasky * internal representation of time values in scalar nanoseconds. The
46270710Shselasky * design plays out best on 64-bit CPUs, where most conversions are
47270710Shselasky * NOPs and most arithmetic ktime_t operations are plain arithmetic
48270710Shselasky * operations.
49270710Shselasky *
50270710Shselasky * On 32-bit CPUs an optimized representation of the timespec structure
51270710Shselasky * is used to avoid expensive conversions from and to timespecs. The
52270710Shselasky * endian-aware order of the tv struct members is chosen to allow
53270710Shselasky * mathematical operations on the tv64 member of the union too, which
54270710Shselasky * for certain operations produces better code.
55270710Shselasky *
56270710Shselasky * For architectures with efficient support for 64/32-bit conversions the
57270710Shselasky * plain scalar nanosecond based representation can be selected by the
58270710Shselasky * config switch CONFIG_KTIME_SCALAR.
59270710Shselasky */
60270710Shselaskyunion ktime {
61270710Shselasky	s64	tv64;
62270710Shselasky#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
63270710Shselasky	struct {
64270710Shselasky# ifdef __BIG_ENDIAN
65270710Shselasky	s32	sec, nsec;
66270710Shselasky# else
67270710Shselasky	s32	nsec, sec;
68270710Shselasky# endif
69270710Shselasky	} tv;
70270710Shselasky#endif
71270710Shselasky};
72270710Shselasky
73270710Shselaskytypedef union ktime ktime_t;		/* Kill this */
74270710Shselasky
75270710Shselasky#define KTIME_MAX                       ((s64)~((u64)1 << 63))
76270710Shselasky#define KTIME_SEC_MAX                   (KTIME_MAX / NSEC_PER_SEC)
77270710Shselasky
78270710Shselasky/*
79270710Shselasky * ktime_t definitions when using the 64-bit scalar representation:
80270710Shselasky */
81270710Shselasky
82270710Shselasky#if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)
83270710Shselasky
84270710Shselasky/**
85270710Shselasky * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
86270710Shselasky * @secs:	seconds to set
87270710Shselasky * @nsecs:	nanoseconds to set
88270710Shselasky *
89270710Shselasky * Return the ktime_t representation of the value
90270710Shselasky */
91270710Shselaskystatic inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
92270710Shselasky{
93270710Shselasky#if (BITS_PER_LONG == 64)
94270710Shselasky	if (unlikely(secs >= KTIME_SEC_MAX))
95270710Shselasky		return (ktime_t){ .tv64 = KTIME_MAX };
96270710Shselasky#endif
97270710Shselasky	return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs };
98270710Shselasky}
99270710Shselasky
100270710Shselasky/* Subtract two ktime_t variables. rem = lhs -rhs: */
101270710Shselasky#define ktime_sub(lhs, rhs) \
102270710Shselasky		({ (ktime_t){ .tv64 = (lhs).tv64 - (rhs).tv64 }; })
103270710Shselasky
104270710Shselasky/* Add two ktime_t variables. res = lhs + rhs: */
105270710Shselasky#define ktime_add(lhs, rhs) \
106270710Shselasky		({ (ktime_t){ .tv64 = (lhs).tv64 + (rhs).tv64 }; })
107270710Shselasky
108270710Shselasky/*
109270710Shselasky * Add a ktime_t variable and a scalar nanosecond value.
110270710Shselasky * res = kt + nsval:
111270710Shselasky */
112270710Shselasky#define ktime_add_ns(kt, nsval) \
113270710Shselasky		({ (ktime_t){ .tv64 = (kt).tv64 + (nsval) }; })
114270710Shselasky
115270710Shselasky/*
116270710Shselasky * Subtract a scalar nanosecod from a ktime_t variable
117270710Shselasky * res = kt - nsval:
118270710Shselasky */
119270710Shselasky#define ktime_sub_ns(kt, nsval) \
120270710Shselasky		({ (ktime_t){ .tv64 = (kt).tv64 - (nsval) }; })
121270710Shselasky
122270710Shselasky/* convert a timespec to ktime_t format: */
123270710Shselaskystatic inline ktime_t timespec_to_ktime(struct timespec ts)
124270710Shselasky{
125270710Shselasky	return ktime_set(ts.tv_sec, ts.tv_nsec);
126270710Shselasky}
127270710Shselasky
128270710Shselasky/* convert a timeval to ktime_t format: */
129270710Shselaskystatic inline ktime_t timeval_to_ktime(struct timeval tv)
130270710Shselasky{
131270710Shselasky	return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC);
132270710Shselasky}
133270710Shselasky
134270710Shselasky/* Map the ktime_t to timespec conversion to ns_to_timespec function */
135270710Shselasky#define ktime_to_timespec(kt)		ns_to_timespec((kt).tv64)
136270710Shselasky
137270710Shselasky/* Map the ktime_t to timeval conversion to ns_to_timeval function */
138270710Shselasky#define ktime_to_timeval(kt)		ns_to_timeval((kt).tv64)
139270710Shselasky
140270710Shselasky/* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */
141270710Shselasky#define ktime_to_ns(kt)			((kt).tv64)
142270710Shselasky
143270710Shselasky#else	/* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */
144270710Shselasky
145270710Shselasky/*
146270710Shselasky * Helper macros/inlines to get the ktime_t math right in the timespec
147270710Shselasky * representation. The macros are sometimes ugly - their actual use is
148270710Shselasky * pretty okay-ish, given the circumstances. We do all this for
149270710Shselasky * performance reasons. The pure scalar nsec_t based code was nice and
150270710Shselasky * simple, but created too many 64-bit / 32-bit conversions and divisions.
151270710Shselasky *
152270710Shselasky * Be especially aware that negative values are represented in a way
153270710Shselasky * that the tv.sec field is negative and the tv.nsec field is greater
154270710Shselasky * or equal to zero but less than nanoseconds per second. This is the
155270710Shselasky * same representation which is used by timespecs.
156270710Shselasky *
157270710Shselasky *   tv.sec < 0 and 0 >= tv.nsec < NSEC_PER_SEC
158270710Shselasky */
159270710Shselasky
160270710Shselasky/* Set a ktime_t variable to a value in sec/nsec representation: */
161270710Shselaskystatic inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
162270710Shselasky{
163270710Shselasky	return (ktime_t) { .tv = { .sec = secs, .nsec = nsecs } };
164270710Shselasky}
165270710Shselasky
166270710Shselasky/**
167270710Shselasky * ktime_sub - subtract two ktime_t variables
168270710Shselasky * @lhs:	minuend
169270710Shselasky * @rhs:	subtrahend
170270710Shselasky *
171270710Shselasky * Returns the remainder of the subtraction
172270710Shselasky */
173270710Shselaskystatic inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
174270710Shselasky{
175270710Shselasky	ktime_t res;
176270710Shselasky
177270710Shselasky	res.tv64 = lhs.tv64 - rhs.tv64;
178270710Shselasky	if (res.tv.nsec < 0)
179270710Shselasky		res.tv.nsec += NSEC_PER_SEC;
180270710Shselasky
181270710Shselasky	return res;
182270710Shselasky}
183270710Shselasky
184270710Shselasky/**
185270710Shselasky * ktime_add - add two ktime_t variables
186270710Shselasky * @add1:	addend1
187270710Shselasky * @add2:	addend2
188270710Shselasky *
189270710Shselasky * Returns the sum of @add1 and @add2.
190270710Shselasky */
191270710Shselaskystatic inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
192270710Shselasky{
193270710Shselasky	ktime_t res;
194270710Shselasky
195270710Shselasky	res.tv64 = add1.tv64 + add2.tv64;
196270710Shselasky	/*
197270710Shselasky	 * performance trick: the (u32) -NSEC gives 0x00000000Fxxxxxxx
198270710Shselasky	 * so we subtract NSEC_PER_SEC and add 1 to the upper 32 bit.
199270710Shselasky	 *
200270710Shselasky	 * it's equivalent to:
201270710Shselasky	 *   tv.nsec -= NSEC_PER_SEC
202270710Shselasky	 *   tv.sec ++;
203270710Shselasky	 */
204270710Shselasky	if (res.tv.nsec >= NSEC_PER_SEC)
205270710Shselasky		res.tv64 += (u32)-NSEC_PER_SEC;
206270710Shselasky
207270710Shselasky	return res;
208270710Shselasky}
209270710Shselasky
210270710Shselasky/**
211270710Shselasky * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
212270710Shselasky * @kt:		addend
213270710Shselasky * @nsec:	the scalar nsec value to add
214270710Shselasky *
215270710Shselasky * Returns the sum of @kt and @nsec in ktime_t format
216270710Shselasky */
217270710Shselaskyextern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
218270710Shselasky
219270710Shselasky/**
220270710Shselasky * ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable
221270710Shselasky * @kt:		minuend
222270710Shselasky * @nsec:	the scalar nsec value to subtract
223270710Shselasky *
224270710Shselasky * Returns the subtraction of @nsec from @kt in ktime_t format
225270710Shselasky */
226270710Shselaskyextern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);
227270710Shselasky
228270710Shselasky/**
229270710Shselasky * timespec_to_ktime - convert a timespec to ktime_t format
230270710Shselasky * @ts:		the timespec variable to convert
231270710Shselasky *
232270710Shselasky * Returns a ktime_t variable with the converted timespec value
233270710Shselasky */
234270710Shselaskystatic inline ktime_t timespec_to_ktime(const struct timespec ts)
235270710Shselasky{
236270710Shselasky	return (ktime_t) { .tv = { .sec = (s32)ts.tv_sec,
237270710Shselasky			   	   .nsec = (s32)ts.tv_nsec } };
238270710Shselasky}
239270710Shselasky
240270710Shselasky/**
241270710Shselasky * timeval_to_ktime - convert a timeval to ktime_t format
242270710Shselasky * @tv:		the timeval variable to convert
243270710Shselasky *
244270710Shselasky * Returns a ktime_t variable with the converted timeval value
245270710Shselasky */
246270710Shselaskystatic inline ktime_t timeval_to_ktime(const struct timeval tv)
247270710Shselasky{
248270710Shselasky	return (ktime_t) { .tv = { .sec = (s32)tv.tv_sec,
249270710Shselasky				   .nsec = (s32)(tv.tv_usec *
250270710Shselasky						 NSEC_PER_USEC) } };
251270710Shselasky}
252270710Shselasky
253270710Shselasky/**
254270710Shselasky * ktime_to_timespec - convert a ktime_t variable to timespec format
255270710Shselasky * @kt:		the ktime_t variable to convert
256270710Shselasky *
257270710Shselasky * Returns the timespec representation of the ktime value
258270710Shselasky */
259270710Shselaskystatic inline struct timespec ktime_to_timespec(const ktime_t kt)
260270710Shselasky{
261270710Shselasky	return (struct timespec) { .tv_sec = (time_t) kt.tv.sec,
262270710Shselasky				   .tv_nsec = (long) kt.tv.nsec };
263270710Shselasky}
264270710Shselasky
265270710Shselasky/**
266270710Shselasky * ktime_to_timeval - convert a ktime_t variable to timeval format
267270710Shselasky * @kt:		the ktime_t variable to convert
268270710Shselasky *
269270710Shselasky * Returns the timeval representation of the ktime value
270270710Shselasky */
271270710Shselaskystatic inline struct timeval ktime_to_timeval(const ktime_t kt)
272270710Shselasky{
273270710Shselasky	return (struct timeval) {
274270710Shselasky		.tv_sec = (time_t) kt.tv.sec,
275270710Shselasky		.tv_usec = (suseconds_t) (kt.tv.nsec / NSEC_PER_USEC) };
276270710Shselasky}
277270710Shselasky
278270710Shselasky/**
279270710Shselasky * ktime_to_ns - convert a ktime_t variable to scalar nanoseconds
280270710Shselasky * @kt:		the ktime_t variable to convert
281270710Shselasky *
282270710Shselasky * Returns the scalar nanoseconds representation of @kt
283270710Shselasky */
284270710Shselaskystatic inline s64 ktime_to_ns(const ktime_t kt)
285270710Shselasky{
286270710Shselasky	return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec;
287270710Shselasky}
288270710Shselasky
289270710Shselasky#endif	/* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */
290270710Shselasky
291270710Shselasky#endif	/* _LINUX_KTIME_H */
292