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 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 128 i82489_cpu_number(void) 129 { 130 return i82489_readreg(LAPIC_ID) >> LAPIC_ID_SHIFT; 131 } 132 133 void 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 141 x2apic_readreg(int reg) 142 { 143 return rdmsr(MSR_X2APIC_BASE + (reg >> 4)); 144 } 145 146 u_int32_t 147 x2apic_cpu_number(void) 148 { 149 return x2apic_readreg(LAPIC_ID) & X2APIC_ID_MASK; 150 } 151 152 void 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 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 168 lapic_cpu_number(void) 169 { 170 if (x2apic_enabled) 171 return x2apic_cpu_number(); 172 return i82489_cpu_number(); 173 } 174 175 void 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 249 lapic_enable(void) 250 { 251 lapic_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR); 252 } 253 254 void 255 lapic_disable(void) 256 { 257 lapic_writereg(LAPIC_SVR, 0); 258 } 259 260 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 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 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 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 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 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 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 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 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 495 lapic_startclock(void) 496 { 497 clockintr_cpu_init(&lapic_timer_intrclock); 498 clockintr_trigger(); 499 } 500 501 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 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 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 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 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 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 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 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 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 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 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 750 lapic_setup(struct pic *pic, struct cpu_info *ci, int pin, int idtvec, int type) 751 { 752 } 753