2 #include "../port/lib.h"
13 T0cntr= 0x40, /* counter ports */
14 T1cntr= 0x41, /* ... */
15 T2cntr= 0x42, /* ... */
16 Tmode= 0x43, /* mode port (control word register) */
17 T2ctl= 0x61, /* counter 2 control port */
20 Latch0= 0x00, /* latch counter 0's value */
21 Load0l= 0x10, /* load counter 0's lsb */
22 Load0m= 0x20, /* load counter 0's msb */
23 Load0= 0x30, /* load counter 0 with 2 bytes */
25 Latch1= 0x40, /* latch counter 1's value */
26 Load1l= 0x50, /* load counter 1's lsb */
27 Load1m= 0x60, /* load counter 1's msb */
28 Load1= 0x70, /* load counter 1 with 2 bytes */
30 Latch2= 0x80, /* latch counter 2's value */
31 Load2l= 0x90, /* load counter 2's lsb */
32 Load2m= 0xa0, /* load counter 2's msb */
33 Load2= 0xb0, /* load counter 2 with 2 bytes */
35 /* 8254 read-back command: everything > pc-at has an 8254 */
36 Rdback= 0xc0, /* readback counters & status */
37 Rdnstat=0x10, /* don't read status */
38 Rdncnt= 0x20, /* don't read counter value */
39 Rd0cntr=0x02, /* read back for which counter */
45 Square= 0x6, /* periodic square wave */
46 Trigger=0x0, /* interrupt on terminal count */
47 Sstrobe=0x8, /* software triggered strobe */
50 T2gate= (1<<0), /* enable T2 counting */
51 T2spkr= (1<<1), /* connect T2 out to speaker */
52 T2out= (1<<5), /* output of T2 */
54 Freq= 1193182, /* Real clock frequency */
55 Tickshift=8, /* extra accuracy */
57 MinPeriod=Freq/(100*HZ),
60 typedef struct I8253 I8253;
64 ulong period; /* current clock period */
66 ushort last; /* last value of clock 1 */
67 uvlong ticks; /* cumulative ticks of counter 1 */
81 i8253.period = Freq/HZ;
84 * enable a 1/HZ interrupt for providing scheduling interrupts
86 outb(Tmode, Load0|Square);
87 outb(T0cntr, (Freq/HZ)); /* low byte */
88 outb(T0cntr, (Freq/HZ)>>8); /* high byte */
91 * enable a longer period counter to use as a clock
93 outb(Tmode, Load2|Square);
94 outb(T2cntr, 0); /* low byte */
95 outb(T2cntr, 0); /* high byte */
101 * Introduce a little delay to make sure the count is
102 * latched and the timer is counting down; with a fast
103 * enough processor this may not be the case.
104 * The i8254 (which this probably is) has a read-back
105 * command which can be used to make sure the counting
106 * register has been written into the counting element.
109 for(loops = 0; loops < 100000 && x >= (Freq/HZ); loops++){
121 ioalloc(T0cntr, 4, 0, "i8253");
122 ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
128 guesscpuhz(int aalcycles)
131 uvlong a, b, cpufreq;
134 for(loops = 1000;;loops += 1000) {
136 * measure time for the loop
142 * the time for the loop should be independent of external
143 * cache and memory system since it fits in the execution
161 if(x >= MaxPeriod || loops >= 1000000)
166 /* avoid division by zero on vmware 7 */
171 * figure out clock frequency and a loop multiplier for delay().
172 * n.b. counter goes up by 2*Freq
174 cpufreq = (vlong)loops*((aalcycles*2*Freq)/x);
175 m->loopconst = (cpufreq/1000)/aalcycles; /* AAM+LOOP's for 1 ms */
177 /* a == b means virtualbox has confused us */
178 if(m->havetsc && b > a){
188 * round to the nearest megahz
190 m->cpumhz = (cpufreq+500000)/1000000L;
196 i8253timerset(uvlong next)
204 want = next>>Tickshift;
205 now = i8253.ticks; /* assuming whomever called us just did fastticks() */
208 if(period < MinPeriod)
210 else if(period > MaxPeriod)
215 if(i8253.period != period){
218 outb(Tmode, Load0|Square);
219 outb(T0cntr, period); /* low byte */
220 outb(T0cntr, period >> 8); /* high byte */
222 /* remember period */
223 i8253.period = period;
230 i8253clock(Ureg* ureg, void*)
238 intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
242 * return the total ticks of counter 2. We shift by
243 * 8 to give timesync more wriggle room for interpretation
247 i8253read(uvlong *hz)
253 *hz = Freq<<Tickshift;
263 x = i8253.last + (0x10000 - y);
264 if (x > 3*MaxPeriod) {
265 outb(Tmode, Load2|Square);
266 outb(T2cntr, 0); /* low byte */
267 outb(T2cntr, 0); /* high byte */
277 return ticks<<Tickshift;
283 millisecs *= m->loopconst;
290 microdelay(int microsecs)
292 microsecs *= m->loopconst;
300 * performance measurement ticks. must be low overhead.
301 * doesn't have to count over a second.