Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / arch / x86_64 / kernel / time.c
1 #include <lwk/kernel.h>
2 #include <lwk/init.h>
3 #include <lwk/spinlock.h>
4 #include <lwk/cpuinfo.h>
5 #include <lwk/smp.h>
6 #include <lwk/time.h>
7 #include <arch/io.h>
8 #include <arch/apic.h>
9
10 #ifdef CONFIG_PC
11 /**
12  * Lock that synchronizes access to the Programmable Interval Timer.
13  */
14 static DEFINE_SPINLOCK(pit_lock);
15
16 /**
17  * This stops the Programmable Interval Timer's periodic system timer
18  * (channel 0). Some systems, BOCHS included, are booted with the PIT system
19  * timer enabled. The LWK doesn't use the PIT, so this function is used during
20  * bootstrap to disable it.
21  */
22 static void __init
23 pit_stop_timer0(void)
24 {
25         unsigned long flags;
26         unsigned PIT_MODE = 0x43;
27         unsigned PIT_CH0  = 0x40;
28
29         spin_lock_irqsave(&pit_lock, flags);
30         outb_p(0x30, PIT_MODE);         /* mode 0 */
31         outb_p(0, PIT_CH0);             /* LSB system timer interval */
32         outb_p(0, PIT_CH0);             /* MSB system timer interval */
33         spin_unlock_irqrestore(&pit_lock, flags);
34 }
35
36 /**
37  * This uses the Programmable Interval Timer that is standard on all
38  * PC-compatible systems to determine the time stamp counter frequency.
39  *
40  * This uses the speaker output (channel 2) of the PIT. This is better than
41  * using the timer interrupt output because we can read the value of the
42  * speaker with just one inb(), where we need three i/o operations for the
43  * interrupt channel. We count how many ticks the TSC does in 50 ms.
44  *
45  * Returns the detected time stamp counter frequency in KHz.
46  */
47 static unsigned int __init
48 pit_calibrate_tsc(void)
49 {
50         cycles_t start, end;
51         unsigned long flags;
52         unsigned long pit_tick_rate = 1193182UL;  /* 1.193182 MHz */
53
54         spin_lock_irqsave(&pit_lock, flags);
55
56         outb((inb(0x61) & ~0x02) | 0x01, 0x61);
57
58         outb(0xb0, 0x43);
59         outb((pit_tick_rate / (1000 / 50)) & 0xff, 0x42);
60         outb((pit_tick_rate / (1000 / 50)) >> 8, 0x42);
61         start = get_cycles_sync();
62         while ((inb(0x61) & 0x20) == 0);
63         end = get_cycles_sync();
64
65         spin_unlock_irqrestore(&pit_lock, flags);
66         
67         return (end - start) / 50;
68 }
69 #endif
70
71 #ifdef CONFIG_CRAY_XT
72 /**
73  * The Cray XT platform does not have any real time clocks. Therefore,
74  * we have to inspect various MSRs to determine the CPU frequency and
75  * trust that it is accurate.
76  *
77  * Returns the detected CPU frequency in KHz.
78  *
79  * NOTE: This function should only be used on Cray XT3/XT4/XT? platforms.
80  *       While it will work on (some) AMD Opteron K8 and K10 systems, using a
81  *       timer based mechanism to detect the actual CPU frequency is preferred.
82  */
83 static unsigned int __init
84 crayxt_detect_cpu_freq(void)
85 {
86         unsigned int MHz = 200;
87         unsigned int lower, upper;
88         int amd_family = cpu_info[this_cpu].arch.x86_family;
89         int amd_model  = cpu_info[this_cpu].arch.x86_model;
90
91         if (amd_family == 16) {
92                 unsigned int fid; /* current frequency id */
93                 unsigned int did; /* current divide id */
94
95                 rdmsr(MSR_K10_COFVID_STATUS, lower, upper);
96                 fid = lower & 0x3f;
97                 did = (lower >> 6) & 0x3f;
98                 MHz = 100 * (fid + 0x10) / (1 << did);
99
100         } else if (amd_family == 15) {
101                 unsigned int fid; /* current frequency id */
102
103                 if (amd_model < 16) {
104                         /* Revision C and earlier */
105                         rdmsr(MSR_K8_HWCR, lower, upper);
106                         fid = (lower >> 24) & 0x3f;
107                 } else {
108                         /* Revision D and later */
109                         rdmsr(MSR_K8_FIDVID_STATUS, lower, upper);
110                         fid = lower & 0x3f;
111                 }
112
113                 switch (fid) {
114                         case 0:   MHz *= 4; break;
115                         case 2:   MHz *= 5; break;
116                         case 4:   MHz *= 6; break;
117                         case 6:   MHz *= 7; break;
118                         case 8:   MHz *= 8; break;
119                         case 10:  MHz *= 9; break;
120                         case 12:  MHz *= 10; break;
121                         case 14:  MHz *= 11; break;
122                         case 16:  MHz *= 12; break;
123                         case 18:  MHz *= 13; break;
124                         case 20:  MHz *= 14; break;
125                         case 22:  MHz *= 15; break;
126                         case 24:  MHz *= 16; break;
127                         case 26:  MHz *= 17; break;
128                         case 28:  MHz *= 18; break;
129                         case 30:  MHz *= 19; break;
130                         case 32:  MHz *= 20; break;
131                         case 34:  MHz *= 21; break;
132                         case 36:  MHz *= 22; break;
133                         case 38:  MHz *= 23; break;
134                         case 40:  MHz *= 24; break;
135                         case 42:  MHz *= 25; break;
136                 }
137         } else {
138                 panic("Unknown AMD CPU family (%d).", amd_family);
139         }
140
141         return (MHz * 1000); /* return CPU freq. in KHz */
142 }
143 #endif
144
145 void __init
146 time_init(void)
147 {
148         unsigned int cpu_khz;
149         unsigned int lapic_khz;
150
151         /*
152          * Detect the CPU frequency
153          */
154 #if defined CONFIG_PC
155         cpu_khz = pit_calibrate_tsc();
156         pit_stop_timer0();
157 #elif defined CONFIG_CRAY_XT
158         cpu_khz = crayxt_detect_cpu_freq();
159 #else
160         #error "In time_init(), unknown system architecture."
161 #endif
162
163         cpu_info[this_cpu].arch.cur_cpu_khz = cpu_khz;
164         cpu_info[this_cpu].arch.max_cpu_khz = cpu_khz;
165         cpu_info[this_cpu].arch.min_cpu_khz = cpu_khz;
166         cpu_info[this_cpu].arch.tsc_khz     = cpu_khz;
167
168         init_cycles2ns(cpu_khz);
169
170         /*
171          * Detect the Local APIC timer's base clock frequency
172          */
173         if (this_cpu == 0) {
174                 lapic_khz = lapic_calibrate_timer();
175         } else {
176                 lapic_khz = cpu_info[0].arch.lapic_khz;
177         }
178
179         cpu_info[this_cpu].arch.lapic_khz   = lapic_khz;
180
181         printk(KERN_DEBUG "CPU %u: %u.%03u MHz, LAPIC bus %u.%03u MHz\n",
182                 this_cpu,
183                 cpu_khz / 1000, cpu_khz % 1000,
184                 lapic_khz / 1000, lapic_khz % 1000
185         );
186 }
187