1 #include <lwk/kernel.h>
3 #include <lwk/spinlock.h>
4 #include <lwk/cpuinfo.h>
12 * Lock that synchronizes access to the Programmable Interval Timer.
14 static DEFINE_SPINLOCK(pit_lock);
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.
26 unsigned PIT_MODE = 0x43;
27 unsigned PIT_CH0 = 0x40;
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);
37 * This uses the Programmable Interval Timer that is standard on all
38 * PC-compatible systems to determine the time stamp counter frequency.
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.
45 * Returns the detected time stamp counter frequency in KHz.
47 static unsigned int __init
48 pit_calibrate_tsc(void)
52 unsigned long pit_tick_rate = 1193182UL; /* 1.193182 MHz */
54 spin_lock_irqsave(&pit_lock, flags);
56 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
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();
65 spin_unlock_irqrestore(&pit_lock, flags);
67 return (end - start) / 50;
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.
77 * Returns the detected CPU frequency in KHz.
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.
83 static unsigned int __init
84 crayxt_detect_cpu_freq(void)
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;
91 if (amd_family == 16) {
92 unsigned int fid; /* current frequency id */
93 unsigned int did; /* current divide id */
95 rdmsr(MSR_K10_COFVID_STATUS, lower, upper);
97 did = (lower >> 6) & 0x3f;
98 MHz = 100 * (fid + 0x10) / (1 << did);
100 } else if (amd_family == 15) {
101 unsigned int fid; /* current frequency id */
103 if (amd_model < 16) {
104 /* Revision C and earlier */
105 rdmsr(MSR_K8_HWCR, lower, upper);
106 fid = (lower >> 24) & 0x3f;
108 /* Revision D and later */
109 rdmsr(MSR_K8_FIDVID_STATUS, lower, upper);
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;
138 panic("Unknown AMD CPU family (%d).", amd_family);
141 return (MHz * 1000); /* return CPU freq. in KHz */
148 unsigned int cpu_khz;
149 unsigned int lapic_khz;
152 * Detect the CPU frequency
154 #if defined CONFIG_PC
155 cpu_khz = pit_calibrate_tsc();
157 #elif defined CONFIG_CRAY_XT
158 cpu_khz = crayxt_detect_cpu_freq();
160 #error "In time_init(), unknown system architecture."
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;
168 init_cycles2ns(cpu_khz);
171 * Detect the Local APIC timer's base clock frequency
174 lapic_khz = lapic_calibrate_timer();
176 lapic_khz = cpu_info[0].arch.lapic_khz;
179 cpu_info[this_cpu].arch.lapic_khz = lapic_khz;
181 printk(KERN_DEBUG "CPU %u: %u.%03u MHz, LAPIC bus %u.%03u MHz\n",
183 cpu_khz / 1000, cpu_khz % 1000,
184 lapic_khz / 1000, lapic_khz % 1000