1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2018 Joyent, Inc. 25 */ 26 27 #define PSMI_1_7 28 29 #include <sys/mutex.h> 30 #include <sys/types.h> 31 #include <sys/time.h> 32 #include <sys/machlock.h> 33 #include <sys/smp_impldefs.h> 34 #include <sys/uadmin.h> 35 #include <sys/promif.h> 36 #include <sys/psm.h> 37 #include <sys/pit.h> 38 #include <sys/apic.h> 39 #include <sys/psm_common.h> 40 #include <sys/atomic.h> 41 #include <sys/archsystm.h> 42 43 #define NSEC_IN_SEC 1000000000 44 45 /* 46 * Local Function Prototypes 47 */ 48 static void uppc_softinit(void); 49 static void uppc_picinit(); 50 static int uppc_post_cpu_start(void); 51 static int uppc_clkinit(int); 52 static int uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl); 53 static int uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl); 54 static processorid_t uppc_get_next_processorid(processorid_t cpu_id); 55 static int uppc_get_clockirq(int ipl); 56 static int uppc_probe(void); 57 static int uppc_translate_irq(dev_info_t *dip, int irqno); 58 static void uppc_shutdown(int cmd, int fcn); 59 static void uppc_preshutdown(int cmd, int fcn); 60 static int uppc_state(psm_state_request_t *request); 61 static int uppc_init_acpi(void); 62 static void uppc_setspl(int); 63 static int uppc_intr_enter(int, int *); 64 static void uppc_intr_exit(int, int); 65 static hrtime_t uppc_gethrtime(); 66 67 static int uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip, 68 int *pci_irqp, iflag_t *intr_flagp); 69 70 /* 71 * Global Data 72 */ 73 static struct standard_pic pics0; 74 int uppc_use_acpi = 1; /* Use ACPI by default */ 75 int uppc_enable_acpi = 0; 76 77 78 /* 79 * For interrupt link devices, if uppc_unconditional_srs is set, an irq resource 80 * will be assigned (via _SRS). If it is not set, use the current 81 * irq setting (via _CRS), but only if that irq is in the set of possible 82 * irqs (returned by _PRS) for the device. 83 */ 84 int uppc_unconditional_srs = 1; 85 86 /* 87 * For interrupt link devices, if uppc_prefer_crs is set when we are 88 * assigning an IRQ resource to a device, prefer the current IRQ setting 89 * over other possible irq settings under same conditions. 90 */ 91 int uppc_prefer_crs = 1; 92 93 int uppc_verbose = 0; 94 95 /* flag definitions for uppc_verbose */ 96 #define UPPC_VERBOSE_IRQ_FLAG 0x00000001 97 #define UPPC_VERBOSE_POWEROFF_FLAG 0x00000002 98 #define UPPC_VERBOSE_POWEROFF_PAUSE_FLAG 0x00000004 99 100 101 #define UPPC_VERBOSE_IRQ(fmt) \ 102 if (uppc_verbose & UPPC_VERBOSE_IRQ_FLAG) \ 103 cmn_err fmt; 104 105 #define UPPC_VERBOSE_POWEROFF(fmt) \ 106 if (uppc_verbose & UPPC_VERBOSE_POWEROFF_FLAG) \ 107 prom_printf fmt; 108 109 uchar_t uppc_reserved_irqlist[MAX_ISA_IRQ + 1]; 110 111 static uint16_t uppc_irq_shared_table[MAX_ISA_IRQ + 1]; 112 113 /* 114 * Contains SCI irqno from FADT after initialization 115 */ 116 static int uppc_sci = -1; 117 118 /* 119 * Local Static Data 120 */ 121 122 static lock_t uppc_gethrtime_lock; 123 static hrtime_t uppc_lasthrtime; 124 125 126 #ifdef UPPC_DEBUG 127 #define DENT 0x0001 128 129 static int uppc_debug = 0; 130 131 132 #endif 133 134 135 static struct psm_ops uppc_ops = { 136 uppc_probe, /* psm_probe */ 137 138 uppc_softinit, /* psm_init */ 139 uppc_picinit, /* psm_picinit */ 140 uppc_intr_enter, /* psm_intr_enter */ 141 uppc_intr_exit, /* psm_intr_exit */ 142 uppc_setspl, /* psm_setspl */ 143 uppc_addspl, /* psm_addspl */ 144 uppc_delspl, /* psm_delspl */ 145 (int (*)(processorid_t))NULL, /* psm_disable_intr */ 146 (void (*)(processorid_t))NULL, /* psm_enable_intr */ 147 (int (*)(int))NULL, /* psm_softlvl_to_irq */ 148 (void (*)(int))NULL, /* psm_set_softintr */ 149 (void (*)(processorid_t))NULL, /* psm_set_idlecpu */ 150 (void (*)(processorid_t))NULL, /* psm_unset_idlecpu */ 151 152 uppc_clkinit, /* psm_clkinit */ 153 uppc_get_clockirq, /* psm_get_clockirq */ 154 (void (*)(void))NULL, /* psm_hrtimeinit */ 155 uppc_gethrtime, /* psm_gethrtime */ 156 157 uppc_get_next_processorid, /* psm_get_next_processorid */ 158 (int (*)(processorid_t, caddr_t))NULL, /* psm_cpu_start */ 159 uppc_post_cpu_start, /* psm_post_cpu_start */ 160 uppc_shutdown, /* psm_shutdown */ 161 (int (*)(int, int))NULL, /* psm_get_ipivect */ 162 (void (*)(processorid_t, int))NULL, /* psm_send_ipi */ 163 164 uppc_translate_irq, /* psm_translate_irq */ 165 166 (void (*)(int, char *))NULL, /* psm_notify_error */ 167 (void (*)(int msg))NULL, /* psm_notify_func */ 168 (void (*)(hrtime_t time))NULL, /* psm_timer_reprogram */ 169 (void (*)(void))NULL, /* psm_timer_enable */ 170 (void (*)(void))NULL, /* psm_timer_disable */ 171 (void (*)(void *arg))NULL, /* psm_post_cyclic_setup */ 172 uppc_preshutdown, /* psm_preshutdown */ 173 174 (int (*)(dev_info_t *, ddi_intr_handle_impl_t *, 175 psm_intr_op_t, int *))NULL, /* psm_intr_ops */ 176 177 uppc_state, /* psm_state */ 178 (int (*)(psm_cpu_request_t *))NULL, /* psm_cpu_ops */ 179 180 (int (*)(void))NULL, /* psm_get_pir_ipivect */ 181 (void (*)(processorid_t))NULL, /* psm_send_pir_ipi */ 182 }; 183 184 185 static struct psm_info uppc_info = { 186 PSM_INFO_VER01_7, /* version */ 187 PSM_OWN_SYS_DEFAULT, /* ownership */ 188 (struct psm_ops *)&uppc_ops, /* operation */ 189 "uppc", /* machine name */ 190 "UniProcessor PC", /* machine descriptions */ 191 }; 192 193 /* 194 * Configuration Data 195 */ 196 197 /* 198 * This is the loadable module wrapper. 199 */ 200 #include <sys/modctl.h> 201 202 static void *uppc_hdlp; 203 204 int 205 _init(void) 206 { 207 return (psm_mod_init(&uppc_hdlp, &uppc_info)); 208 } 209 210 int 211 _fini(void) 212 { 213 return (psm_mod_fini(&uppc_hdlp, &uppc_info)); 214 } 215 216 int 217 _info(struct modinfo *modinfop) 218 { 219 return (psm_mod_info(&uppc_hdlp, &uppc_info, modinfop)); 220 } 221 222 /* 223 * Autoconfiguration Routines 224 */ 225 226 static int 227 uppc_probe(void) 228 { 229 230 231 return (PSM_SUCCESS); 232 } 233 234 static void 235 uppc_softinit(void) 236 { 237 struct standard_pic *pp; 238 int i; 239 240 pp = &pics0; 241 242 243 if (uppc_use_acpi && uppc_init_acpi()) { 244 build_reserved_irqlist((uchar_t *)uppc_reserved_irqlist); 245 for (i = 0; i <= MAX_ISA_IRQ; i++) 246 uppc_irq_shared_table[i] = 0; 247 uppc_enable_acpi = 1; 248 } 249 250 /* 251 * initialize the ipl mask 252 */ 253 for (i = 0; i < (MAXIPL << 1); i += 2) { 254 /* enable slave lines on master */ 255 pp->c_iplmask[i] = 0xff; 256 pp->c_iplmask[i+1] = (0xff & ~(1 << MASTERLINE)); 257 } 258 } 259 260 /*ARGSUSED*/ 261 static int 262 uppc_clkinit(int hertz) 263 { 264 ulong_t clkticks = PIT_HZ / hz; 265 266 if (hertz == 0) 267 return (0); /* One shot mode not supported */ 268 269 /* 270 * program timer 0 271 */ 272 outb(PITCTL_PORT, (PIT_C0|PIT_NDIVMODE|PIT_READMODE)); 273 outb(PITCTR0_PORT, (uchar_t)clkticks); 274 outb(PITCTR0_PORT, (uchar_t)(clkticks>>8)); 275 276 return (NSEC_IN_SEC / hertz); 277 } 278 279 static void 280 uppc_picinit() 281 { 282 picsetup(); 283 284 /* 285 * If a valid SCI is present, manually addspl() 286 * since we're not set-up early enough in boot 287 * to do it "conventionally" (via add_avintr) 288 */ 289 if (uppc_sci >= 0) 290 (void) uppc_addspl(uppc_sci, SCI_IPL, SCI_IPL, SCI_IPL); 291 } 292 293 static int 294 uppc_post_cpu_start(void) 295 { 296 /* 297 * On uppc machines psm_post_cpu_start is called during S3 resume 298 * on the boot cpu from assembly, using the ap_mlsetup vector. 299 */ 300 301 /* 302 * Init master and slave pic 303 */ 304 picsetup(); 305 306 /* 307 * program timer 0 308 */ 309 (void) uppc_clkinit(hz); 310 311 return (PSM_SUCCESS); 312 } 313 314 /*ARGSUSED3*/ 315 static int 316 uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl) 317 { 318 struct standard_pic *pp; 319 int i; 320 int startidx; 321 uchar_t vectmask; 322 323 if (irqno <= MAX_ISA_IRQ) 324 atomic_inc_16(&uppc_irq_shared_table[irqno]); 325 326 if (ipl != min_ipl) 327 return (0); 328 329 if (irqno > 7) { 330 vectmask = 1 << (irqno - 8); 331 startidx = (ipl << 1); 332 } else { 333 vectmask = 1 << irqno; 334 startidx = (ipl << 1) + 1; 335 } 336 337 /* 338 * mask intr same or above ipl 339 * level MAXIPL has all intr off as init. default 340 */ 341 pp = &pics0; 342 for (i = startidx; i < (MAXIPL << 1); i += 2) { 343 if (pp->c_iplmask[i] & vectmask) 344 break; 345 pp->c_iplmask[i] |= vectmask; 346 } 347 348 /* 349 * unmask intr below ipl 350 */ 351 for (i = startidx-2; i >= 0; i -= 2) { 352 if (!(pp->c_iplmask[i] & vectmask)) 353 break; 354 pp->c_iplmask[i] &= ~vectmask; 355 } 356 return (0); 357 } 358 359 static int 360 uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl) 361 { 362 struct standard_pic *pp; 363 int i; 364 uchar_t vectmask; 365 366 if (irqno <= MAX_ISA_IRQ) 367 atomic_dec_16(&uppc_irq_shared_table[irqno]); 368 369 /* 370 * skip if we are not deleting the last handler 371 * and the ipl is higher than minimum 372 */ 373 if ((max_ipl != PSM_INVALID_IPL) && (ipl >= min_ipl)) 374 return (0); 375 376 if (irqno > 7) { 377 vectmask = 1 << (irqno - 8); 378 i = 0; 379 } else { 380 vectmask = 1 << irqno; 381 i = 1; 382 } 383 384 pp = &pics0; 385 386 /* 387 * check any handlers left for this irqno 388 */ 389 if (max_ipl != PSM_INVALID_IPL) { 390 /* 391 * unmasks all levels below the lowest priority 392 */ 393 i += ((min_ipl - 1) << 1); 394 for (; i >= 0; i -= 2) { 395 if (!(pp->c_iplmask[i] & vectmask)) 396 break; 397 pp->c_iplmask[i] &= ~vectmask; 398 } 399 } else { 400 /* 401 * set mask to all levels 402 */ 403 for (; i < (MAXIPL << 1); i += 2) { 404 if (pp->c_iplmask[i] & vectmask) 405 break; 406 pp->c_iplmask[i] |= vectmask; 407 } 408 } 409 return (0); 410 } 411 412 static processorid_t 413 uppc_get_next_processorid(processorid_t cpu_id) 414 { 415 if (cpu_id == -1) 416 return (0); 417 return (-1); 418 } 419 420 /*ARGSUSED*/ 421 static int 422 uppc_get_clockirq(int ipl) 423 { 424 return (CLOCK_VECTOR); 425 } 426 427 428 static int 429 uppc_init_acpi(void) 430 { 431 int verboseflags = 0; 432 int sci; 433 iflag_t sci_flags; 434 435 /* 436 * Process SCI configuration here; this may return 437 * an error if acpi-user-options has specified 438 * legacy mode (use ACPI without ACPI mode or SCI) 439 */ 440 if (acpica_get_sci(&sci, &sci_flags) != AE_OK) 441 sci = -1; 442 443 /* 444 * Initialize sub-system - if error is returns, ACPI is not 445 * used. 446 */ 447 if (acpica_init() != AE_OK) 448 return (0); 449 450 /* 451 * uppc implies system is in PIC mode; set edge/level 452 * via ELCR based on return value from get_sci; this 453 * will default to level/low if no override present, 454 * as recommended by Intel ACPI CA team. 455 */ 456 if (sci >= 0) { 457 ASSERT((sci_flags.intr_el == INTR_EL_LEVEL) || 458 (sci_flags.intr_el == INTR_EL_EDGE)); 459 460 psm_set_elcr(sci, sci_flags.intr_el == INTR_EL_LEVEL); 461 } 462 463 /* 464 * Remember SCI for later use 465 */ 466 uppc_sci = sci; 467 468 if (uppc_verbose & UPPC_VERBOSE_IRQ_FLAG) 469 verboseflags |= PSM_VERBOSE_IRQ_FLAG; 470 471 if (uppc_verbose & UPPC_VERBOSE_POWEROFF_FLAG) 472 verboseflags |= PSM_VERBOSE_POWEROFF_FLAG; 473 474 if (uppc_verbose & UPPC_VERBOSE_POWEROFF_PAUSE_FLAG) 475 verboseflags |= PSM_VERBOSE_POWEROFF_PAUSE_FLAG; 476 477 if (acpi_psm_init(uppc_info.p_mach_idstring, verboseflags) == 478 ACPI_PSM_FAILURE) { 479 return (0); 480 } 481 482 return (1); 483 } 484 485 486 static void 487 uppc_preshutdown(int cmd, int fcn) 488 { 489 UPPC_VERBOSE_POWEROFF(("uppc_preshutdown(%d,%d);\n", cmd, fcn)); 490 491 } 492 493 static void 494 uppc_shutdown(int cmd, int fcn) 495 { 496 UPPC_VERBOSE_POWEROFF(("uppc_shutdown(%d,%d);\n", cmd, fcn)); 497 498 /* 499 * Return if passed a command other than A_SHUTDOWN or 500 * if we're not using ACPI. 501 */ 502 if ((cmd != A_SHUTDOWN) || (!uppc_enable_acpi)) 503 return; 504 505 /* 506 * Switch system back into Legacy-Mode if using ACPI and 507 * not powering-off. Some BIOSes need to remain in ACPI-mode 508 * for power-off to succeed (Dell Dimension 4600) 509 */ 510 if (fcn != AD_POWEROFF) { 511 (void) AcpiDisable(); 512 return; 513 } 514 515 (void) acpi_poweroff(); 516 } 517 518 519 static int 520 uppc_acpi_enter_picmode(void) 521 { 522 ACPI_OBJECT_LIST arglist; 523 ACPI_OBJECT arg; 524 ACPI_STATUS status; 525 526 /* Setup parameter object */ 527 arglist.Count = 1; 528 arglist.Pointer = &arg; 529 arg.Type = ACPI_TYPE_INTEGER; 530 arg.Integer.Value = ACPI_PIC_MODE; 531 532 status = AcpiEvaluateObject(NULL, "\\_PIC", &arglist, NULL); 533 if (ACPI_FAILURE(status)) 534 return (PSM_FAILURE); 535 else 536 return (PSM_SUCCESS); 537 } 538 539 540 struct pic_state { 541 int8_t mmask; 542 int8_t smask; 543 uint16_t elcr; 544 }; 545 546 547 static void 548 pic_save_state(struct pic_state *sp) 549 { 550 struct standard_pic *pp; 551 int vecno; 552 553 /* 554 * Only the PIC masks and the ELCR can be saved; 555 * other 8259 state is write-only 556 */ 557 558 /* 559 * save current master and slave interrupt mask 560 */ 561 pp = &pics0; 562 sp->smask = pp->c_curmask[0]; 563 sp->mmask = pp->c_curmask[1]; 564 565 /* 566 * save edge/level configuration for isa interrupts 567 */ 568 sp->elcr = 0; 569 for (vecno = 0; vecno <= MAX_ISA_IRQ; vecno++) 570 sp->elcr |= psm_get_elcr(vecno) << vecno; 571 } 572 573 static void 574 pic_restore_state(struct pic_state *sp) 575 { 576 int vecno; 577 578 /* Restore master and slave interrupt masks */ 579 outb(SIMR_PORT, sp->smask); 580 outb(MIMR_PORT, sp->mmask); 581 582 /* Read master to allow pics to settle */ 583 (void) inb(MIMR_PORT); 584 585 /* Restore edge/level configuration for isa interupts */ 586 for (vecno = 0; vecno <= MAX_ISA_IRQ; vecno++) 587 psm_set_elcr(vecno, sp->elcr & (1 << vecno)); 588 589 /* Reenter PIC mode before restoring LNK devices */ 590 (void) uppc_acpi_enter_picmode(); 591 592 /* Restore ACPI link device mappings */ 593 acpi_restore_link_devices(); 594 } 595 596 static int 597 uppc_state(psm_state_request_t *rp) 598 { 599 switch (rp->psr_cmd) { 600 case PSM_STATE_ALLOC: 601 rp->req.psm_state_req.psr_state = 602 kmem_zalloc(sizeof (struct pic_state), KM_NOSLEEP); 603 if (rp->req.psm_state_req.psr_state == NULL) 604 return (ENOMEM); 605 rp->req.psm_state_req.psr_state_size = 606 sizeof (struct pic_state); 607 return (0); 608 case PSM_STATE_FREE: 609 kmem_free(rp->req.psm_state_req.psr_state, 610 rp->req.psm_state_req.psr_state_size); 611 return (0); 612 case PSM_STATE_SAVE: 613 pic_save_state(rp->req.psm_state_req.psr_state); 614 return (0); 615 case PSM_STATE_RESTORE: 616 pic_restore_state(rp->req.psm_state_req.psr_state); 617 return (0); 618 default: 619 return (EINVAL); 620 } 621 } 622 623 624 static int 625 uppc_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid, 626 int ipin, int *pci_irqp, iflag_t *intr_flagp) 627 { 628 int status; 629 acpi_psm_lnk_t acpipsmlnk; 630 631 if ((status = acpi_get_irq_cache_ent(busid, devid, ipin, pci_irqp, 632 intr_flagp)) == ACPI_PSM_SUCCESS) { 633 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Found irqno %d " 634 "from cache for device %s, instance #%d\n", *pci_irqp, 635 ddi_get_name(dip), ddi_get_instance(dip))); 636 return (status); 637 } 638 639 bzero(&acpipsmlnk, sizeof (acpi_psm_lnk_t)); 640 641 if ((status = acpi_translate_pci_irq(dip, ipin, pci_irqp, 642 intr_flagp, &acpipsmlnk)) == ACPI_PSM_FAILURE) { 643 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: " 644 " acpi_translate_pci_irq failed for device %s, instance" 645 " #%d\n", ddi_get_name(dip), ddi_get_instance(dip))); 646 647 return (status); 648 } 649 650 if (status == ACPI_PSM_PARTIAL && acpipsmlnk.lnkobj != NULL) { 651 status = uppc_acpi_irq_configure(&acpipsmlnk, dip, pci_irqp, 652 intr_flagp); 653 if (status != ACPI_PSM_SUCCESS) { 654 status = acpi_get_current_irq_resource(&acpipsmlnk, 655 pci_irqp, intr_flagp); 656 } 657 } 658 659 if (status == ACPI_PSM_SUCCESS) { 660 acpi_new_irq_cache_ent(busid, devid, ipin, *pci_irqp, 661 intr_flagp, &acpipsmlnk); 662 psm_set_elcr(*pci_irqp, 1); /* set IRQ to PCI mode */ 663 664 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: [ACPI] " 665 "new irq %d for device %s, instance #%d\n", 666 *pci_irqp, ddi_get_name(dip), ddi_get_instance(dip))); 667 } 668 669 return (status); 670 } 671 672 /* 673 * Configures the irq for the interrupt link device identified by 674 * acpipsmlnkp. 675 * 676 * Gets the current and the list of possible irq settings for the 677 * device. If uppc_unconditional_srs is not set, and the current 678 * resource setting is in the list of possible irq settings, 679 * current irq resource setting is passed to the caller. 680 * 681 * Otherwise, picks an irq number from the list of possible irq 682 * settings, and sets the irq of the device to this value. 683 * If prefer_crs is set, among a set of irq numbers in the list that have 684 * the least number of devices sharing the interrupt, we pick current irq 685 * resource setting if it is a member of this set. 686 * 687 * Passes the irq number in the value pointed to by pci_irqp, and 688 * polarity and sensitivity in the structure pointed to by dipintrflagp 689 * to the caller. 690 * 691 * Note that if setting the irq resource failed, but successfuly obtained 692 * the current irq resource settings, passes the current irq resources 693 * and considers it a success. 694 * 695 * Returns: 696 * ACPI_PSM_SUCCESS on success. 697 * 698 * ACPI_PSM_FAILURE if an error occured during the configuration or 699 * if a suitable irq was not found for this device, or if setting the 700 * irq resource and obtaining the current resource fails. 701 * 702 */ 703 static int 704 uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip, 705 int *pci_irqp, iflag_t *dipintr_flagp) 706 { 707 int i, min_share, foundnow, done = 0; 708 int32_t irq; 709 int32_t share_irq = -1; 710 int32_t chosen_irq = -1; 711 int cur_irq = -1; 712 acpi_irqlist_t *irqlistp; 713 acpi_irqlist_t *irqlistent; 714 715 if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp)) 716 == ACPI_PSM_FAILURE) { 717 UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: Unable to determine " 718 "or assign IRQ for device %s, instance #%d: The system was " 719 "unable to get the list of potential IRQs from ACPI.", 720 ddi_get_name(dip), ddi_get_instance(dip))); 721 722 return (ACPI_PSM_FAILURE); 723 } 724 725 if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq, 726 dipintr_flagp) == ACPI_PSM_SUCCESS) && (!uppc_unconditional_srs) && 727 (cur_irq > 0)) { 728 729 if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL) 730 == ACPI_PSM_SUCCESS) { 731 732 acpi_free_irqlist(irqlistp); 733 ASSERT(pci_irqp != NULL); 734 *pci_irqp = cur_irq; 735 return (ACPI_PSM_SUCCESS); 736 } 737 UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: Could not find the " 738 "current irq %d for device %s, instance #%d in ACPI's " 739 "list of possible irqs for this device. Picking one from " 740 " the latter list.", cur_irq, ddi_get_name(dip), 741 ddi_get_instance(dip))); 742 743 } 744 745 irqlistent = irqlistp; 746 min_share = 255; 747 748 while (irqlistent != NULL) { 749 750 for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) { 751 752 irq = irqlistp->irqs[i]; 753 754 if ((irq > MAX_ISA_IRQ) || 755 (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) || 756 (irq == 0)) 757 continue; 758 759 if (uppc_reserved_irqlist[irq]) 760 continue; 761 762 if (uppc_irq_shared_table[irq] == 0) { 763 chosen_irq = irq; 764 foundnow = 1; 765 if (!(uppc_prefer_crs) || (irq == cur_irq)) { 766 done = 1; 767 break; 768 } 769 } 770 771 if ((uppc_irq_shared_table[irq] < min_share) || 772 ((uppc_irq_shared_table[irq] == min_share) && 773 (cur_irq == irq) && (uppc_prefer_crs))) { 774 min_share = uppc_irq_shared_table[irq]; 775 share_irq = irq; 776 foundnow = 1; 777 } 778 } 779 780 /* If we found an IRQ in the inner loop, save the details */ 781 if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) { 782 /* 783 * Copy the acpi_prs_private_t and flags from this 784 * irq list entry, since we found an irq from this 785 * entry. 786 */ 787 acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv; 788 *dipintr_flagp = irqlistent->intr_flags; 789 } 790 791 if (done) 792 break; 793 794 /* Load the next entry in the irqlist */ 795 irqlistent = irqlistent->next; 796 } 797 798 acpi_free_irqlist(irqlistp); 799 800 if (chosen_irq != -1) 801 irq = chosen_irq; 802 else if (share_irq != -1) 803 irq = share_irq; 804 else { 805 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Could not find a " 806 "suitable irq from the list of possible irqs for device " 807 "%s, instance #%d in ACPI's list of possible\n", 808 ddi_get_name(dip), ddi_get_instance(dip))); 809 810 return (ACPI_PSM_FAILURE); 811 } 812 813 814 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Setting irq %d for device %s " 815 "instance #%d\n", irq, ddi_get_name(dip), ddi_get_instance(dip))); 816 817 if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) { 818 /* 819 * setting irq was successful, check to make sure CRS 820 * reflects that. If CRS does not agree with what we 821 * set, return the irq that was set. 822 */ 823 824 if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq, 825 dipintr_flagp) == ACPI_PSM_SUCCESS) { 826 827 if (cur_irq != irq) 828 UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: " 829 "IRQ resource set (irqno %d) for device %s " 830 "instance #%d, differs from current " 831 "setting irqno %d", 832 irq, ddi_get_name(dip), 833 ddi_get_instance(dip), cur_irq)); 834 } 835 /* 836 * return the irq that was set, and not what CRS reports, 837 * since CRS has been seen to be bogus on some systems 838 */ 839 cur_irq = irq; 840 } else { 841 UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: set resource irq %d " 842 "failed for device %s instance #%d", 843 irq, ddi_get_name(dip), ddi_get_instance(dip))); 844 if (cur_irq == -1) 845 return (ACPI_PSM_FAILURE); 846 } 847 848 ASSERT(pci_irqp != NULL); 849 *pci_irqp = cur_irq; 850 return (ACPI_PSM_SUCCESS); 851 } 852 853 854 /*ARGSUSED*/ 855 static int 856 uppc_translate_irq(dev_info_t *dip, int irqno) 857 { 858 char dev_type[16]; 859 int dev_len, pci_irq, devid, busid; 860 ddi_acc_handle_t cfg_handle; 861 uchar_t ipin, iline; 862 iflag_t intr_flag; 863 864 if (dip == NULL) { 865 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: irqno = %d" 866 " dip = NULL\n", irqno)); 867 return (irqno); 868 } 869 870 if (!uppc_enable_acpi) { 871 return (irqno); 872 } 873 874 dev_len = sizeof (dev_type); 875 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip), 876 DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, 877 &dev_len) != DDI_PROP_SUCCESS) { 878 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: irqno %d" 879 "device %s instance %d no device_type\n", irqno, 880 ddi_get_name(dip), ddi_get_instance(dip))); 881 return (irqno); 882 } 883 884 if ((strcmp(dev_type, "pci") == 0) || 885 (strcmp(dev_type, "pciex") == 0)) { 886 887 /* pci device */ 888 if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0) 889 return (irqno); 890 891 if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS) 892 return (irqno); 893 894 ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA; 895 iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE); 896 if (uppc_acpi_translate_pci_irq(dip, busid, devid, 897 ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) { 898 899 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: [ACPI] new irq " 900 "%d old irq %d device %s, instance %d\n", pci_irq, 901 irqno, ddi_get_name(dip), ddi_get_instance(dip))); 902 903 /* 904 * Make sure pci_irq is within range. 905 * Otherwise, fall through and return irqno. 906 */ 907 if (pci_irq <= MAX_ISA_IRQ) { 908 if (iline != pci_irq) { 909 /* 910 * Update the device's ILINE byte, 911 * in case uppc_acpi_translate_pci_irq 912 * has choosen a different pci_irq 913 * than the BIOS has configured. 914 * Some chipsets use the value in 915 * ILINE to control interrupt routing, 916 * in conflict with the PCI spec. 917 */ 918 pci_config_put8(cfg_handle, 919 PCI_CONF_ILINE, pci_irq); 920 } 921 pci_config_teardown(&cfg_handle); 922 return (pci_irq); 923 } 924 } 925 pci_config_teardown(&cfg_handle); 926 927 /* FALLTHRU to common case - returning irqno */ 928 } else { 929 /* non-PCI; assumes ISA-style edge-triggered */ 930 psm_set_elcr(irqno, 0); /* set IRQ to ISA mode */ 931 932 UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: non-pci," 933 "irqno %d device %s instance %d\n", irqno, 934 ddi_get_name(dip), ddi_get_instance(dip))); 935 } 936 937 return (irqno); 938 } 939 940 /* 941 * uppc_intr_enter() raises the ipl to the level of the current interrupt, 942 * and sends EOI to the pics. 943 * If interrupt is 7 or 15 and not spurious interrupt, send specific EOI 944 * else send non-specific EOI 945 * uppc_intr_enter() returns the new priority level, 946 * or -1 for spurious interrupt 947 */ 948 static int 949 uppc_intr_enter(int ipl, int *vector) 950 { 951 int newipl; 952 int intno; 953 954 intno = (*vector); 955 956 ASSERT(intno < 256); 957 958 newipl = autovect[intno].avh_hi_pri; 959 960 /* 961 * During wait_till_seen() periods when interrupt vector is being 962 * removed in remove_av(), the removed hardware interrupt could 963 * trigger and got here with newipl 0. It has to send EOI 964 * as usual but no need to call setspl and returns -1 like spurious. 965 */ 966 if ((intno & 7) != 7) { 967 if (newipl) 968 uppc_setspl(newipl); 969 outb(MCMD_PORT, PIC_NSEOI); 970 if (intno >= 8) { 971 outb(SCMD_PORT, PIC_NSEOI); 972 } 973 } else { /* int was 7 or 15 */ 974 if (newipl && newipl <= ipl) { /* Check for spurious int */ 975 if (intno != 7) 976 outb(MCMD_PORT, PIC_NSEOI); 977 return (-1); /* Spurious int */ 978 } else { 979 if (newipl) 980 uppc_setspl(newipl); 981 if (intno != 7) { 982 outb(MCMD_PORT, PIC_NSEOI); 983 outb(SCMD_PORT, PIC_SEOI_LVL7); 984 } else { 985 outb(MCMD_PORT, PIC_SEOI_LVL7); 986 } 987 } 988 } 989 990 if (newipl) 991 return (newipl); 992 else 993 return (-1); /* not real spurious int */ 994 } 995 996 /* 997 * uppc_intr_exit() restores the old interrupt 998 * priority level after processing an interrupt. 999 * It is called with interrupts disabled, and does not enable interrupts. 1000 */ 1001 /* ARGSUSED */ 1002 static void 1003 uppc_intr_exit(int ipl, int vector) 1004 { 1005 uppc_setspl(ipl); 1006 } 1007 1008 /* 1009 * uppc_setspl() loads new interrupt masks into the pics 1010 * based on input ipl. 1011 */ 1012 /* ARGSUSED */ 1013 static void 1014 uppc_setspl(int ipl) 1015 { 1016 struct standard_pic *pp; 1017 uint8_t smask, mmask; 1018 uint8_t cursmask, curmmask; 1019 1020 pp = &pics0; 1021 smask = pp->c_iplmask[ipl * 2]; 1022 mmask = pp->c_iplmask[ipl * 2 + 1]; 1023 cursmask = pp->c_curmask[0]; 1024 curmmask = pp->c_curmask[1]; 1025 if (cursmask == smask && curmmask == mmask) 1026 return; 1027 pp->c_curmask[0] = smask; 1028 pp->c_curmask[1] = mmask; 1029 1030 if (cursmask != smask) { 1031 /* 1032 * program new slave pic mask 1033 */ 1034 outb(SIMR_PORT, smask); 1035 } 1036 if (curmmask != mmask) { 1037 /* 1038 * program new master pic mask 1039 */ 1040 outb(MIMR_PORT, mmask); 1041 } 1042 /* 1043 * read master to allow pics to settle 1044 */ 1045 (void) inb(MIMR_PORT); 1046 } 1047 1048 /* 1049 * uppc_gethrtime() returns high resolution timer value 1050 */ 1051 static hrtime_t 1052 uppc_gethrtime() 1053 { 1054 hrtime_t timeval, temp; 1055 unsigned int ctr0; 1056 ulong_t oflags; 1057 1058 oflags = intr_clear(); /* disable ints */ 1059 lock_set(&uppc_gethrtime_lock); 1060 retry: 1061 temp = hrtime_base; 1062 outb(PITCTL_PORT, 0); /* latch counter 0 */ 1063 /* 1064 * read counter 0 1065 */ 1066 ctr0 = inb(PITCTR0_PORT); 1067 ctr0 |= inb(PITCTR0_PORT) << 8; 1068 timeval = (hrtime_t)ctr0 * (NANOSEC / PIT_HZ); 1069 if (temp != hrtime_base) 1070 goto retry; 1071 timeval -= temp; 1072 if (timeval < uppc_lasthrtime) 1073 timeval = uppc_lasthrtime; 1074 uppc_lasthrtime = timeval; 1075 lock_clear(&uppc_gethrtime_lock); 1076 intr_restore(oflags); 1077 return (timeval); 1078 } 1079