Rev 1621 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
120 | giacomo | 1 | /* Project: OSLib |
2 | * Description: The OS Construction Kit |
||
3 | * Date: 1.6.2000 |
||
4 | * Idea by: Luca Abeni & Gerardo Lamastra |
||
5 | * |
||
6 | * OSLib is an SO project aimed at developing a common, easy-to-use |
||
7 | * low-level infrastructure for developing OS kernels and Embedded |
||
8 | * Applications; it partially derives from the HARTIK project but it |
||
9 | * currently is independently developed. |
||
10 | * |
||
11 | * OSLib is distributed under GPL License, and some of its code has |
||
12 | * been derived from the Linux kernel source; also some important |
||
13 | * ideas come from studying the DJGPP go32 extender. |
||
14 | * |
||
15 | * We acknowledge the Linux Community, Free Software Foundation, |
||
16 | * D.J. Delorie and all the other developers who believe in the |
||
17 | * freedom of software and ideas. |
||
18 | * |
||
19 | * For legalese, check out the included GPL license. |
||
20 | */ |
||
21 | |||
22 | /* Advanced Timer Managment |
||
23 | * Author: Giacomo Guidi <giacomo@gandalf.sssup.it> |
||
24 | */ |
||
25 | |||
1621 | fabio | 26 | #include <arch/i386/stdlib.h> |
120 | giacomo | 27 | #include <ll/i386/error.h> |
28 | #include <ll/sys/ll/ll-data.h> |
||
29 | #include <ll/sys/ll/ll-func.h> |
||
30 | #include <ll/i386/pic.h> |
||
299 | giacomo | 31 | #include <ll/i386/apic.h> |
305 | giacomo | 32 | #include <ll/i386/64bit.h> |
120 | giacomo | 33 | #include <ll/sys/ll/event.h> |
34 | #include <ll/sys/ll/time.h> |
||
305 | giacomo | 35 | #include <ll/i386/advtimer.h> |
120 | giacomo | 36 | |
264 | giacomo | 37 | #define CALIBRATE_USING_CMOS |
38 | |||
305 | giacomo | 39 | unsigned long long init_tsc; |
40 | unsigned long long * ptr_init_tsc = &init_tsc; |
||
120 | giacomo | 41 | |
648 | mauro | 42 | struct timespec init_time; |
43 | struct timespec * ptr_init_time = &init_time; |
||
120 | giacomo | 44 | |
305 | giacomo | 45 | unsigned int clk_per_msec = 0; |
46 | unsigned int apic_clk_per_msec = 0; |
||
47 | unsigned int apic_set_limit = 0; |
||
194 | giacomo | 48 | |
336 | giacomo | 49 | /* Precalcolated const |
50 | used in ll_read_timer */ |
||
51 | unsigned int clk_opt_0 = 0; |
||
329 | giacomo | 52 | unsigned int clk_opt_1 = 0; |
53 | unsigned int clk_opt_2 = 0; |
||
54 | unsigned int clk_opt_3 = 0; |
||
55 | unsigned int clk_opt_4 = 0; |
||
336 | giacomo | 56 | unsigned int clk_opt_5 = 0; |
329 | giacomo | 57 | |
120 | giacomo | 58 | unsigned char save_CMOS_regA; |
59 | unsigned char save_CMOS_regB; |
||
60 | |||
651 | mauro | 61 | unsigned long msr_original_low, msr_original_high; |
62 | |||
619 | mauro | 63 | unsigned char X86_tsc = 0; |
64 | unsigned char X86_apic = 0; |
||
65 | unsigned char use_tsc = 0; |
||
66 | unsigned char use_apic = 0; |
||
67 | |||
120 | giacomo | 68 | #ifdef CONFIG_MELAN |
69 | # define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ |
||
70 | #else |
||
249 | giacomo | 71 | # define CLOCK_TICK_RATE 1193182 /* Underlying HZ */ |
120 | giacomo | 72 | #endif |
73 | |||
248 | giacomo | 74 | #define COUNTER_END 100 |
120 | giacomo | 75 | |
245 | giacomo | 76 | #define barrier() __asm__ __volatile__("" ::: "memory"); |
77 | |||
120 | giacomo | 78 | //TSC Calibration (idea from the linux kernel code) |
79 | void ll_calibrate_tsc(void) |
||
80 | { |
||
81 | |||
305 | giacomo | 82 | unsigned long long start; |
83 | unsigned long long end; |
||
84 | unsigned long long dtsc; |
||
120 | giacomo | 85 | |
305 | giacomo | 86 | unsigned int start_8253, end_8253, delta_8253; |
120 | giacomo | 87 | |
248 | giacomo | 88 | outp(0x61, (inp(0x61) & ~0x02) | 0x01); |
120 | giacomo | 89 | |
90 | outp(0x43,0xB0); /* binary, mode 0, LSB/MSB, Ch 2 */ |
||
238 | giacomo | 91 | outp(0x42,0xFF); /* LSB of count */ |
92 | outp(0x42,0xFF); /* MSB of count */ |
||
242 | giacomo | 93 | |
619 | mauro | 94 | barrier(); |
95 | rdtscll(start); |
||
96 | barrier(); |
||
97 | outp(0x43,0x00); |
||
243 | giacomo | 98 | start_8253 = inp(0x42); |
99 | start_8253 |= inp(0x42) << 8; |
||
619 | mauro | 100 | barrier(); |
101 | rdtscll(start); |
||
102 | barrier(); |
||
243 | giacomo | 103 | |
104 | do { |
||
105 | outp(0x43,0x00); |
||
106 | end_8253 = inp(0x42); |
||
107 | end_8253 |= inp(0x42) << 8; |
||
108 | } while (end_8253 > COUNTER_END); |
||
109 | |||
619 | mauro | 110 | barrier(); |
111 | rdtscll(end); |
||
112 | barrier(); |
||
243 | giacomo | 113 | outp(0x43,0x00); |
114 | end_8253 = inp(0x42); |
||
115 | end_8253 |= inp(0x42) << 8; |
||
619 | mauro | 116 | barrier(); |
117 | rdtscll(end); |
||
118 | barrier(); |
||
243 | giacomo | 119 | |
120 | //Delta TSC |
||
619 | mauro | 121 | dtsc = end - start; |
243 | giacomo | 122 | |
123 | //Delta PIT |
||
264 | giacomo | 124 | delta_8253 = start_8253 - end_8253; |
243 | giacomo | 125 | |
242 | giacomo | 126 | if (delta_8253 > 0x20000) { |
120 | giacomo | 127 | message("Error calculating Delta PIT\n"); |
128 | ll_abort(10); |
||
129 | } |
||
130 | |||
305 | giacomo | 131 | message("Delta TSC = %10d\n",(int)dtsc); |
120 | giacomo | 132 | |
305 | giacomo | 133 | message("Delta PIT = %10d\n",delta_8253); |
120 | giacomo | 134 | |
252 | giacomo | 135 | clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000; |
120 | giacomo | 136 | |
305 | giacomo | 137 | message("Calibrated Clk_per_msec = %10d\n",clk_per_msec); |
120 | giacomo | 138 | } |
139 | |||
264 | giacomo | 140 | #define CMOS_INIT 0 |
141 | #define CMOS_BEGIN 1 |
||
142 | #define CMOS_START 2 |
||
143 | #define CMOS_END 3 |
||
144 | |||
145 | int cmos_calibrate_status = CMOS_INIT; |
||
305 | giacomo | 146 | unsigned long long irq8_start; |
147 | unsigned long long irq8_end; |
||
264 | giacomo | 148 | |
299 | giacomo | 149 | void calibrate_tsc_IRQ8(void *p) |
264 | giacomo | 150 | { |
619 | mauro | 151 | unsigned char set; |
264 | giacomo | 152 | |
619 | mauro | 153 | CMOS_READ(0x0C,set); |
264 | giacomo | 154 | |
619 | mauro | 155 | barrier(); |
156 | rdtscll(irq8_end); |
||
157 | barrier(); |
||
264 | giacomo | 158 | |
619 | mauro | 159 | if (cmos_calibrate_status == CMOS_START) { |
160 | cmos_calibrate_status = CMOS_END; |
||
161 | } |
||
264 | giacomo | 162 | |
619 | mauro | 163 | if (cmos_calibrate_status == CMOS_BEGIN) { |
164 | irq8_start = irq8_end; |
||
165 | cmos_calibrate_status = CMOS_START; |
||
166 | } |
||
264 | giacomo | 167 | |
619 | mauro | 168 | if (cmos_calibrate_status == CMOS_INIT) { |
169 | cmos_calibrate_status = CMOS_BEGIN; |
||
170 | } |
||
264 | giacomo | 171 | } |
172 | |||
173 | //TSC Calibration using RTC |
||
174 | void ll_calibrate_tsc_cmos(void) |
||
175 | { |
||
619 | mauro | 176 | unsigned long long dtsc; |
264 | giacomo | 177 | |
619 | mauro | 178 | irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE); |
264 | giacomo | 179 | |
619 | mauro | 180 | CMOS_READ(0x0A,save_CMOS_regA); |
181 | CMOS_READ(0x0B,save_CMOS_regB); |
||
182 | |||
183 | CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt |
||
184 | CMOS_WRITE(0x0B,0x42); // Enable Interrupt |
||
264 | giacomo | 185 | |
619 | mauro | 186 | irq_unmask(8); |
317 | giacomo | 187 | |
619 | mauro | 188 | sti(); |
264 | giacomo | 189 | |
619 | mauro | 190 | while (cmos_calibrate_status != CMOS_END) { |
191 | barrier(); |
||
192 | } |
||
317 | giacomo | 193 | |
619 | mauro | 194 | cli(); |
264 | giacomo | 195 | |
619 | mauro | 196 | dtsc = irq8_end - irq8_start; |
264 | giacomo | 197 | |
619 | mauro | 198 | clk_per_msec = dtsc / 500; |
199 | clk_opt_0 = (unsigned int)(dtsc); |
||
200 | clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1)); |
||
201 | clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L); |
||
202 | clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L); |
||
203 | clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L); |
||
204 | clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L); |
||
264 | giacomo | 205 | |
619 | mauro | 206 | message("Calibrated CPU Clk/msec = %10u\n",clk_per_msec); |
264 | giacomo | 207 | |
619 | mauro | 208 | #ifdef __O1000__ |
209 | if (clk_per_msec < 1000000) { |
||
210 | message("Timer Optimization CPU < 1 GHz\n"); |
||
211 | } else { |
||
212 | message("Bad Timer Optimization\n"); |
||
213 | ll_abort(66); |
||
214 | } |
||
215 | #endif |
||
329 | giacomo | 216 | |
619 | mauro | 217 | #ifdef __O2000__ |
218 | if (clk_per_msec < 2000000 && clk_per_msec >= 1000000) { |
||
219 | message("Timer Optimization 1 GHz < CPU < 2 GHz\n"); |
||
220 | } else { |
||
221 | message("Bad Timer Optimization\n"); |
||
222 | ll_abort(66); |
||
223 | } |
||
224 | #endif |
||
329 | giacomo | 225 | |
619 | mauro | 226 | #ifdef __O4000__ |
227 | if (clk_per_msec < 4000000 && clk_per_msec >= 2000000) { |
||
228 | message("Timer Optimization 2 GHz < CPU < 4 GHz\n"); |
||
229 | } else { |
||
230 | message("Bad Timer Optimization\n"); |
||
231 | ll_abort(66); |
||
232 | } |
||
233 | #endif |
||
329 | giacomo | 234 | |
619 | mauro | 235 | irq_mask(8); |
264 | giacomo | 236 | |
619 | mauro | 237 | CMOS_WRITE(0x0A,save_CMOS_regA); |
238 | CMOS_WRITE(0x0B,save_CMOS_regB); |
||
264 | giacomo | 239 | } |
240 | |||
299 | giacomo | 241 | int apic_get_maxlvt(void) |
242 | { |
||
243 | unsigned int v, ver, maxlvt; |
||
244 | |||
245 | v = apic_read(APIC_LVR); |
||
246 | ver = GET_APIC_VERSION(v); |
||
247 | /* 82489DXs do not report # of LVT entries. */ |
||
248 | maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; |
||
249 | return maxlvt; |
||
250 | } |
||
251 | |||
304 | giacomo | 252 | /* Clear local APIC, from Linux kernel */ |
299 | giacomo | 253 | void clear_local_APIC(void) |
254 | { |
||
255 | int maxlvt; |
||
256 | unsigned long v; |
||
257 | |||
258 | maxlvt = apic_get_maxlvt(); |
||
259 | |||
260 | /* |
||
261 | * Masking an LVT entry on a P6 can trigger a local APIC error |
||
262 | * if the vector is zero. Mask LVTERR first to prevent this. |
||
263 | */ |
||
264 | if (maxlvt >= 3) { |
||
265 | v = 0xFF; /* any non-zero vector will do */ |
||
266 | apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); |
||
267 | } |
||
268 | /* |
||
269 | * Careful: we have to set masks only first to deassert |
||
270 | * any level-triggered sources. |
||
271 | */ |
||
272 | v = apic_read(APIC_LVTT); |
||
273 | apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
||
274 | v = apic_read(APIC_LVT0); |
||
275 | apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); |
||
276 | v = apic_read(APIC_LVT1); |
||
277 | apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); |
||
278 | if (maxlvt >= 4) { |
||
279 | v = apic_read(APIC_LVTPC); |
||
280 | apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); |
||
281 | } |
||
282 | |||
283 | /* |
||
284 | * Clean APIC state for other OSs: |
||
285 | */ |
||
286 | apic_write_around(APIC_LVTT, APIC_LVT_MASKED); |
||
287 | apic_write_around(APIC_LVT0, APIC_LVT_MASKED); |
||
288 | apic_write_around(APIC_LVT1, APIC_LVT_MASKED); |
||
289 | if (maxlvt >= 3) |
||
290 | apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); |
||
291 | if (maxlvt >= 4) |
||
292 | apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); |
||
293 | v = GET_APIC_VERSION(apic_read(APIC_LVR)); |
||
294 | if (APIC_INTEGRATED(v)) { /* !82489DX */ |
||
295 | if (maxlvt > 3) |
||
296 | apic_write(APIC_ESR, 0); |
||
297 | apic_read(APIC_ESR); |
||
298 | } |
||
299 | } |
||
300 | |||
301 | void disable_local_APIC(void) |
||
302 | { |
||
303 | unsigned long value; |
||
304 | |||
305 | clear_local_APIC(); |
||
306 | |||
307 | /* |
||
308 | * Disable APIC (implies clearing of registers |
||
309 | * for 82489DX!). |
||
310 | */ |
||
311 | value = apic_read(APIC_SPIV); |
||
312 | value &= ~APIC_SPIV_APIC_ENABLED; |
||
313 | apic_write_around(APIC_SPIV, value); |
||
314 | } |
||
315 | |||
316 | #define SPURIOUS_APIC_VECTOR 0xFF |
||
317 | |||
318 | /* |
||
302 | giacomo | 319 | * Setup the local APIC, minimal code to run P6 APIC |
299 | giacomo | 320 | */ |
321 | void setup_local_APIC (void) |
||
322 | { |
||
301 | giacomo | 323 | unsigned long value; |
299 | giacomo | 324 | |
325 | /* Pound the ESR really hard over the head with a big hammer - mbligh */ |
||
619 | mauro | 326 | |
299 | giacomo | 327 | apic_write(APIC_ESR, 0); |
328 | apic_write(APIC_ESR, 0); |
||
329 | apic_write(APIC_ESR, 0); |
||
330 | apic_write(APIC_ESR, 0); |
||
619 | mauro | 331 | |
301 | giacomo | 332 | value = APIC_SPIV_FOCUS_DISABLED | APIC_SPIV_APIC_ENABLED | SPURIOUS_APIC_VECTOR; |
333 | apic_write_around(APIC_SPIV, value); |
||
299 | giacomo | 334 | |
619 | mauro | 335 | value = APIC_DM_EXTINT | APIC_LVT_LEVEL_TRIGGER; |
336 | apic_write_around(APIC_LVT0, value); |
||
299 | giacomo | 337 | |
619 | mauro | 338 | value = APIC_DM_NMI; |
339 | apic_write_around(APIC_LVT1, value); |
||
299 | giacomo | 340 | |
619 | mauro | 341 | apic_write(APIC_ESR, 0); |
299 | giacomo | 342 | } |
343 | |||
344 | void disable_APIC_timer(void) |
||
345 | { |
||
619 | mauro | 346 | unsigned long v; |
299 | giacomo | 347 | |
619 | mauro | 348 | v = apic_read(APIC_LVTT); |
349 | apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
||
299 | giacomo | 350 | } |
351 | |||
352 | void enable_APIC_timer(void) |
||
353 | { |
||
619 | mauro | 354 | unsigned long v; |
299 | giacomo | 355 | |
619 | mauro | 356 | v = apic_read(APIC_LVTT); |
357 | apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED); |
||
299 | giacomo | 358 | } |
359 | |||
304 | giacomo | 360 | #define LOCAL_TIMER_VECTOR 0x39 |
302 | giacomo | 361 | |
303 | giacomo | 362 | /* Set APIC Timer... from Linux kernel */ |
363 | void setup_APIC_timer() |
||
299 | giacomo | 364 | { |
619 | mauro | 365 | unsigned int lvtt1_value; |
303 | giacomo | 366 | |
619 | mauro | 367 | lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | |
368 | APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; |
||
369 | apic_write_around(APIC_LVTT, lvtt1_value); |
||
303 | giacomo | 370 | |
619 | mauro | 371 | /* |
372 | * Divide PICLK by 1 |
||
373 | */ |
||
374 | apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
||
375 | |||
376 | apic_write_around(APIC_TMICT, MAX_DWORD); |
||
377 | |||
378 | disable_APIC_timer(); |
||
299 | giacomo | 379 | } |
380 | |||
381 | #define APIC_LIMIT 0xFF000000 |
||
303 | giacomo | 382 | #define APIC_SET_LIMIT 10 |
299 | giacomo | 383 | |
384 | void ll_calibrate_apic(void) |
||
385 | { |
||
619 | mauro | 386 | unsigned int apic_start = 0, apic_end = 0, dapic; |
387 | unsigned long long tsc_start = 0, tsc_end = 0, dtsc; |
||
388 | unsigned int tmp_value; |
||
299 | giacomo | 389 | |
619 | mauro | 390 | tmp_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | LOCAL_TIMER_VECTOR; |
391 | apic_write_around(APIC_LVTT, tmp_value); |
||
299 | giacomo | 392 | |
619 | mauro | 393 | apic_write_around(APIC_TDCR, APIC_TDR_DIV_1); |
299 | giacomo | 394 | |
619 | mauro | 395 | apic_write(APIC_TMICT, MAX_DWORD); |
312 | giacomo | 396 | |
619 | mauro | 397 | enable_APIC_timer(); |
299 | giacomo | 398 | |
619 | mauro | 399 | barrier(); |
400 | rdtscll(tsc_start); |
||
401 | barrier(); |
||
402 | apic_start = apic_read(APIC_TMCCT); |
||
403 | barrier(); |
||
312 | giacomo | 404 | |
619 | mauro | 405 | while (apic_read(APIC_TMCCT) > APIC_LIMIT) { |
406 | barrier(); |
||
407 | rdtscll(tsc_end); |
||
408 | } |
||
299 | giacomo | 409 | |
619 | mauro | 410 | barrier(); |
411 | rdtscll(tsc_end); |
||
412 | barrier(); |
||
413 | apic_end = apic_read(APIC_TMCCT); |
||
414 | barrier(); |
||
299 | giacomo | 415 | |
619 | mauro | 416 | disable_APIC_timer(); |
312 | giacomo | 417 | |
619 | mauro | 418 | dtsc = tsc_end - tsc_start; |
419 | dapic = apic_start - apic_end; |
||
420 | |||
421 | apic_clk_per_msec = (unsigned long long)(clk_per_msec) * (unsigned long long)(dapic) / dtsc; |
||
422 | apic_set_limit = ((apic_clk_per_msec / 100) != 0) ? (apic_clk_per_msec/100) : APIC_SET_LIMIT; |
||
299 | giacomo | 423 | |
619 | mauro | 424 | message("Calibrated APIC Clk/msec = %10d\n",apic_clk_per_msec); |
299 | giacomo | 425 | } |
426 | |||
120 | giacomo | 427 | void ll_init_advtimer() |
428 | { |
||
429 | |||
649 | mauro | 430 | #ifdef __TSC__ |
431 | use_tsc = X86_tsc; |
||
432 | |||
619 | mauro | 433 | #ifdef __APIC__ |
434 | use_apic = X86_apic; |
||
435 | #endif |
||
436 | |||
437 | #endif |
||
438 | |||
650 | giacomo | 439 | if (use_tsc == 0) use_apic = 0; |
440 | |||
619 | mauro | 441 | if (use_tsc) { |
120 | giacomo | 442 | |
619 | mauro | 443 | #ifdef CALIBRATE_USING_CMOS |
444 | ll_calibrate_tsc_cmos(); |
||
445 | #else |
||
446 | ll_calibrate_tsc(); |
||
447 | #endif |
||
264 | giacomo | 448 | |
619 | mauro | 449 | rdtscll(init_tsc); // Read start TSC |
648 | mauro | 450 | init_time.tv_sec = 0; |
451 | init_time.tv_nsec = 0; |
||
120 | giacomo | 452 | |
619 | mauro | 453 | if (use_apic) { |
651 | mauro | 454 | rdmsr(APIC_BASE_MSR, msr_original_low, msr_original_high); |
455 | wrmsr(APIC_BASE_MSR, msr_original_low|(1<<11), 0); |
||
299 | giacomo | 456 | |
619 | mauro | 457 | clear_local_APIC(); |
299 | giacomo | 458 | |
619 | mauro | 459 | ll_calibrate_apic(); |
299 | giacomo | 460 | |
619 | mauro | 461 | setup_local_APIC(); |
303 | giacomo | 462 | |
619 | mauro | 463 | setup_APIC_timer(); |
464 | } |
||
465 | } |
||
120 | giacomo | 466 | } |
467 | |||
301 | giacomo | 468 | void ll_restore_adv() |
120 | giacomo | 469 | { |
646 | mauro | 470 | SYS_FLAGS f; |
471 | |||
472 | /* Disable APIC */ |
||
619 | mauro | 473 | if (use_apic) { |
301 | giacomo | 474 | |
646 | mauro | 475 | f = ll_fsave(); |
301 | giacomo | 476 | |
646 | mauro | 477 | disable_APIC_timer(); |
301 | giacomo | 478 | |
651 | mauro | 479 | wrmsr(APIC_BASE_MSR, msr_original_low, msr_original_high); |
301 | giacomo | 480 | |
646 | mauro | 481 | ll_frestore(f); |
619 | mauro | 482 | } |
120 | giacomo | 483 | } |
646 | mauro | 484 | |
485 | void ll_scale_advtimer(unsigned int old_f, unsigned int new_f) |
||
486 | { |
||
487 | unsigned long long dtsc; |
||
488 | unsigned long temp; |
||
652 | mauro | 489 | struct timespec temp_time; |
646 | mauro | 490 | SYS_FLAGS f; |
491 | |||
648 | mauro | 492 | if (use_tsc) { |
493 | f = ll_fsave(); |
||
646 | mauro | 494 | |
652 | mauro | 495 | __asm__("cpuid"::"a" (0), "b" (0), "c" (0), "d" (0)); |
496 | ll_read_timespec(&temp_time); // Set new start TimeSpec |
||
497 | TIMESPEC_ASSIGN(&init_time,&temp_time); |
||
648 | mauro | 498 | rdtscll(init_tsc); // Set new start TSC |
652 | mauro | 499 | __asm__("cpuid"::"a" (0), "b" (0), "c" (0), "d" (0)); |
500 | |||
648 | mauro | 501 | mul32div32to32(clk_per_msec,new_f,old_f,temp); |
502 | clk_per_msec = temp; |
||
503 | dtsc = (unsigned long long)(clk_per_msec) * 500; |
||
504 | clk_opt_0 = (unsigned int)(dtsc); |
||
505 | clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1)); |
||
506 | clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L); |
||
507 | clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L); |
||
508 | clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L); |
||
509 | clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L); |
||
652 | mauro | 510 | |
648 | mauro | 511 | ll_frestore(f); |
512 | } |
||
646 | mauro | 513 | } |