1 /* $OpenBSD: lapic.c,v 1.74 2024/11/07 17:24:42 bluhm Exp $ */
2 /* $NetBSD: lapic.c,v 1.2 2003/05/08 01:04:35 fvdl Exp $ */
3
4 /*-
5 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by RedBack Networks Inc.
10 *
11 * Author: Bill Sommerfeld
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/atomic.h>
38 #include <sys/clockintr.h>
39 #include <sys/device.h>
40
41 #include <uvm/uvm_extern.h>
42
43 #include <machine/codepatch.h>
44 #include <machine/cpu.h>
45 #include <machine/cpufunc.h>
46 #include <machine/pmap.h>
47 #include <machine/mpbiosvar.h>
48 #include <machine/specialreg.h>
49 #include <machine/segments.h>
50
51 #include <machine/i82489reg.h>
52 #include <machine/i82489var.h>
53
54 #include <dev/ic/i8253reg.h>
55
56 #include "ioapic.h"
57 #include "xen.h"
58 #include "hyperv.h"
59 #include "vmm.h"
60
61 #if NIOAPIC > 0
62 #include <machine/i82093var.h>
63 #endif
64
65 /* #define LAPIC_DEBUG */
66
67 #ifdef LAPIC_DEBUG
68 #define DPRINTF(x...) do { printf(x); } while(0)
69 #else
70 #define DPRINTF(x...)
71 #endif /* LAPIC_DEBUG */
72
73 struct evcount clk_count;
74 #ifdef MULTIPROCESSOR
75 struct evcount ipi_count;
76 #endif
77
78 static u_int32_t lapic_gettick(void);
79 void lapic_clockintr(void *, struct intrframe);
80 void lapic_initclocks(void);
81 void lapic_map(paddr_t);
82
83 void lapic_hwmask(struct pic *, int);
84 void lapic_hwunmask(struct pic *, int);
85 void lapic_setup(struct pic *, struct cpu_info *, int, int, int);
86
87 extern char idt_allocmap[];
88
89 struct pic local_pic = {
90 {0, {NULL}, NULL, 0, "lapic", NULL, 0, 0},
91 PIC_LAPIC,
92 #ifdef MULTIPROCESSOR
93 {},
94 #endif
95 lapic_hwmask,
96 lapic_hwunmask,
97 lapic_setup,
98 lapic_setup,
99 };
100
101 extern int x2apic_eoi;
102 int x2apic_enabled = 0;
103
104 u_int32_t x2apic_readreg(int reg);
105 u_int32_t x2apic_cpu_number(void);
106 void x2apic_writereg(int reg, u_int32_t val);
107 void x2apic_ipi(int vec, int target, int dl);
108
109 u_int32_t i82489_readreg(int reg);
110 u_int32_t i82489_cpu_number(void);
111 void i82489_writereg(int reg, u_int32_t val);
112 void i82489_ipi(int vec, int target, int dl);
113
114 u_int32_t (*lapic_readreg)(int) = i82489_readreg;
115 void (*lapic_writereg)(int, u_int32_t) = i82489_writereg;
116 #ifdef MULTIPROCESSOR
117 void (*x86_ipi)(int vec, int target, int dl) = i82489_ipi;
118 #endif
119
120 u_int32_t
i82489_readreg(int reg)121 i82489_readreg(int reg)
122 {
123 return *((volatile u_int32_t *)(((volatile u_int8_t *)local_apic)
124 + reg));
125 }
126
127 u_int32_t
i82489_cpu_number(void)128 i82489_cpu_number(void)
129 {
130 return i82489_readreg(LAPIC_ID) >> LAPIC_ID_SHIFT;
131 }
132
133 void
i82489_writereg(int reg,u_int32_t val)134 i82489_writereg(int reg, u_int32_t val)
135 {
136 *((volatile u_int32_t *)(((volatile u_int8_t *)local_apic) + reg)) =
137 val;
138 }
139
140 u_int32_t
x2apic_readreg(int reg)141 x2apic_readreg(int reg)
142 {
143 return rdmsr(MSR_X2APIC_BASE + (reg >> 4));
144 }
145
146 u_int32_t
x2apic_cpu_number(void)147 x2apic_cpu_number(void)
148 {
149 return x2apic_readreg(LAPIC_ID) & X2APIC_ID_MASK;
150 }
151
152 void
x2apic_writereg(int reg,u_int32_t val)153 x2apic_writereg(int reg, u_int32_t val)
154 {
155 wrmsr(MSR_X2APIC_BASE + (reg >> 4), val);
156 }
157
158 #ifdef MULTIPROCESSOR
159 static inline void
x2apic_writeicr(u_int32_t hi,u_int32_t lo)160 x2apic_writeicr(u_int32_t hi, u_int32_t lo)
161 {
162 u_int32_t msr = MSR_X2APIC_BASE + (LAPIC_ICRLO >> 4);
163 __asm volatile("wrmsr" : : "a" (lo), "d" (hi), "c" (msr));
164 }
165 #endif
166
167 u_int32_t
lapic_cpu_number(void)168 lapic_cpu_number(void)
169 {
170 if (x2apic_enabled)
171 return x2apic_cpu_number();
172 return i82489_cpu_number();
173 }
174
175 void
lapic_map(paddr_t lapic_base)176 lapic_map(paddr_t lapic_base)
177 {
178 pt_entry_t *pte;
179 vaddr_t va;
180 u_int64_t msr;
181 u_long s;
182 int tpr;
183
184 s = intr_disable();
185 tpr = lapic_tpr;
186
187 msr = rdmsr(MSR_APICBASE);
188
189 if (ISSET(msr, APICBASE_ENABLE_X2APIC) ||
190 (ISSET(cpu_ecxfeature, CPUIDECX_HV) &&
191 ISSET(cpu_ecxfeature, CPUIDECX_X2APIC))) {
192 /*
193 * On real hardware, x2apic must only be enabled if interrupt
194 * remapping is also enabled. See 10.12.7 of the SDM vol 3.
195 * On hypervisors, this is not necessary. Hypervisors can
196 * implement x2apic support even if the host CPU does not
197 * support it. Until we support interrupt remapping, use
198 * x2apic only if the hypervisor flag is also set or it is
199 * enabled by BIOS.
200 */
201 if (!ISSET(msr, APICBASE_ENABLE_X2APIC)) {
202 msr |= APICBASE_ENABLE_X2APIC;
203 wrmsr(MSR_APICBASE, msr);
204 }
205 lapic_readreg = x2apic_readreg;
206 lapic_writereg = x2apic_writereg;
207 #ifdef MULTIPROCESSOR
208 x86_ipi = x2apic_ipi;
209 #endif
210 x2apic_enabled = 1;
211 codepatch_call(CPTAG_EOI, &x2apic_eoi);
212
213 lapic_writereg(LAPIC_TPRI, tpr);
214 va = (vaddr_t)&local_apic;
215 } else {
216 /*
217 * Map local apic.
218 *
219 * Whap the PTE "by hand" rather than calling pmap_kenter_pa
220 * because the latter will attempt to invoke TLB shootdown
221 * code just as we might have changed the value of
222 * cpu_number()..
223 */
224 va = (vaddr_t)&local_apic;
225 pte = kvtopte(va);
226 *pte = lapic_base | PG_RW | PG_V | PG_N | PG_G | pg_nx;
227 invlpg(va);
228
229 lapic_tpr = tpr;
230 }
231
232 /*
233 * Enter the LAPIC MMIO page in the U-K page table for handling
234 * Meltdown (needed in the interrupt stub to acknowledge the
235 * incoming interrupt). On CPUs unaffected by Meltdown,
236 * pmap_enter_special is a no-op.
237 */
238 pmap_enter_special(va, lapic_base, PROT_READ | PROT_WRITE);
239 DPRINTF("%s: entered lapic page va 0x%llx pa 0x%llx\n", __func__,
240 (uint64_t)va, (uint64_t)lapic_base);
241
242 intr_restore(s);
243 }
244
245 /*
246 * enable local apic
247 */
248 void
lapic_enable(void)249 lapic_enable(void)
250 {
251 lapic_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR);
252 }
253
254 void
lapic_disable(void)255 lapic_disable(void)
256 {
257 lapic_writereg(LAPIC_SVR, 0);
258 }
259
260 void
lapic_set_lvt(void)261 lapic_set_lvt(void)
262 {
263 struct cpu_info *ci = curcpu();
264 int i;
265 struct mp_intr_map *mpi;
266 uint32_t lint0;
267
268 #ifdef MULTIPROCESSOR
269 if (mp_verbose) {
270 apic_format_redir(ci->ci_dev->dv_xname, "prelint", 0, 0,
271 lapic_readreg(LAPIC_LVINT0));
272 apic_format_redir(ci->ci_dev->dv_xname, "prelint", 1, 0,
273 lapic_readreg(LAPIC_LVINT1));
274 }
275 #endif
276
277 #if NIOAPIC > 0
278 /*
279 * Disable ExtINT by default when using I/O APICs.
280 */
281 if (nioapics > 0) {
282 lint0 = lapic_readreg(LAPIC_LVINT0);
283 lint0 |= LAPIC_LVT_MASKED;
284 lapic_writereg(LAPIC_LVINT0, lint0);
285 }
286 #endif
287
288 if (ci->ci_vendor == CPUV_AMD) {
289 /*
290 * Detect the presence of C1E capability mostly on latest
291 * dual-cores (or future) k8 family. This mis-feature renders
292 * the local APIC timer dead, so we disable it by reading
293 * the Interrupt Pending Message register and clearing both
294 * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
295 *
296 * Reference:
297 * "BIOS and Kernel Developer's Guide for AMD NPT
298 * Family 0Fh Processors"
299 * #32559 revision 3.00
300 */
301 if (ci->ci_family == 0xf || ci->ci_family == 0x10) {
302 uint64_t msr;
303
304 msr = rdmsr(MSR_INT_PEN_MSG);
305 if (msr & (IPM_C1E_CMP_HLT|IPM_SMI_CMP_HLT)) {
306 msr &= ~(IPM_C1E_CMP_HLT|IPM_SMI_CMP_HLT);
307 wrmsr(MSR_INT_PEN_MSG, msr);
308 }
309 }
310 }
311
312 for (i = 0; i < mp_nintrs; i++) {
313 mpi = &mp_intrs[i];
314 if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS
315 || mpi->cpu_id == ci->ci_apicid)) {
316 #ifdef DIAGNOSTIC
317 if (mpi->ioapic_pin > 1)
318 panic("lapic_set_lvt: bad pin value %d",
319 mpi->ioapic_pin);
320 #endif
321 if (mpi->ioapic_pin == 0)
322 lapic_writereg(LAPIC_LVINT0, mpi->redir);
323 else
324 lapic_writereg(LAPIC_LVINT1, mpi->redir);
325 }
326 }
327
328 #ifdef MULTIPROCESSOR
329 if (mp_verbose) {
330 apic_format_redir(ci->ci_dev->dv_xname, "timer", 0, 0,
331 lapic_readreg(LAPIC_LVTT));
332 apic_format_redir(ci->ci_dev->dv_xname, "pcint", 0, 0,
333 lapic_readreg(LAPIC_PCINT));
334 apic_format_redir(ci->ci_dev->dv_xname, "lint", 0, 0,
335 lapic_readreg(LAPIC_LVINT0));
336 apic_format_redir(ci->ci_dev->dv_xname, "lint", 1, 0,
337 lapic_readreg(LAPIC_LVINT1));
338 apic_format_redir(ci->ci_dev->dv_xname, "err", 0, 0,
339 lapic_readreg(LAPIC_LVERR));
340 }
341 #endif
342 }
343
344 /*
345 * Initialize fixed idt vectors for use by local apic.
346 */
347 void
lapic_boot_init(paddr_t lapic_base)348 lapic_boot_init(paddr_t lapic_base)
349 {
350 static u_int64_t clk_irq = 0;
351 #ifdef MULTIPROCESSOR
352 static u_int64_t ipi_irq = 0;
353 #endif
354
355 lapic_map(lapic_base);
356
357 #ifdef MULTIPROCESSOR
358 idt_allocmap[LAPIC_IPI_VECTOR] = 1;
359 idt_vec_set(LAPIC_IPI_VECTOR, Xintr_lapic_ipi);
360 idt_allocmap[LAPIC_IPI_INVLTLB] = 1;
361 idt_allocmap[LAPIC_IPI_INVLPG] = 1;
362 idt_allocmap[LAPIC_IPI_INVLRANGE] = 1;
363 if (!pmap_use_pcid) {
364 idt_vec_set(LAPIC_IPI_INVLTLB, Xipi_invltlb);
365 idt_vec_set(LAPIC_IPI_INVLPG, Xipi_invlpg);
366 idt_vec_set(LAPIC_IPI_INVLRANGE, Xipi_invlrange);
367 } else {
368 idt_vec_set(LAPIC_IPI_INVLTLB, Xipi_invltlb_pcid);
369 idt_vec_set(LAPIC_IPI_INVLPG, Xipi_invlpg_pcid);
370 idt_vec_set(LAPIC_IPI_INVLRANGE, Xipi_invlrange_pcid);
371 }
372 idt_allocmap[LAPIC_IPI_WBINVD] = 1;
373 idt_vec_set(LAPIC_IPI_WBINVD, Xipi_wbinvd);
374 #if NVMM > 0
375 idt_allocmap[LAPIC_IPI_INVEPT] = 1;
376 idt_vec_set(LAPIC_IPI_INVEPT, Xipi_invept);
377 #endif /* NVMM > 0 */
378 #endif /* MULTIPROCESSOR */
379 idt_allocmap[LAPIC_SPURIOUS_VECTOR] = 1;
380 idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious);
381
382 idt_allocmap[LAPIC_TIMER_VECTOR] = 1;
383 idt_vec_set(LAPIC_TIMER_VECTOR, Xintr_lapic_ltimer);
384
385 #if NXEN > 0
386 /* Xen HVM Event Channel Interrupt Vector */
387 idt_allocmap[LAPIC_XEN_VECTOR] = 1;
388 idt_vec_set(LAPIC_XEN_VECTOR, Xintr_xen_upcall);
389 #endif
390 #if NHYPERV > 0
391 /* Hyper-V Interrupt Vector */
392 idt_allocmap[LAPIC_HYPERV_VECTOR] = 1;
393 idt_vec_set(LAPIC_HYPERV_VECTOR, Xintr_hyperv_upcall);
394 #endif
395
396 evcount_attach(&clk_count, "clock", &clk_irq);
397 evcount_percpu(&clk_count);
398 #ifdef MULTIPROCESSOR
399 evcount_attach(&ipi_count, "ipi", &ipi_irq);
400 evcount_percpu(&ipi_count);
401 #endif
402 }
403
404 static __inline u_int32_t
lapic_gettick(void)405 lapic_gettick(void)
406 {
407 return lapic_readreg(LAPIC_CCR_TIMER);
408 }
409
410 #include <sys/kernel.h> /* for hz */
411
412 /*
413 * this gets us up to a 4GHz busclock....
414 */
415 u_int32_t lapic_per_second = 0;
416 uint64_t lapic_timer_nsec_cycle_ratio;
417 uint64_t lapic_timer_nsec_max;
418
419 void lapic_timer_rearm(void *, uint64_t);
420 void lapic_timer_trigger(void *);
421
422 const struct intrclock lapic_timer_intrclock = {
423 .ic_rearm = lapic_timer_rearm,
424 .ic_trigger = lapic_timer_trigger
425 };
426
427 void lapic_timer_oneshot(uint32_t, uint32_t);
428 void lapic_timer_periodic(uint32_t, uint32_t);
429
430 void
lapic_timer_rearm(void * unused,uint64_t nsecs)431 lapic_timer_rearm(void *unused, uint64_t nsecs)
432 {
433 uint32_t cycles;
434
435 if (nsecs > lapic_timer_nsec_max)
436 nsecs = lapic_timer_nsec_max;
437 cycles = (nsecs * lapic_timer_nsec_cycle_ratio) >> 32;
438 if (cycles == 0)
439 cycles = 1;
440 lapic_writereg(LAPIC_ICR_TIMER, cycles);
441 }
442
443 void
lapic_timer_trigger(void * unused)444 lapic_timer_trigger(void *unused)
445 {
446 u_long s;
447
448 s = intr_disable();
449 lapic_timer_oneshot(0, 1);
450 intr_restore(s);
451 }
452
453 /*
454 * Start the local apic countdown timer.
455 *
456 * First set the mode, mask, and vector. Then set the
457 * divisor. Last, set the cycle count: this restarts
458 * the countdown.
459 */
460 static inline void
lapic_timer_start(uint32_t mode,uint32_t mask,uint32_t cycles)461 lapic_timer_start(uint32_t mode, uint32_t mask, uint32_t cycles)
462 {
463 lapic_writereg(LAPIC_LVTT, mode | mask | LAPIC_TIMER_VECTOR);
464 lapic_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
465 lapic_writereg(LAPIC_ICR_TIMER, cycles);
466 }
467
468 void
lapic_timer_oneshot(uint32_t mask,uint32_t cycles)469 lapic_timer_oneshot(uint32_t mask, uint32_t cycles)
470 {
471 lapic_timer_start(LAPIC_LVTT_TM_ONESHOT, mask, cycles);
472 }
473
474 void
lapic_timer_periodic(uint32_t mask,uint32_t cycles)475 lapic_timer_periodic(uint32_t mask, uint32_t cycles)
476 {
477 lapic_timer_start(LAPIC_LVTT_TM_PERIODIC, mask, cycles);
478 }
479
480 void
lapic_clockintr(void * arg,struct intrframe frame)481 lapic_clockintr(void *arg, struct intrframe frame)
482 {
483 struct cpu_info *ci = curcpu();
484 int floor;
485
486 floor = ci->ci_handled_intr_level;
487 ci->ci_handled_intr_level = ci->ci_ilevel;
488 clockintr_dispatch(&frame);
489 ci->ci_handled_intr_level = floor;
490
491 evcount_inc(&clk_count);
492 }
493
494 void
lapic_startclock(void)495 lapic_startclock(void)
496 {
497 clockintr_cpu_init(&lapic_timer_intrclock);
498 clockintr_trigger();
499 }
500
501 void
lapic_initclocks(void)502 lapic_initclocks(void)
503 {
504 i8254_inittimecounter_simple();
505
506 stathz = hz;
507 profhz = stathz * 10;
508 statclock_is_randomized = 1;
509 }
510
511
512 extern int gettick(void); /* XXX put in header file */
513 extern u_long rtclock_tval; /* XXX put in header file */
514
515 static __inline void
wait_next_cycle(void)516 wait_next_cycle(void)
517 {
518 unsigned int tick, tlast;
519
520 tlast = (1 << 16); /* i8254 counter has 16 bits at most */
521 for (;;) {
522 tick = gettick();
523 if (tick > tlast)
524 return;
525 tlast = tick;
526 }
527 }
528
529 /*
530 * Calibrate the local apic count-down timer (which is running at
531 * bus-clock speed) vs. the i8254 counter/timer (which is running at
532 * a fixed rate).
533 *
534 * The Intel MP spec says: "An MP operating system may use the IRQ8
535 * real-time clock as a reference to determine the actual APIC timer clock
536 * speed."
537 *
538 * We're actually using the IRQ0 timer. Hmm.
539 */
540 void
lapic_calibrate_timer(struct cpu_info * ci)541 lapic_calibrate_timer(struct cpu_info *ci)
542 {
543 unsigned int startapic, endapic;
544 u_int64_t dtick, dapic, tmp;
545 u_long s;
546 int i;
547
548 if (lapic_per_second)
549 goto skip_calibration;
550
551 if (mp_verbose)
552 printf("%s: calibrating local timer\n", ci->ci_dev->dv_xname);
553
554 /*
555 * Configure timer to one-shot, interrupt masked,
556 * large positive number.
557 */
558 lapic_timer_oneshot(LAPIC_LVTT_M, 0x80000000);
559
560 if (delay_func == i8254_delay) {
561 s = intr_disable();
562
563 /* wait for current cycle to finish */
564 wait_next_cycle();
565
566 startapic = lapic_gettick();
567
568 /* wait the next hz cycles */
569 for (i = 0; i < hz; i++)
570 wait_next_cycle();
571
572 endapic = lapic_gettick();
573
574 intr_restore(s);
575
576 dtick = hz * rtclock_tval;
577 dapic = startapic-endapic;
578
579 /*
580 * there are TIMER_FREQ ticks per second.
581 * in dtick ticks, there are dapic bus clocks.
582 */
583 tmp = (TIMER_FREQ * dapic) / dtick;
584
585 lapic_per_second = tmp;
586 } else {
587 s = intr_disable();
588 startapic = lapic_gettick();
589 delay(1 * 1000 * 1000);
590 endapic = lapic_gettick();
591 intr_restore(s);
592 lapic_per_second = startapic - endapic;
593 }
594
595 skip_calibration:
596 printf("%s: apic clock running at %dMHz\n",
597 ci->ci_dev->dv_xname, lapic_per_second / (1000 * 1000));
598
599 /* XXX What do we do if this is zero? */
600 if (lapic_per_second == 0)
601 return;
602
603 lapic_timer_nsec_cycle_ratio =
604 lapic_per_second * (1ULL << 32) / 1000000000;
605 lapic_timer_nsec_max = UINT64_MAX / lapic_timer_nsec_cycle_ratio;
606 initclock_func = lapic_initclocks;
607 startclock_func = lapic_startclock;
608 }
609
610 /*
611 * XXX the following belong mostly or partly elsewhere..
612 */
613
614 #ifdef MULTIPROCESSOR
615 static __inline void i82489_icr_wait(void);
616
617 static __inline void
i82489_icr_wait(void)618 i82489_icr_wait(void)
619 {
620 #ifdef DIAGNOSTIC
621 unsigned j = 100000;
622 #endif /* DIAGNOSTIC */
623
624 while ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) {
625 __asm volatile("pause": : :"memory");
626 #ifdef DIAGNOSTIC
627 j--;
628 if (j == 0)
629 panic("i82489_icr_wait: busy");
630 #endif /* DIAGNOSTIC */
631 }
632 }
633
634 void
i82489_ipi_init(int target)635 i82489_ipi_init(int target)
636 {
637
638 if ((target & LAPIC_DEST_MASK) == 0)
639 i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
640
641 i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
642 LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT );
643
644 i82489_icr_wait();
645
646 delay(10000);
647
648 i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
649 LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT);
650
651 i82489_icr_wait();
652 }
653
654 void
i82489_ipi(int vec,int target,int dl)655 i82489_ipi(int vec, int target, int dl)
656 {
657 int s;
658
659 s = splhigh();
660
661 i82489_icr_wait();
662
663 if ((target & LAPIC_DEST_MASK) == 0)
664 i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
665
666 i82489_writereg(LAPIC_ICRLO,
667 (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT);
668
669 i82489_icr_wait();
670
671 splx(s);
672 }
673
674 void
x2apic_ipi_init(int target)675 x2apic_ipi_init(int target)
676 {
677 u_int64_t hi = 0;
678
679 if ((target & LAPIC_DEST_MASK) == 0)
680 hi = target & 0xff;
681
682 x2apic_writeicr(hi, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT |
683 LAPIC_LVL_ASSERT );
684
685 delay(10000);
686
687 x2apic_writeicr(0, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT |
688 LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT);
689 }
690
691 void
x2apic_ipi(int vec,int target,int dl)692 x2apic_ipi(int vec, int target, int dl)
693 {
694 u_int64_t hi = 0, lo;
695
696 if ((target & LAPIC_DEST_MASK) == 0)
697 hi = target & 0xff;
698
699 lo = (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT;
700
701 x2apic_writeicr(hi, lo);
702 }
703
704 void
x86_ipi_init(int target)705 x86_ipi_init(int target)
706 {
707 if (x2apic_enabled)
708 x2apic_ipi_init(target);
709 else
710 i82489_ipi_init(target);
711 }
712 #endif /* MULTIPROCESSOR */
713
714
715 /*
716 * Using 'pin numbers' as:
717 * 0 - timer
718 * 1 - unused
719 * 2 - PCINT
720 * 3 - LVINT0
721 * 4 - LVINT1
722 * 5 - LVERR
723 */
724
725 void
lapic_hwmask(struct pic * pic,int pin)726 lapic_hwmask(struct pic *pic, int pin)
727 {
728 int reg;
729 u_int32_t val;
730
731 reg = LAPIC_LVTT + (pin << 4);
732 val = lapic_readreg(reg);
733 val |= LAPIC_LVT_MASKED;
734 lapic_writereg(reg, val);
735 }
736
737 void
lapic_hwunmask(struct pic * pic,int pin)738 lapic_hwunmask(struct pic *pic, int pin)
739 {
740 int reg;
741 u_int32_t val;
742
743 reg = LAPIC_LVTT + (pin << 4);
744 val = lapic_readreg(reg);
745 val &= ~LAPIC_LVT_MASKED;
746 lapic_writereg(reg, val);
747 }
748
749 void
lapic_setup(struct pic * pic,struct cpu_info * ci,int pin,int idtvec,int type)750 lapic_setup(struct pic *pic, struct cpu_info *ci, int pin, int idtvec, int type)
751 {
752 }
753