This source file includes following definitions.
- lapic_map
- lapic_enable
- lapic_set_softvectors
- lapic_set_lvt
- lapic_boot_init
- lapic_gettick
- lapic_clockintr
- lapic_initclocks
- lapic_calibrate_timer
- lapic_delay
- i386_ipi_microset
- lapic_microtime
- i386_ipi_init
- i386_ipi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #include <sys/param.h>
43 #include <sys/proc.h>
44 #include <sys/user.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/timetc.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <machine/cpu.h>
52 #include <machine/cpufunc.h>
53 #include <machine/cpuvar.h>
54 #include <machine/pmap.h>
55 #include <machine/vmparam.h>
56 #include <machine/mpbiosvar.h>
57 #include <machine/pcb.h>
58 #include <machine/specialreg.h>
59 #include <machine/segments.h>
60
61 #include <machine/apicvar.h>
62 #include <machine/i82489reg.h>
63 #include <machine/i82489var.h>
64 #include <machine/pctr.h>
65
66 #include <dev/ic/i8253reg.h>
67
68 struct evcount clk_count;
69 struct evcount ipi_count;
70
71 void lapic_delay(int);
72 void lapic_microtime(struct timeval *);
73 static __inline u_int32_t lapic_gettick(void);
74 void lapic_clockintr(void *);
75 void lapic_initclocks(void);
76 void lapic_map(paddr_t);
77
78 void
79 lapic_map(lapic_base)
80 paddr_t lapic_base;
81 {
82 int s;
83 pt_entry_t *pte;
84 vaddr_t va = (vaddr_t)&local_apic;
85
86 disable_intr();
87 s = lapic_tpr;
88
89
90
91
92
93
94
95
96
97
98 pte = kvtopte(va);
99 *pte = lapic_base | PG_RW | PG_V | PG_N;
100 invlpg(va);
101
102 #ifdef MULTIPROCESSOR
103 cpu_init_first();
104 #endif
105
106 lapic_tpr = s;
107 enable_intr();
108 }
109
110
111
112
113 void
114 lapic_enable()
115 {
116 i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR);
117 }
118
119 void
120 lapic_set_softvectors()
121 {
122 idt_vec_set(LAPIC_SOFTCLOCK_VECTOR, Xintrsoftclock);
123 idt_vec_set(LAPIC_SOFTNET_VECTOR, Xintrsoftnet);
124 idt_vec_set(LAPIC_SOFTTTY_VECTOR, Xintrsofttty);
125 idt_vec_set(LAPIC_SOFTAST_VECTOR, Xintrsoftast);
126 }
127
128 void
129 lapic_set_lvt()
130 {
131 struct cpu_info *ci = curcpu();
132 int i;
133 struct mp_intr_map *mpi;
134
135 #ifdef MULTIPROCESSOR
136 if (mp_verbose) {
137 apic_format_redir(ci->ci_dev.dv_xname, "prelint", 0, 0,
138 i82489_readreg(LAPIC_LVINT0));
139 apic_format_redir(ci->ci_dev.dv_xname, "prelint", 1, 0,
140 i82489_readreg(LAPIC_LVINT1));
141 }
142 #endif
143
144 for (i = 0; i < mp_nintrs; i++) {
145 mpi = &mp_intrs[i];
146 if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS
147 || mpi->cpu_id == ci->ci_apicid)) {
148 #ifdef DIAGNOSTIC
149 if (mpi->ioapic_pin > 1)
150 panic("lapic_set_lvt: bad pin value %d",
151 mpi->ioapic_pin);
152 #endif
153 if (mpi->ioapic_pin == 0)
154 i82489_writereg(LAPIC_LVINT0, mpi->redir);
155 else
156 i82489_writereg(LAPIC_LVINT1, mpi->redir);
157 }
158 }
159
160 #ifdef MULTIPROCESSOR
161 if (mp_verbose) {
162 apic_format_redir(ci->ci_dev.dv_xname, "timer", 0, 0,
163 i82489_readreg(LAPIC_LVTT));
164 apic_format_redir(ci->ci_dev.dv_xname, "pcint", 0, 0,
165 i82489_readreg(LAPIC_PCINT));
166 apic_format_redir(ci->ci_dev.dv_xname, "lint", 0, 0,
167 i82489_readreg(LAPIC_LVINT0));
168 apic_format_redir(ci->ci_dev.dv_xname, "lint", 1, 0,
169 i82489_readreg(LAPIC_LVINT1));
170 apic_format_redir(ci->ci_dev.dv_xname, "err", 0, 0,
171 i82489_readreg(LAPIC_LVERR));
172 }
173 #endif
174 }
175
176
177
178
179 void
180 lapic_boot_init(paddr_t lapic_base)
181 {
182 static int clk_irq = 0;
183 static int ipi_irq = 0;
184
185 lapic_map(lapic_base);
186
187 #ifdef MULTIPROCESSOR
188 idt_vec_set(LAPIC_IPI_VECTOR, Xintripi);
189 idt_vec_set(LAPIC_IPI_AST, Xintripi_ast);
190 idt_vec_set(LAPIC_IPI_INVLTLB, Xintripi_invltlb);
191 idt_vec_set(LAPIC_IPI_INVLPG, Xintripi_invlpg);
192 idt_vec_set(LAPIC_IPI_INVLRANGE, Xintripi_invlrange);
193 #endif
194 idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious);
195 idt_vec_set(LAPIC_TIMER_VECTOR, Xintrltimer);
196
197 evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
198 evcount_attach(&ipi_count, "ipi", (void *)&ipi_irq, &evcount_intr);
199 }
200
201 static __inline u_int32_t
202 lapic_gettick()
203 {
204 return (i82489_readreg(LAPIC_CCR_TIMER));
205 }
206
207 #include <sys/kernel.h>
208
209 u_int32_t lapic_tval;
210
211
212
213
214 u_int32_t lapic_per_second;
215 u_int32_t lapic_frac_usec_per_cycle;
216 u_int64_t lapic_frac_cycle_per_usec;
217 u_int32_t lapic_delaytab[26];
218 u_int64_t scaled_pentium_mhz;
219
220 void
221 lapic_clockintr(arg)
222 void *arg;
223 {
224 struct cpu_info *ci = curcpu();
225 struct clockframe *frame = arg;
226
227 if (CPU_IS_PRIMARY(ci)) {
228 ci->ci_tscbase = rdtsc();
229 i386_broadcast_ipi(I386_IPI_MICROSET);
230 }
231 hardclock(frame);
232
233 clk_count.ec_count++;
234 }
235
236 void
237 lapic_initclocks()
238 {
239
240
241
242
243
244
245
246 i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M);
247 i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
248 i82489_writereg(LAPIC_ICR_TIMER, lapic_tval);
249 i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR);
250 }
251
252 extern int gettick(void);
253 extern void (*initclock_func)(void);
254
255
256
257
258
259
260
261
262
263
264
265
266 void
267 lapic_calibrate_timer(struct cpu_info *ci)
268 {
269 unsigned int starttick, tick1, tick2, endtick;
270 unsigned int startapic, apic1, apic2, endapic;
271 u_int64_t dtick, dapic, tmp;
272 int i;
273 char tbuf[9];
274
275 if (mp_verbose)
276 printf("%s: calibrating local timer\n", ci->ci_dev.dv_xname);
277
278
279
280
281
282 i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_M);
283 i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
284 i82489_writereg(LAPIC_ICR_TIMER, 0x80000000);
285
286 starttick = gettick();
287 startapic = lapic_gettick();
288
289 DELAY(2);
290
291 for (i=0; i<hz; i++) {
292 do {
293 tick1 = gettick();
294 apic1 = lapic_gettick();
295 } while (tick1 < starttick);
296
297 do {
298 tick2 = gettick();
299 apic2 = lapic_gettick();
300 } while (tick2 > starttick);
301 }
302
303 endtick = gettick();
304 endapic = lapic_gettick();
305
306 dtick = hz * TIMER_DIV(hz) + (starttick-endtick);
307 dapic = startapic-endapic;
308
309
310
311
312
313 tmp = (TIMER_FREQ * dapic) / dtick;
314
315 lapic_per_second = tmp;
316
317 #if 0
318 humanize_number(tbuf, sizeof(tbuf), tmp, "Hz", 1000);
319 #else
320 {
321
322 static const char prefixes[] = " KMGTPE";
323
324 int i;
325 u_int64_t max;
326 size_t suffixlen;
327
328 if (tbuf == NULL)
329 goto out;
330 if (sizeof(tbuf) > 0)
331 tbuf[0] = '\0';
332 suffixlen = sizeof "Hz" - 1;
333
334 if (sizeof(tbuf) < 4 + suffixlen)
335 goto out;
336
337 max = 1;
338 for (i = 0; i < sizeof(tbuf) - suffixlen - 3; i++)
339 max *= 10;
340 for (i = 0; tmp >= max && i < sizeof(prefixes); i++)
341 tmp /= 1000;
342
343 snprintf(tbuf, sizeof(tbuf), "%qu%s%c%s",
344 (unsigned long long)tmp, i == 0 ? "" : " ", prefixes[i],
345 "Hz");
346 out:
347 ;
348 }
349 #endif
350
351 printf("%s: apic clock running at %s\n", ci->ci_dev.dv_xname, tbuf);
352
353 if (lapic_per_second != 0) {
354
355
356
357
358 lapic_tval = (lapic_per_second * 2) / hz;
359 lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1);
360
361 i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM | LAPIC_LVTT_M |
362 LAPIC_TIMER_VECTOR);
363 i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
364 i82489_writereg(LAPIC_ICR_TIMER, lapic_tval);
365
366
367
368
369
370
371
372 tmp = (1000000 * (u_int64_t)1 << 32) / lapic_per_second;
373 lapic_frac_usec_per_cycle = tmp;
374
375 tmp = (lapic_per_second * (u_int64_t)1 << 32) / 1000000;
376
377 lapic_frac_cycle_per_usec = tmp;
378
379 scaled_pentium_mhz = (1ULL << 32) / cpuspeed;
380
381
382
383
384 for (i = 0; i < 26; i++)
385 lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >>
386 32;
387
388
389
390
391
392 delay_func = lapic_delay;
393 initclock_func = lapic_initclocks;
394 }
395 }
396
397
398
399
400
401 void
402 lapic_delay(int usec)
403 {
404 int32_t tick, otick;
405 int64_t deltat;
406
407 otick = lapic_gettick();
408
409 if (usec <= 0)
410 return;
411 if (usec <= 25)
412 deltat = lapic_delaytab[usec];
413 else
414 deltat = (lapic_frac_cycle_per_usec * usec) >> 32;
415
416 while (deltat > 0) {
417 tick = lapic_gettick();
418 if (tick > otick)
419 deltat -= lapic_tval - (tick - otick);
420 else
421 deltat -= otick - tick;
422 otick = tick;
423 }
424 }
425
426 #define LAPIC_TICK_THRESH 200
427
428
429
430
431 void
432 i386_ipi_microset(struct cpu_info *ci)
433 {
434 ci->ci_tscbase = rdtsc();
435 }
436
437 #if 0
438
439
440
441 void
442 lapic_microtime(tv)
443 struct timeval *tv;
444 {
445 struct cpu_info *ci = curcpu();
446 struct timeval now;
447 u_int64_t tmp;
448
449 disable_intr();
450 now = time;
451 tmp = rdtsc() - ci->ci_tscbase;
452 enable_intr();
453
454 now.tv_usec += (tmp * scaled_pentium_mhz) >> 32;
455
456 while (now.tv_usec >= 1000000) {
457 now.tv_sec += 1;
458 now.tv_usec -= 1000000;
459 }
460
461 *tv = now;
462 }
463 #endif
464
465
466
467
468
469 int
470 i386_ipi_init(target)
471 int target;
472 {
473 unsigned j;
474
475 if ((target & LAPIC_DEST_MASK) == 0)
476 i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
477
478 i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
479 LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT );
480
481 for (j = 100000; j > 0; j--) {
482 __asm __volatile("pause": : :"memory");
483 if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0)
484 break;
485 }
486
487 delay(10000);
488
489 i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
490 LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT);
491
492 for (j = 100000; j > 0; j--) {
493 __asm __volatile("pause": : :"memory");
494 if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0)
495 break;
496 }
497
498 return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY)?EBUSY:0;
499 }
500
501 int
502 i386_ipi(vec,target,dl)
503 int vec,target,dl;
504 {
505 unsigned j;
506
507 if ((target & LAPIC_DEST_MASK) == 0)
508 i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
509
510 i82489_writereg(LAPIC_ICRLO,
511 (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT);
512
513 for (j = 100000;
514 j > 0 && (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY);
515 j--)
516 SPINLOCK_SPIN_HOOK;
517
518 return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0;
519 }