97627879e6c276faec9ff8067f35ba2c1ff93208
[akaros.git] / kern / arch / x86 / time.c
1 /* Copyright (c) 2009 The Regents of the University of California
2  * David (Yu) Zhu <yuzhu@cs.berkeley.edu>
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  *
5  * See LICENSE for details. */
6
7 #include <arch/x86.h>
8 #include <arch/arch.h>
9 #include <arch/pic.h>
10 #include <arch/apic.h>
11 #include <time.h>
12 #include <assert.h>
13 #include <stdio.h>
14
15 system_timing_t system_timing = {0, 0, 0xffff, 0};
16
17 // timer init calibrates both tsc timer and lapic timer using PIT
18 void timer_init(void){
19         /* some boards have this unmasked early on. */
20         pic_mask_irq(0 + PIC1_OFFSET);
21         uint64_t tscval[2];
22         long timercount[2];
23         pit_set_timer(0xffff, TIMER_RATEGEN);
24         // assume tsc exist
25         tscval[0] = read_tsc();
26         udelay_pit(1000000);
27         tscval[1] = read_tsc();
28         system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
29         cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
30         __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
31                           LAPIC_TIMER_DIVISOR_BITS);
32         // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
33         mask_lapic_lvt(LAPIC_LVT_TIMER);
34         timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
35         udelay_pit(1000000);
36         timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
37         system_timing.bus_freq = (timercount[0] - timercount[1])
38                                  * LAPIC_TIMER_DIVISOR_VAL;
39         /* The time base for the timer is derived from the processor's bus clock,
40          * divided by the value specified in the divide configuration register.
41          * Note we mult and div by the divisor, saving the actual freq (even though
42          * we don't use it yet). */
43         cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
44 }
45
46 void pit_set_timer(uint32_t divisor, uint32_t mode)
47 {
48         if (divisor & 0xffff0000)
49                 warn("Divisor too large!");
50         mode = TIMER_SEL0|TIMER_16BIT|mode;
51         outb(TIMER_MODE, mode); 
52         outb(TIMER_CNTR0, divisor & 0xff);
53         outb(TIMER_CNTR0, (divisor >> 8) );
54         system_timing.pit_mode = SINIT(mode);
55         system_timing.pit_divisor = SINIT(divisor);
56         // cprintf("timer mode set to %d, divisor %d\n",mode, divisor);
57 }
58
59 static int getpit()
60 {
61     int high, low;
62         // TODO: need a lock to protect access to PIT
63
64     /* Select counter 0 and latch counter value. */
65     outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
66     
67     low = inb(TIMER_CNTR0);
68     high = inb(TIMER_CNTR0);
69
70     return ((high << 8) | low);
71 }
72
73 // forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
74 void udelay(uint64_t usec)
75 {
76         #if !defined(__BOCHS__)
77         if (system_timing.tsc_freq != 0)
78         {
79                 uint64_t start, end, now;
80
81                 start = read_tsc();
82         end = start + usec2tsc(usec);
83         //cprintf("start %llu, end %llu\n", start, end);
84                 if (end == 0) cprintf("This is terribly wrong \n");
85                 do {
86             cpu_relax();
87             now = read_tsc();
88                         //cprintf("now %llu\n", now);
89                 } while (now < end || (now > start && end < start));
90         return;
91
92         } else
93         #endif
94         {
95                 udelay_pit(usec);
96         }
97 }
98
99 void udelay_pit(uint64_t usec)
100 {
101         int64_t delta, prev_tick, tick, ticks_left;
102         prev_tick = getpit();
103         /*
104          * Calculate (n * (i8254_freq / 1e6)) without using floating point
105          * and without any avoidable overflows.
106          */
107         if (usec <= 0)
108                 ticks_left = 0;
109         // some optimization from bsd code
110         else if (usec < 256)
111                 /*
112                  * Use fixed point to avoid a slow division by 1000000.
113                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
114                  * 2^15 is the first power of 2 that gives exact results
115                  * for n between 0 and 256.
116                  */
117                 ticks_left = ((uint64_t)usec * 39099 + (1 << 15) - 1) >> 15;
118         else
119                 // round up the ticks left
120                 ticks_left = ((uint64_t)usec * (long long)PIT_FREQ+ 999999)
121                              / 1000000; 
122         while (ticks_left > 0) {
123                 tick = getpit();
124                 delta = prev_tick - tick;
125                 prev_tick = tick;
126                 if (delta < 0) {
127                         // counter looped around during the delta time period
128                         delta += system_timing.pit_divisor; // maximum count 
129                         if (delta < 0)
130                                 delta = 0;
131                 }
132                 ticks_left -= delta;
133         }
134 }
135
136 uint64_t gettimer(void)
137 {
138         return read_tsc();      
139 }
140
141 uint64_t getfreq(void)
142 {
143         return system_timing.tsc_freq;
144 }
145
146 void set_core_timer(uint32_t usec, bool periodic)
147 {
148         if (usec)
149                 lapic_set_timer(usec, periodic);
150         else
151                 lapic_disable_timer();
152 }