local_apic.c revision 140254
1/*- 2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3 * Copyright (c) 1996, by Steve Passe 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. The name of the developer may NOT be used to endorse or promote products 12 * derived from this software without specific prior written permission. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30/* 31 * Local APIC support on Pentium and later processors. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/i386/i386/local_apic.c 140254 2005-01-14 18:31:00Z jhb $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/bus.h> 40#include <sys/kernel.h> 41#include <sys/pcpu.h> 42 43#include <vm/vm.h> 44#include <vm/pmap.h> 45 46#include <machine/apicreg.h> 47#include <machine/cputypes.h> 48#include <machine/frame.h> 49#include <machine/intr_machdep.h> 50#include <machine/apicvar.h> 51#include <machine/md_var.h> 52#include <machine/smp.h> 53#include <machine/specialreg.h> 54 55/* 56 * We can handle up to 60 APICs via our logical cluster IDs, but currently 57 * the physical IDs on Intel processors up to the Pentium 4 are limited to 58 * 16. 59 */ 60#define MAX_APICID 16 61 62/* Sanity checks on IDT vectors. */ 63CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT); 64CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS); 65CTASSERT(APIC_LOCAL_INTS == 240); 66CTASSERT(IPI_STOP < APIC_SPURIOUS_INT); 67 68/* 69 * Support for local APICs. Local APICs manage interrupts on each 70 * individual processor as opposed to I/O APICs which receive interrupts 71 * from I/O devices and then forward them on to the local APICs. 72 * 73 * Local APICs can also send interrupts to each other thus providing the 74 * mechanism for IPIs. 75 */ 76 77struct lvt { 78 u_int lvt_edgetrigger:1; 79 u_int lvt_activehi:1; 80 u_int lvt_masked:1; 81 u_int lvt_active:1; 82 u_int lvt_mode:16; 83 u_int lvt_vector:8; 84}; 85 86struct lapic { 87 struct lvt la_lvts[LVT_MAX + 1]; 88 u_int la_id:8; 89 u_int la_cluster:4; 90 u_int la_cluster_id:2; 91 u_int la_present:1; 92} static lapics[MAX_APICID]; 93 94/* XXX: should thermal be an NMI? */ 95 96/* Global defaults for local APIC LVT entries. */ 97static struct lvt lvts[LVT_MAX + 1] = { 98 { 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 }, /* LINT0: masked ExtINT */ 99 { 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */ 100 { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */ 101 { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */ 102 { 1, 1, 1, 1, APIC_LVT_DM_FIXED, 0 }, /* PMC */ 103 { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */ 104}; 105 106static inthand_t *ioint_handlers[] = { 107 NULL, /* 0 - 31 */ 108 IDTVEC(apic_isr1), /* 32 - 63 */ 109 IDTVEC(apic_isr2), /* 64 - 95 */ 110 IDTVEC(apic_isr3), /* 96 - 127 */ 111 IDTVEC(apic_isr4), /* 128 - 159 */ 112 IDTVEC(apic_isr5), /* 160 - 191 */ 113 IDTVEC(apic_isr6), /* 192 - 223 */ 114 IDTVEC(apic_isr7), /* 224 - 255 */ 115}; 116 117volatile lapic_t *lapic; 118 119static void lapic_enable(void); 120static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); 121 122static uint32_t 123lvt_mode(struct lapic *la, u_int pin, uint32_t value) 124{ 125 struct lvt *lvt; 126 127 KASSERT(pin <= LVT_MAX, ("%s: pin %u out of range", __func__, pin)); 128 if (la->la_lvts[pin].lvt_active) 129 lvt = &la->la_lvts[pin]; 130 else 131 lvt = &lvts[pin]; 132 133 value &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM | 134 APIC_LVT_VECTOR); 135 if (lvt->lvt_edgetrigger == 0) 136 value |= APIC_LVT_TM; 137 if (lvt->lvt_activehi == 0) 138 value |= APIC_LVT_IIPP_INTALO; 139 if (lvt->lvt_masked) 140 value |= APIC_LVT_M; 141 value |= lvt->lvt_mode; 142 switch (lvt->lvt_mode) { 143 case APIC_LVT_DM_NMI: 144 case APIC_LVT_DM_SMI: 145 case APIC_LVT_DM_INIT: 146 case APIC_LVT_DM_EXTINT: 147 if (!lvt->lvt_edgetrigger) { 148 printf("lapic%u: Forcing LINT%u to edge trigger\n", 149 la->la_id, pin); 150 value |= APIC_LVT_TM; 151 } 152 /* Use a vector of 0. */ 153 break; 154 case APIC_LVT_DM_FIXED: 155 value |= lvt->lvt_vector; 156 break; 157 default: 158 panic("bad APIC LVT delivery mode: %#x\n", value); 159 } 160 return (value); 161} 162 163/* 164 * Map the local APIC and setup necessary interrupt vectors. 165 */ 166void 167lapic_init(uintptr_t addr) 168{ 169 170 /* Map the local APIC and setup the spurious interrupt handler. */ 171 KASSERT(trunc_page(addr) == addr, 172 ("local APIC not aligned on a page boundary")); 173 lapic = (lapic_t *)pmap_mapdev(addr, sizeof(lapic_t)); 174 setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL, 175 GSEL(GCODE_SEL, SEL_KPL)); 176 177 /* Perform basic initialization of the BSP's local APIC. */ 178 lapic_enable(); 179 180 /* Set BSP's per-CPU local APIC ID. */ 181 PCPU_SET(apic_id, lapic_id()); 182 183 /* XXX: timer/error/thermal interrupts */ 184} 185 186/* 187 * Create a local APIC instance. 188 */ 189void 190lapic_create(u_int apic_id, int boot_cpu) 191{ 192 int i; 193 194 if (apic_id >= MAX_APICID) { 195 printf("APIC: Ignoring local APIC with ID %d\n", apic_id); 196 if (boot_cpu) 197 panic("Can't ignore BSP"); 198 return; 199 } 200 KASSERT(!lapics[apic_id].la_present, ("duplicate local APIC %u", 201 apic_id)); 202 203 /* 204 * Assume no local LVT overrides and a cluster of 0 and 205 * intra-cluster ID of 0. 206 */ 207 lapics[apic_id].la_present = 1; 208 lapics[apic_id].la_id = apic_id; 209 for (i = 0; i < LVT_MAX; i++) { 210 lapics[apic_id].la_lvts[i] = lvts[i]; 211 lapics[apic_id].la_lvts[i].lvt_active = 0; 212 } 213 214#ifdef SMP 215 cpu_add(apic_id, boot_cpu); 216#endif 217} 218 219/* 220 * Dump contents of local APIC registers 221 */ 222void 223lapic_dump(const char* str) 224{ 225 226 printf("cpu%d %s:\n", PCPU_GET(cpuid), str); 227 printf(" ID: 0x%08x VER: 0x%08x LDR: 0x%08x DFR: 0x%08x\n", 228 lapic->id, lapic->version, lapic->ldr, lapic->dfr); 229 printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n", 230 lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr); 231 printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n", 232 lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error, 233 lapic->lvt_pcint); 234} 235 236void 237lapic_enable_intr(u_int irq) 238{ 239 u_int vector; 240 241 vector = apic_irq_to_idt(irq); 242 KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); 243 KASSERT(ioint_handlers[vector / 32] != NULL, 244 ("No ISR handler for IRQ %u", irq)); 245 setidt(vector, ioint_handlers[vector / 32], SDT_SYS386IGT, SEL_KPL, 246 GSEL(GCODE_SEL, SEL_KPL)); 247} 248 249void 250lapic_setup(void) 251{ 252 struct lapic *la; 253 u_int32_t value, maxlvt; 254 register_t eflags; 255 256 la = &lapics[lapic_id()]; 257 KASSERT(la->la_present, ("missing APIC structure")); 258 eflags = intr_disable(); 259 maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT; 260 261 /* Initialize the TPR to allow all interrupts. */ 262 lapic_set_tpr(0); 263 264 /* Use the cluster model for logical IDs. */ 265 value = lapic->dfr; 266 value &= ~APIC_DFR_MODEL_MASK; 267 value |= APIC_DFR_MODEL_CLUSTER; 268 lapic->dfr = value; 269 270 /* Set this APIC's logical ID. */ 271 value = lapic->ldr; 272 value &= ~APIC_ID_MASK; 273 value |= (la->la_cluster << APIC_ID_CLUSTER_SHIFT | 274 1 << la->la_cluster_id) << APIC_ID_SHIFT; 275 lapic->ldr = value; 276 277 /* Setup spurious vector and enable the local APIC. */ 278 lapic_enable(); 279 280 /* Program LINT[01] LVT entries. */ 281 lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0); 282 lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1); 283 284 /* XXX: more LVT entries */ 285 286 intr_restore(eflags); 287} 288 289void 290lapic_disable(void) 291{ 292 uint32_t value; 293 294 /* Software disable the local APIC. */ 295 value = lapic->svr; 296 value &= ~APIC_SVR_SWEN; 297 lapic->svr = value; 298} 299 300static void 301lapic_enable(void) 302{ 303 u_int32_t value; 304 305 /* Program the spurious vector to enable the local APIC. */ 306 value = lapic->svr; 307 value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS); 308 value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT); 309 lapic->svr = value; 310} 311 312int 313lapic_id(void) 314{ 315 316 KASSERT(lapic != NULL, ("local APIC is not mapped")); 317 return (lapic->id >> APIC_ID_SHIFT); 318} 319 320int 321lapic_intr_pending(u_int vector) 322{ 323 volatile u_int32_t *irr; 324 325 /* 326 * The IRR registers are an array of 128-bit registers each of 327 * which only describes 32 interrupts in the low 32 bits.. Thus, 328 * we divide the vector by 32 to get the 128-bit index. We then 329 * multiply that index by 4 to get the equivalent index from 330 * treating the IRR as an array of 32-bit registers. Finally, we 331 * modulus the vector by 32 to determine the individual bit to 332 * test. 333 */ 334 irr = &lapic->irr0; 335 return (irr[(vector / 32) * 4] & 1 << (vector % 32)); 336} 337 338void 339lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id) 340{ 341 struct lapic *la; 342 343 KASSERT(lapics[apic_id].la_present, ("%s: APIC %u doesn't exist", 344 __func__, apic_id)); 345 KASSERT(cluster <= APIC_MAX_CLUSTER, ("%s: cluster %u too big", 346 __func__, cluster)); 347 KASSERT(cluster_id <= APIC_MAX_INTRACLUSTER_ID, 348 ("%s: intra cluster id %u too big", __func__, cluster_id)); 349 la = &lapics[apic_id]; 350 la->la_cluster = cluster; 351 la->la_cluster_id = cluster_id; 352} 353 354int 355lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked) 356{ 357 358 if (pin > LVT_MAX) 359 return (EINVAL); 360 if (apic_id == APIC_ID_ALL) { 361 lvts[pin].lvt_masked = masked; 362 if (bootverbose) 363 printf("lapic:"); 364 } else { 365 KASSERT(lapics[apic_id].la_present, 366 ("%s: missing APIC %u", __func__, apic_id)); 367 lapics[apic_id].la_lvts[pin].lvt_masked = masked; 368 lapics[apic_id].la_lvts[pin].lvt_active = 1; 369 if (bootverbose) 370 printf("lapic%u:", apic_id); 371 } 372 if (bootverbose) 373 printf(" LINT%u %s\n", pin, masked ? "masked" : "unmasked"); 374 return (0); 375} 376 377int 378lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode) 379{ 380 struct lvt *lvt; 381 382 if (pin > LVT_MAX) 383 return (EINVAL); 384 if (apic_id == APIC_ID_ALL) { 385 lvt = &lvts[pin]; 386 if (bootverbose) 387 printf("lapic:"); 388 } else { 389 KASSERT(lapics[apic_id].la_present, 390 ("%s: missing APIC %u", __func__, apic_id)); 391 lvt = &lapics[apic_id].la_lvts[pin]; 392 lvt->lvt_active = 1; 393 if (bootverbose) 394 printf("lapic%u:", apic_id); 395 } 396 lvt->lvt_mode = mode; 397 switch (mode) { 398 case APIC_LVT_DM_NMI: 399 case APIC_LVT_DM_SMI: 400 case APIC_LVT_DM_INIT: 401 case APIC_LVT_DM_EXTINT: 402 lvt->lvt_edgetrigger = 1; 403 lvt->lvt_activehi = 1; 404 if (mode == APIC_LVT_DM_EXTINT) 405 lvt->lvt_masked = 1; 406 else 407 lvt->lvt_masked = 0; 408 break; 409 default: 410 panic("Unsupported delivery mode: 0x%x\n", mode); 411 } 412 if (bootverbose) { 413 printf(" Routing "); 414 switch (mode) { 415 case APIC_LVT_DM_NMI: 416 printf("NMI"); 417 break; 418 case APIC_LVT_DM_SMI: 419 printf("SMI"); 420 break; 421 case APIC_LVT_DM_INIT: 422 printf("INIT"); 423 break; 424 case APIC_LVT_DM_EXTINT: 425 printf("ExtINT"); 426 break; 427 } 428 printf(" -> LINT%u\n", pin); 429 } 430 return (0); 431} 432 433int 434lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol) 435{ 436 437 if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM) 438 return (EINVAL); 439 if (apic_id == APIC_ID_ALL) { 440 lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH); 441 if (bootverbose) 442 printf("lapic:"); 443 } else { 444 KASSERT(lapics[apic_id].la_present, 445 ("%s: missing APIC %u", __func__, apic_id)); 446 lapics[apic_id].la_lvts[pin].lvt_active = 1; 447 lapics[apic_id].la_lvts[pin].lvt_activehi = 448 (pol == INTR_POLARITY_HIGH); 449 if (bootverbose) 450 printf("lapic%u:", apic_id); 451 } 452 if (bootverbose) 453 printf(" LINT%u polarity: %s\n", pin, 454 pol == INTR_POLARITY_HIGH ? "high" : "low"); 455 return (0); 456} 457 458int 459lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger) 460{ 461 462 if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM) 463 return (EINVAL); 464 if (apic_id == APIC_ID_ALL) { 465 lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE); 466 if (bootverbose) 467 printf("lapic:"); 468 } else { 469 KASSERT(lapics[apic_id].la_present, 470 ("%s: missing APIC %u", __func__, apic_id)); 471 lapics[apic_id].la_lvts[pin].lvt_edgetrigger = 472 (trigger == INTR_TRIGGER_EDGE); 473 lapics[apic_id].la_lvts[pin].lvt_active = 1; 474 if (bootverbose) 475 printf("lapic%u:", apic_id); 476 } 477 if (bootverbose) 478 printf(" LINT%u trigger: %s\n", pin, 479 trigger == INTR_TRIGGER_EDGE ? "edge" : "level"); 480 return (0); 481} 482 483/* 484 * Adjust the TPR of the current CPU so that it blocks all interrupts below 485 * the passed in vector. 486 */ 487void 488lapic_set_tpr(u_int vector) 489{ 490#ifdef CHEAP_TPR 491 lapic->tpr = vector; 492#else 493 u_int32_t tpr; 494 495 tpr = lapic->tpr & ~APIC_TPR_PRIO; 496 tpr |= vector; 497 lapic->tpr = tpr; 498#endif 499} 500 501void 502lapic_eoi(void) 503{ 504 505 lapic->eoi = 0; 506} 507 508void 509lapic_handle_intr(struct intrframe frame) 510{ 511 struct intsrc *isrc; 512 513 if (frame.if_vec == -1) 514 panic("Couldn't get vector from ISR!"); 515 isrc = intr_lookup_source(apic_idt_to_irq(frame.if_vec)); 516 intr_execute_handlers(isrc, &frame); 517} 518 519/* Translate between IDT vectors and IRQ vectors. */ 520u_int 521apic_irq_to_idt(u_int irq) 522{ 523 u_int vector; 524 525 KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq)); 526 vector = irq + APIC_IO_INTS; 527 if (vector >= IDT_SYSCALL) 528 vector++; 529 return (vector); 530} 531 532u_int 533apic_idt_to_irq(u_int vector) 534{ 535 536 KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL && 537 vector <= APIC_IO_INTS + NUM_IO_INTS, 538 ("Vector %u does not map to an IRQ line", vector)); 539 if (vector > IDT_SYSCALL) 540 vector--; 541 return (vector - APIC_IO_INTS); 542} 543 544/* 545 * APIC probing support code. This includes code to manage enumerators. 546 */ 547 548static SLIST_HEAD(, apic_enumerator) enumerators = 549 SLIST_HEAD_INITIALIZER(enumerators); 550static struct apic_enumerator *best_enum; 551 552void 553apic_register_enumerator(struct apic_enumerator *enumerator) 554{ 555#ifdef INVARIANTS 556 struct apic_enumerator *apic_enum; 557 558 SLIST_FOREACH(apic_enum, &enumerators, apic_next) { 559 if (apic_enum == enumerator) 560 panic("%s: Duplicate register of %s", __func__, 561 enumerator->apic_name); 562 } 563#endif 564 SLIST_INSERT_HEAD(&enumerators, enumerator, apic_next); 565} 566 567/* 568 * Probe the APIC enumerators, enumerate CPUs, and initialize the 569 * local APIC. 570 */ 571static void 572apic_init(void *dummy __unused) 573{ 574 struct apic_enumerator *enumerator; 575 uint64_t apic_base; 576 int retval, best; 577 578 /* We only support built in local APICs. */ 579 if (!(cpu_feature & CPUID_APIC)) 580 return; 581 582 /* Don't probe if APIC mode is disabled. */ 583 if (resource_disabled("apic", 0)) 584 return; 585 586 /* First, probe all the enumerators to find the best match. */ 587 best_enum = NULL; 588 best = 0; 589 SLIST_FOREACH(enumerator, &enumerators, apic_next) { 590 retval = enumerator->apic_probe(); 591 if (retval > 0) 592 continue; 593 if (best_enum == NULL || best < retval) { 594 best_enum = enumerator; 595 best = retval; 596 } 597 } 598 if (best_enum == NULL) { 599 if (bootverbose) 600 printf("APIC: Could not find any APICs.\n"); 601 return; 602 } 603 604 if (bootverbose) 605 printf("APIC: Using the %s enumerator.\n", 606 best_enum->apic_name); 607 608 /* 609 * To work around an errata, we disable the local APIC on some 610 * CPUs during early startup. We need to turn the local APIC back 611 * on on such CPUs now. 612 */ 613 if (cpu == CPU_686 && strcmp(cpu_vendor, "GenuineIntel") == 0 && 614 (cpu_id & 0xff0) == 0x610) { 615 apic_base = rdmsr(MSR_APICBASE); 616 apic_base |= APICBASE_ENABLED; 617 wrmsr(MSR_APICBASE, apic_base); 618 } 619 620 /* Second, probe the CPU's in the system. */ 621 retval = best_enum->apic_probe_cpus(); 622 if (retval != 0) 623 printf("%s: Failed to probe CPUs: returned %d\n", 624 best_enum->apic_name, retval); 625 626 /* Third, initialize the local APIC. */ 627 retval = best_enum->apic_setup_local(); 628 if (retval != 0) 629 printf("%s: Failed to setup the local APIC: returned %d\n", 630 best_enum->apic_name, retval); 631#ifdef SMP 632 /* Last, setup the cpu topology now that we have probed CPUs */ 633 mp_topology(); 634#endif 635} 636SYSINIT(apic_init, SI_SUB_CPU, SI_ORDER_FIRST, apic_init, NULL) 637 638/* 639 * Setup the I/O APICs. 640 */ 641static void 642apic_setup_io(void *dummy __unused) 643{ 644 int retval; 645 646 if (best_enum == NULL) 647 return; 648 retval = best_enum->apic_setup_io(); 649 if (retval != 0) 650 printf("%s: Failed to setup I/O APICs: returned %d\n", 651 best_enum->apic_name, retval); 652 653 /* 654 * Finish setting up the local APIC on the BSP once we know how to 655 * properly program the LINT pins. 656 */ 657 lapic_setup(); 658 if (bootverbose) 659 lapic_dump("BSP"); 660} 661SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_SECOND, apic_setup_io, NULL) 662 663#ifdef SMP 664/* 665 * Inter Processor Interrupt functions. The lapic_ipi_*() functions are 666 * private to the sys/i386 code. The public interface for the rest of the 667 * kernel is defined in mp_machdep.c. 668 */ 669int 670lapic_ipi_wait(int delay) 671{ 672 int x, incr; 673 674 /* 675 * Wait delay loops for IPI to be sent. This is highly bogus 676 * since this is sensitive to CPU clock speed. If delay is 677 * -1, we wait forever. 678 */ 679 if (delay == -1) { 680 incr = 0; 681 delay = 1; 682 } else 683 incr = 1; 684 for (x = 0; x < delay; x += incr) { 685 if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE) 686 return (1); 687 ia32_pause(); 688 } 689 return (0); 690} 691 692void 693lapic_ipi_raw(register_t icrlo, u_int dest) 694{ 695 register_t value, eflags; 696 697 /* XXX: Need more sanity checking of icrlo? */ 698 KASSERT(lapic != NULL, ("%s called too early", __func__)); 699 KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, 700 ("%s: invalid dest field", __func__)); 701 KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0, 702 ("%s: reserved bits set in ICR LO register", __func__)); 703 704 /* Set destination in ICR HI register if it is being used. */ 705 eflags = intr_disable(); 706 if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) { 707 value = lapic->icr_hi; 708 value &= ~APIC_ID_MASK; 709 value |= dest << APIC_ID_SHIFT; 710 lapic->icr_hi = value; 711 } 712 713 /* Program the contents of the IPI and dispatch it. */ 714 value = lapic->icr_lo; 715 value &= APIC_ICRLO_RESV_MASK; 716 value |= icrlo; 717 lapic->icr_lo = value; 718 intr_restore(eflags); 719} 720 721#define BEFORE_SPIN 1000000 722#ifdef DETECT_DEADLOCK 723#define AFTER_SPIN 1000 724#endif 725 726void 727lapic_ipi_vectored(u_int vector, int dest) 728{ 729 register_t icrlo, destfield; 730 731 KASSERT((vector & ~APIC_VECTOR_MASK) == 0, 732 ("%s: invalid vector %d", __func__, vector)); 733 734 icrlo = vector | APIC_DELMODE_FIXED | APIC_DESTMODE_PHY | 735 APIC_LEVEL_DEASSERT | APIC_TRIGMOD_EDGE; 736 destfield = 0; 737 switch (dest) { 738 case APIC_IPI_DEST_SELF: 739 icrlo |= APIC_DEST_SELF; 740 break; 741 case APIC_IPI_DEST_ALL: 742 icrlo |= APIC_DEST_ALLISELF; 743 break; 744 case APIC_IPI_DEST_OTHERS: 745 icrlo |= APIC_DEST_ALLESELF; 746 break; 747 default: 748 KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, 749 ("%s: invalid destination 0x%x", __func__, dest)); 750 destfield = dest; 751 } 752 753 /* Wait for an earlier IPI to finish. */ 754 if (!lapic_ipi_wait(BEFORE_SPIN)) 755 panic("APIC: Previous IPI is stuck"); 756 757 lapic_ipi_raw(icrlo, destfield); 758 759#ifdef DETECT_DEADLOCK 760 /* Wait for IPI to be delivered. */ 761 if (!lapic_ipi_wait(AFTER_SPIN)) { 762#ifdef needsattention 763 /* 764 * XXX FIXME: 765 * 766 * The above function waits for the message to actually be 767 * delivered. It breaks out after an arbitrary timeout 768 * since the message should eventually be delivered (at 769 * least in theory) and that if it wasn't we would catch 770 * the failure with the check above when the next IPI is 771 * sent. 772 * 773 * We could skip this wait entirely, EXCEPT it probably 774 * protects us from other routines that assume that the 775 * message was delivered and acted upon when this function 776 * returns. 777 */ 778 printf("APIC: IPI might be stuck\n"); 779#else /* !needsattention */ 780 /* Wait until mesage is sent without a timeout. */ 781 while (lapic->icr_lo & APIC_DELSTAT_PEND) 782 ia32_pause(); 783#endif /* needsattention */ 784 } 785#endif /* DETECT_DEADLOCK */ 786} 787#endif /* SMP */ 788