2355d45f7ca5ec7761d52cede10f426c258c810f
[reactos.git] / drivers / net / packet / time_calls.h
1 /*
2  * Copyright (c) 2001
3  *      Politecnico di Torino.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the Politecnico
13  * di Torino, and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifndef _time_calls
23 #define _time_calls
24
25 #ifdef WIN_NT_DRIVER
26
27 #include "debug.h"
28
29 /*!
30   \brief A microsecond precise timestamp.
31
32   included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet. 
33 */
34
35 struct timeval {
36         long    tv_sec;         ///< seconds
37         long    tv_usec;        ///< microseconds
38 };
39
40 #endif /*WIN_NT_DRIVER*/
41
42 struct time_conv {
43         ULONGLONG reference;
44         struct timeval start;
45 };
46
47 #ifdef __GNUC__
48
49 void TIME_DESYNCHRONIZE(struct time_conv *data);
50 VOID TIME_SYNCHRONIZE(struct time_conv *data);
51 void FORCE_TIME(struct timeval *src, struct time_conv *dest);
52 void GET_TIME(struct timeval *dst, struct time_conv *data);
53
54 #else /* __GNUC__ */
55
56 #ifdef WIN_NT_DRIVER
57
58 __inline void TIME_DESYNCHRONIZE(struct time_conv *data)
59 {
60         data->reference = 0;
61         data->start.tv_sec = 0;
62         data->start.tv_usec = 0;
63 }
64
65 #ifdef KQPC_TS
66
67 /* KeQueryPerformanceCounter TimeStamps */
68
69 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
70 {
71         struct timeval tmp;
72         LARGE_INTEGER SystemTime;
73         LARGE_INTEGER i;
74         ULONG tmp2;
75         LARGE_INTEGER TimeFreq,PTime;
76
77         if (data->reference!=0)
78                 return;
79         
80         // get the absolute value of the system boot time.   
81         PTime=KeQueryPerformanceCounter(&TimeFreq);
82         KeQuerySystemTime(&SystemTime);
83         tmp.tv_sec=(LONG)(SystemTime.QuadPart/10000000-11644473600);
84         tmp.tv_usec=(LONG)((SystemTime.QuadPart%10000000)/10);
85         tmp.tv_sec-=(ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
86         tmp.tv_usec-=(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
87         if (tmp.tv_usec<0) {
88                 tmp.tv_sec--;
89                 tmp.tv_usec+=1000000;
90         }
91         data->start=tmp;
92         data->reference=1;
93 }
94
95 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
96 {
97         dest->start=*src;
98 }
99
100 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
101 {
102         LARGE_INTEGER PTime, TimeFreq;
103         LONG tmp;
104
105         PTime=KeQueryPerformanceCounter(&TimeFreq);
106         tmp=(LONG)(PTime.QuadPart/TimeFreq.QuadPart);
107         dst->tv_sec=data->start.tv_sec+tmp;
108         dst->tv_usec=data->start.tv_usec+(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
109         if (dst->tv_usec>=1000000) {
110                 dst->tv_sec++;
111                 dst->tv_usec-=1000000;
112         }
113 }
114
115 #else
116
117 /*RDTSC timestamps*/
118
119 /* callers must be at IRQL=PASSIVE_LEVEL */
120 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
121 {
122         struct timeval tmp;
123         LARGE_INTEGER system_time;
124         ULONGLONG curr_ticks;
125         KIRQL old;
126         LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
127         ULONGLONG start_ticks,stop_ticks;
128         ULONGLONG delta,delta2;
129         KEVENT event;
130         LARGE_INTEGER i;
131         ULONGLONG reference;
132
133         if (data->reference!=0)
134                 return;
135         
136         KeInitializeEvent(&event,NotificationEvent,FALSE);
137         i.QuadPart=-3500000;
138         KeRaiseIrql(HIGH_LEVEL,&old);
139         start_kqpc=KeQueryPerformanceCounter(&start_freq);
140 #ifndef __GNUC__
141         __asm
142         {
143                 push eax
144                 push edx
145                 push ecx
146                 rdtsc
147                 lea ecx, start_ticks
148                 mov [ecx+4], edx
149                 mov [ecx], eax
150                 pop ecx
151                 pop edx
152                 pop eax
153         }
154 #else
155 #endif
156         KeLowerIrql(old);
157     KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
158         KeRaiseIrql(HIGH_LEVEL,&old);
159         stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
160 #ifndef __GNUC__
161         __asm
162         {
163                 push eax
164                 push edx
165                 push ecx
166                 rdtsc
167                 lea ecx, stop_ticks
168                 mov [ecx+4], edx
169                 mov [ecx], eax
170                 pop ecx
171                 pop edx
172                 pop eax
173         }
174 #else
175 #endif
176         KeLowerIrql(old);
177         delta=stop_ticks-start_ticks;
178         delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
179         if (delta>10000000000) {
180                 delta/=16;
181                 delta2/=16;
182         }
183         reference=delta*(start_freq.QuadPart)/delta2;
184         data->reference=reference/1000;
185         if (reference%1000>500) 
186                 data->reference++;
187         data->reference*=1000;
188         reference=data->reference;
189         KeQuerySystemTime(&system_time);
190 #ifndef __GNUC__
191         __asm
192         {
193                 push eax
194                 push edx
195                 push ecx
196                 rdtsc
197                 lea ecx, curr_ticks
198                 mov [ecx+4], edx
199                 mov [ecx], eax
200                 pop ecx
201                 pop edx
202                 pop eax
203         }
204 #else
205 #endif
206         tmp.tv_sec=-(LONG)(curr_ticks/reference);
207         tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
208         system_time.QuadPart-=116444736000000000;
209         tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
210         tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
211         if (tmp.tv_usec<0) {
212                 tmp.tv_sec--;
213                 tmp.tv_usec+=1000000;
214         }
215         data->start=tmp;
216         IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
217 }
218
219 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
220 {
221         dest->start=*src;
222 }
223
224 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
225 {
226         ULONGLONG tmp;
227 #ifndef __GNUC__
228         __asm
229         {
230                 push eax
231                 push edx
232                 push ecx
233                 rdtsc
234                 lea ecx, tmp
235                 mov [ecx+4], edx
236                 mov [ecx], eax
237                 pop ecx
238                 pop edx
239                 pop eax
240         }
241 #else
242 #endif
243         if (data->reference==0) {
244                 return;
245         }
246         dst->tv_sec=(LONG)(tmp/data->reference);
247         dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
248         dst->tv_sec+=data->start.tv_sec;
249         dst->tv_usec+=data->start.tv_usec;
250         if (dst->tv_usec>=1000000) {
251                 dst->tv_sec++;
252                 dst->tv_usec-=1000000;
253         }
254 }
255
256 #endif /*KQPC_TS*/
257
258 #endif /*WIN_NT_DRIVER*/
259
260 #endif /* __GNUC__ */
261
262 #endif /*_time_calls*/