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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/cmn_err.h> 32 #include <sys/promif.h> 33 #include <sys/acpi/acpi.h> 34 #include <sys/acpica.h> 35 #include <sys/sunddi.h> 36 #include <sys/ddi.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/pci.h> 39 #include <sys/debug.h> 40 #include <sys/psm_common.h> 41 #include <sys/sunndi.h> 42 #include <sys/ksynch.h> 43 44 /* 45 * ACPI Poweroff patchable options in acpi_poweroff_opt for broken BIOS 46 * workarounds. 47 */ 48 #define ACPI_PO_CLRWAK 0x0001 49 #define ACPI_PO_CLRALL 0x0002 50 #define ACPI_PO_RSTGPE 0x0004 51 #define ACPI_PO_DISARB 0x0008 52 #define ACPI_PO_2NDTRY 0x0010 53 54 /* Global configurables */ 55 56 char *psm_module_name; /* used to store name of psm module */ 57 58 /* 59 * acpi_irq_check_elcr: when set elcr will also be consulted for building 60 * the reserved irq list. When 0 (false), the existing state of the ELCR 61 * is ignored when selecting a vector during IRQ translation, and the ELCR 62 * is programmed to the proper setting for the type of bus (level-triggered 63 * for PCI, edge-triggered for non-PCI). When non-zero (true), vectors 64 * set to edge-mode will not be used when in PIC-mode. The default value 65 * is 0 (false). Note that ACPI's SCI vector is always set to conform to 66 * ACPI-specification regardless of this. 67 * 68 */ 69 int acpi_irq_check_elcr = 0; 70 71 /* 72 * acpi_s5_slp_typ: 73 * If >= 0 then override the \_S5 parameter return value. This is useful 74 * for systems with broken \_S5 methods which return the wrong value for 75 * the chipset in use. 76 */ 77 int acpi_s5_slp_typ = -1; 78 int acpi_s5_slp_typ2 = -1; /* second parameter (only patch if different) */ 79 int acpi_poweroff_opt = 0; /* patchable poweroff options */ 80 81 int psm_verbose = 0; 82 83 #define PSM_VERBOSE_IRQ(fmt) \ 84 if (psm_verbose & PSM_VERBOSE_IRQ_FLAG) \ 85 cmn_err fmt; 86 87 #define PSM_VERBOSE_POWEROFF(fmt) \ 88 if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \ 89 psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \ 90 prom_printf fmt; 91 92 #define PSM_VERBOSE_POWEROFF_PAUSE(fmt) \ 93 if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \ 94 psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) {\ 95 prom_printf fmt; \ 96 if (psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \ 97 (void) goany(); \ 98 } 99 100 101 /* Local storage */ 102 static ACPI_HANDLE acpi_sbobj = NULL; 103 static kmutex_t acpi_irq_cache_mutex; 104 105 #define D2A_INITLEN 20 106 static int d2a_len = 0; 107 static int d2a_valid = 0; 108 static d2a *d2a_table; 109 110 /* 111 * irq_cache_table is a list that serves a two-key cache. It is used 112 * as a pci busid/devid/ipin <-> irq cache and also as a acpi 113 * interrupt lnk <-> irq cache. 114 */ 115 static irq_cache_t *irq_cache_table; 116 117 #define IRQ_CACHE_INITLEN 20 118 static int irq_cache_len = 0; 119 static int irq_cache_valid = 0; 120 121 static int acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno, 122 int ipin, int *pci_irqp, iflag_t *iflagp, acpi_psm_lnk_t *acpipsmlnkp); 123 124 static int acpi_eval_lnk(dev_info_t *dip, char *lnkname, 125 int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp); 126 127 static int acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp, 128 iflag_t *intr_flagp); 129 130 extern int goany(void); 131 132 133 #define NEXT_PRT_ITEM(p) \ 134 (ACPI_PCI_ROUTING_TABLE *)(((char *)(p)) + (p)->Length) 135 136 static int 137 acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno, int ipin, 138 int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp) 139 { 140 ACPI_BUFFER rb; 141 ACPI_PCI_ROUTING_TABLE *prtp; 142 int status; 143 int dev_adr; 144 145 /* 146 * Get the IRQ routing table 147 */ 148 rb.Pointer = NULL; 149 rb.Length = ACPI_ALLOCATE_BUFFER; 150 if (AcpiGetIrqRoutingTable(pciobj, &rb) != AE_OK) { 151 return (ACPI_PSM_FAILURE); 152 } 153 154 status = ACPI_PSM_FAILURE; 155 dev_adr = (devno << 16 | 0xffff); 156 for (prtp = rb.Pointer; prtp->Length != 0; prtp = NEXT_PRT_ITEM(prtp)) { 157 /* look until a matching dev/pin is found */ 158 if (dev_adr != prtp->Address || ipin != prtp->Pin) 159 continue; 160 161 /* NULL Source name means index is GSIV */ 162 if (*prtp->Source == 0) { 163 intr_flagp->intr_el = TRIGGER_LEVEL; 164 intr_flagp->intr_po = POLARITY_ACTIVE_LOW; 165 ASSERT(pci_irqp != NULL); 166 *pci_irqp = prtp->SourceIndex; 167 status = ACPI_PSM_SUCCESS; 168 } else 169 status = acpi_eval_lnk(dip, prtp->Source, pci_irqp, 170 intr_flagp, acpipsmlnkp); 171 172 break; 173 174 } 175 176 AcpiOsFree(rb.Pointer); 177 return (status); 178 } 179 180 /* 181 * 182 * If the interrupt link device is already configured, 183 * stores polarity and sensitivity in the structure pointed to by 184 * intr_flagp, and irqno in the value pointed to by pci_irqp. 185 * 186 * Returns: 187 * ACPI_PSM_SUCCESS if the interrupt link device is already configured. 188 * ACPI_PSM_PARTIAL if configuration is needed. 189 * ACPI_PSM_FAILURE in case of error. 190 * 191 * When two devices share the same interrupt link device, and the 192 * link device is already configured (i.e. found in the irq cache) 193 * we need to use the already configured irq instead of reconfiguring 194 * the link device. 195 */ 196 static int 197 acpi_eval_lnk(dev_info_t *dip, char *lnkname, int *pci_irqp, 198 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp) 199 { 200 ACPI_HANDLE tmpobj; 201 ACPI_HANDLE lnkobj; 202 int status; 203 204 /* 205 * Convert the passed-in link device name to a handle 206 */ 207 if (AcpiGetHandle(NULL, lnkname, &lnkobj) != AE_OK) { 208 return (ACPI_PSM_FAILURE); 209 } 210 211 /* 212 * Assume that the link device is invalid if no _CRS method 213 * exists, since _CRS method is a required method 214 */ 215 if (AcpiGetHandle(lnkobj, "_CRS", &tmpobj) != AE_OK) { 216 return (ACPI_PSM_FAILURE); 217 } 218 219 ASSERT(acpipsmlnkp != NULL); 220 acpipsmlnkp->lnkobj = lnkobj; 221 if ((acpi_get_irq_lnk_cache_ent(lnkobj, pci_irqp, intr_flagp)) == 222 ACPI_PSM_SUCCESS) { 223 PSM_VERBOSE_IRQ((CE_CONT, "!psm: link object found from cache " 224 " for device %s, instance #%d, irq no %d\n", 225 ddi_get_name(dip), ddi_get_instance(dip), *pci_irqp)); 226 return (ACPI_PSM_SUCCESS); 227 } else { 228 if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) { 229 acpipsmlnkp->device_status = (uchar_t)status; 230 } 231 232 return (ACPI_PSM_PARTIAL); 233 } 234 } 235 236 int 237 acpi_psm_init(char *module_name, int verbose_flags) 238 { 239 psm_module_name = module_name; 240 241 psm_verbose = verbose_flags; 242 243 if (AcpiGetHandle(NULL, "\\_SB", &acpi_sbobj) != AE_OK) { 244 cmn_err(CE_WARN, "!psm: get _SB failed"); 245 return (ACPI_PSM_FAILURE); 246 } 247 248 mutex_init(&acpi_irq_cache_mutex, NULL, MUTEX_DEFAULT, NULL); 249 250 return (ACPI_PSM_SUCCESS); 251 252 } 253 254 /* 255 * Return bus/dev/fn for PCI dip (note: not the parent "pci" node). 256 */ 257 258 int 259 get_bdf(dev_info_t *dip, int *bus, int *device, int *func) 260 { 261 pci_regspec_t *pci_rp; 262 int len; 263 264 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 265 "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS) 266 return (-1); 267 268 if (len < (sizeof (pci_regspec_t) / sizeof (int))) { 269 ddi_prop_free(pci_rp); 270 return (-1); 271 } 272 if (bus != NULL) 273 *bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi); 274 if (device != NULL) 275 *device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi); 276 if (func != NULL) 277 *func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 278 ddi_prop_free(pci_rp); 279 return (0); 280 } 281 282 283 /* 284 * Build the reserved ISA irq list, and store it in the table pointed to by 285 * reserved_irqs_table. The caller is responsible for allocating this table 286 * with a minimum of MAX_ISA_IRQ + 1 entries. 287 * 288 * The routine looks in the device tree at the subtree rooted at /isa 289 * for each of the devices under that node, if an interrupts property 290 * is present, its values are used to "reserve" irqs so that later ACPI 291 * configuration won't choose those irqs. 292 * 293 * In addition, if acpi_irq_check_elcr is set, will use ELCR register 294 * to identify reserved IRQs. 295 */ 296 void 297 build_reserved_irqlist(uchar_t *reserved_irqs_table) 298 { 299 dev_info_t *isanode = ddi_find_devinfo("isa", -1, 0); 300 dev_info_t *isa_child = 0; 301 int i; 302 uint_t elcrval; 303 304 /* Initialize the reserved ISA IRQs: */ 305 for (i = 0; i < MAX_ISA_IRQ; i++) 306 reserved_irqs_table[i] = 0; 307 308 if (acpi_irq_check_elcr) { 309 310 elcrval = (inb(ELCR_PORT2) << 8) | (inb(ELCR_PORT1)); 311 if (ELCR_EDGE(elcrval, 0) && ELCR_EDGE(elcrval, 1) && 312 ELCR_EDGE(elcrval, 2) && ELCR_EDGE(elcrval, 8) && 313 ELCR_EDGE(elcrval, 13)) { 314 /* valid ELCR */ 315 for (i = 0; i < MAX_ISA_IRQ; i++) 316 if (!ELCR_LEVEL(elcrval, i)) 317 reserved_irqs_table[i] = 1; 318 } 319 } 320 321 /* always check the isa devinfo nodes */ 322 323 if (isanode != 0) { /* Found ISA */ 324 uint_t intcnt; /* Interrupt count */ 325 int *intrs; /* Interrupt values */ 326 327 /* Load first child: */ 328 isa_child = ddi_get_child(isanode); 329 while (isa_child != 0) { /* Iterate over /isa children */ 330 /* if child has any interrupts, save them */ 331 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, isa_child, 332 DDI_PROP_DONTPASS, "interrupts", &intrs, &intcnt) 333 == DDI_PROP_SUCCESS) { 334 /* 335 * iterate over child interrupt list, adding 336 * them to the reserved irq list 337 */ 338 while (intcnt-- > 0) { 339 /* 340 * Each value MUST be <= MAX_ISA_IRQ 341 */ 342 343 if ((intrs[intcnt] > MAX_ISA_IRQ) || 344 (intrs[intcnt] < 0)) 345 continue; 346 347 reserved_irqs_table[intrs[intcnt]] = 1; 348 } 349 ddi_prop_free(intrs); 350 } 351 isa_child = ddi_get_next_sibling(isa_child); 352 } 353 /* The isa node was held by ddi_find_devinfo, so release it */ 354 ndi_rele_devi(isanode); 355 } 356 357 /* 358 * Reserve IRQ14 & IRQ15 for IDE. It shouldn't be hard-coded 359 * here but there's no other way to find the irqs for 360 * legacy-mode ata (since it's hard-coded in pci-ide also). 361 */ 362 reserved_irqs_table[14] = 1; 363 reserved_irqs_table[15] = 1; 364 } 365 366 /* 367 * Examine devinfo node to determine if it is a PCI-PCI bridge 368 * 369 * Returns: 370 * 0 if not a bridge or error 371 * 1 if a bridge 372 */ 373 static int 374 psm_is_pci_bridge(dev_info_t *dip) 375 { 376 ddi_acc_handle_t cfg_handle; 377 int rv = 0; 378 379 if (pci_config_setup(dip, &cfg_handle) == DDI_SUCCESS) { 380 rv = ((pci_config_get8(cfg_handle, PCI_CONF_BASCLASS) == 381 PCI_CLASS_BRIDGE) && (pci_config_get8(cfg_handle, 382 PCI_CONF_SUBCLASS) == PCI_BRIDGE_PCI)); 383 pci_config_teardown(&cfg_handle); 384 } 385 386 return (rv); 387 } 388 389 390 /* 391 * Examines ACPI node for presence of _PRT object 392 * 393 * Returns: 394 * 0 if no _PRT or error 395 * 1 if _PRT is present 396 */ 397 static int 398 psm_node_has_prt(ACPI_HANDLE *ah) 399 { 400 ACPI_HANDLE rh; 401 402 return (AcpiGetHandle(ah, "_PRT", &rh) == AE_OK); 403 } 404 405 406 /* 407 * Look first for an ACPI PCI bus node matching busid, then for a _PRT on the 408 * parent node; then drop into the bridge-chasing code (which will also 409 * look for _PRTs on the way up the tree of bridges) 410 * 411 * Stores polarity and sensitivity in the structure pointed to by 412 * intr_flagp, and irqno in the value pointed to by pci_irqp. * 413 * Returns: 414 * ACPI_PSM_SUCCESS on success. 415 * ACPI_PSM_PARTIAL to indicate need to configure the interrupt 416 * link device. 417 * ACPI_PSM_FAILURE if an error prevented the system from 418 * obtaining irq information for dip. 419 */ 420 int 421 acpi_translate_pci_irq(dev_info_t *dip, int ipin, int *pci_irqp, 422 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp) 423 { 424 ACPI_HANDLE pciobj; 425 int status = AE_ERROR; 426 dev_info_t *curdip, *parentdip; 427 int curpin, curbus, curdev; 428 429 430 curpin = ipin; 431 curdip = dip; 432 while (curdip != ddi_root_node()) { 433 parentdip = ddi_get_parent(curdip); 434 ASSERT(parentdip != NULL); 435 436 if (get_bdf(curdip, &curbus, &curdev, NULL) != 0) { 437 break; 438 } 439 440 status = acpica_find_pciobj(parentdip, &pciobj); 441 if ((status == AE_OK) && psm_node_has_prt(pciobj)) { 442 return (acpi_get_gsiv(curdip, pciobj, curdev, curpin, 443 pci_irqp, intr_flagp, acpipsmlnkp)); 444 } 445 446 /* if we got here, we need to traverse a bridge upwards */ 447 if (!psm_is_pci_bridge(parentdip)) 448 break; 449 450 /* 451 * This is the rotating scheme that Compaq is using 452 * and documented in the PCI-PCI spec. Also, if the 453 * PCI-PCI bridge is behind another PCI-PCI bridge, 454 * then it needs to keep ascending until an interrupt 455 * entry is found or the top is reached 456 */ 457 curpin = (curdev + curpin) % PCI_INTD; 458 curdip = parentdip; 459 } 460 461 /* 462 * We should never, ever get here; didn't find a _PRT 463 */ 464 return (ACPI_PSM_FAILURE); 465 } 466 467 /* 468 * Sets the irq resource of the lnk object to the requested irq value. 469 * 470 * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure. 471 */ 472 int 473 acpi_set_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int irq) 474 { 475 ACPI_BUFFER rsb; 476 ACPI_RESOURCE *resp; 477 ACPI_RESOURCE *srsp; 478 ACPI_HANDLE lnkobj; 479 int status; 480 481 ASSERT(acpipsmlnkp != NULL); 482 483 lnkobj = acpipsmlnkp->lnkobj; 484 485 /* 486 * Fetch the possible resources for the link 487 */ 488 489 rsb.Pointer = NULL; 490 rsb.Length = ACPI_ALLOCATE_BUFFER; 491 status = AcpiGetPossibleResources(lnkobj, &rsb); 492 if (status != AE_OK) { 493 cmn_err(CE_WARN, "!psm: set_irq: _PRS failed"); 494 return (ACPI_PSM_FAILURE); 495 } 496 497 /* 498 * Find an IRQ resource descriptor to use as template 499 */ 500 srsp = NULL; 501 for (resp = rsb.Pointer; resp->Length != 0; 502 resp = ACPI_NEXT_RESOURCE(resp)) { 503 if ((resp->Id == ACPI_RSTYPE_IRQ) || 504 (resp->Id == ACPI_RSTYPE_EXT_IRQ)) { 505 /* 506 * Mild trickery here; allocate two 507 * resource structures, and set the Length 508 * field of the second one to 0 to terminate 509 * the list. Copy the possible resource into 510 * the first one as a template. 511 */ 512 srsp = kmem_zalloc(2 * sizeof (*srsp), KM_SLEEP); 513 srsp[1].Length = 0; 514 *srsp = *resp; 515 break; /* drop out of the loop */ 516 } 517 } 518 519 /* 520 * We're done with the PRS values, toss 'em lest we forget 521 */ 522 AcpiOsFree(rsb.Pointer); 523 524 if (srsp == NULL) 525 return (ACPI_PSM_FAILURE); 526 527 /* 528 * The Interrupts[] array is always at least one entry 529 * long; see the definition of ACPI_RESOURCE. 530 */ 531 switch (srsp->Id) { 532 case ACPI_RSTYPE_IRQ: 533 srsp->Data.Irq.NumberOfInterrupts = 1; 534 srsp->Data.Irq.Interrupts[0] = irq; 535 break; 536 case ACPI_RSTYPE_EXT_IRQ: 537 srsp->Data.ExtendedIrq.NumberOfInterrupts = 1; 538 srsp->Data.ExtendedIrq.Interrupts[0] = irq; 539 break; 540 } 541 542 rsb.Pointer = srsp; 543 rsb.Length = 2 * sizeof (*srsp); 544 status = AcpiSetCurrentResources(lnkobj, &rsb); 545 kmem_free(srsp, 2 * sizeof (*srsp)); 546 if (status != AE_OK) { 547 cmn_err(CE_WARN, "!psm: set_irq: _SRS failed"); 548 return (ACPI_PSM_FAILURE); 549 } 550 551 if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) { 552 acpipsmlnkp->device_status = (uchar_t)status; 553 return (ACPI_PSM_SUCCESS); 554 } else 555 return (ACPI_PSM_FAILURE); 556 } 557 558 559 /* 560 * 561 */ 562 static int 563 psm_acpi_edgelevel(UINT32 el) 564 { 565 switch (el) { 566 case ACPI_EDGE_SENSITIVE: 567 return (INTR_EL_EDGE); 568 case ACPI_LEVEL_SENSITIVE: 569 return (INTR_EL_LEVEL); 570 default: 571 /* el is a single bit; should never reach here */ 572 return (INTR_EL_CONFORM); 573 } 574 } 575 576 577 /* 578 * 579 */ 580 static int 581 psm_acpi_po(UINT32 po) 582 { 583 switch (po) { 584 case ACPI_ACTIVE_HIGH: 585 return (INTR_PO_ACTIVE_HIGH); 586 case ACPI_ACTIVE_LOW: 587 return (INTR_PO_ACTIVE_LOW); 588 default: 589 /* po is a single bit; should never reach here */ 590 return (INTR_PO_CONFORM); 591 } 592 } 593 594 595 /* 596 * Retrieves the current irq setting for the interrrupt link device. 597 * 598 * Stores polarity and sensitivity in the structure pointed to by 599 * intr_flagp, and irqno in the value pointed to by pci_irqp. 600 * 601 * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure. 602 */ 603 int 604 acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp, 605 iflag_t *intr_flagp) 606 { 607 ACPI_HANDLE lnkobj; 608 ACPI_BUFFER rb; 609 ACPI_RESOURCE *rp; 610 int irq; 611 int status = ACPI_PSM_FAILURE; 612 613 ASSERT(acpipsmlnkp != NULL); 614 lnkobj = acpipsmlnkp->lnkobj; 615 616 if (!(acpipsmlnkp->device_status & STA_PRESENT) || 617 !(acpipsmlnkp->device_status & STA_ENABLE)) { 618 PSM_VERBOSE_IRQ((CE_WARN, "!psm: crs device either not " 619 "present or disabled, status 0x%x", 620 acpipsmlnkp->device_status)); 621 return (ACPI_PSM_FAILURE); 622 } 623 624 rb.Pointer = NULL; 625 rb.Length = ACPI_ALLOCATE_BUFFER; 626 if (AcpiGetCurrentResources(lnkobj, &rb) != AE_OK) { 627 PSM_VERBOSE_IRQ((CE_WARN, "!psm: no crs object found or" 628 " evaluation failed")); 629 return (ACPI_PSM_FAILURE); 630 } 631 632 irq = -1; 633 for (rp = rb.Pointer; rp->Length != 0; rp = ACPI_NEXT_RESOURCE(rp)) { 634 if (rp->Id == ACPI_RSTYPE_IRQ) { 635 if (irq > 0) { 636 PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ" 637 " from _CRS ")); 638 status = ACPI_PSM_FAILURE; 639 break; 640 } 641 642 if (rp->Data.Irq.NumberOfInterrupts != 1) { 643 PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt" 644 " from _CRS ")); 645 status = ACPI_PSM_FAILURE; 646 break; 647 } 648 649 intr_flagp->intr_el = psm_acpi_edgelevel( 650 rp->Data.Irq.EdgeLevel); 651 intr_flagp->intr_po = psm_acpi_po( 652 rp->Data.Irq.ActiveHighLow); 653 irq = rp->Data.Irq.Interrupts[0]; 654 status = ACPI_PSM_SUCCESS; 655 } else if (rp->Id == ACPI_RSTYPE_EXT_IRQ) { 656 if (irq > 0) { 657 PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ" 658 " from _CRS ")); 659 status = ACPI_PSM_FAILURE; 660 break; 661 } 662 663 if (rp->Data.ExtendedIrq.NumberOfInterrupts != 1) { 664 PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt" 665 " from _CRS ")); 666 status = ACPI_PSM_FAILURE; 667 break; 668 } 669 670 intr_flagp->intr_el = psm_acpi_edgelevel( 671 rp->Data.ExtendedIrq.EdgeLevel); 672 intr_flagp->intr_po = psm_acpi_po( 673 rp->Data.ExtendedIrq.ActiveHighLow); 674 irq = rp->Data.ExtendedIrq.Interrupts[0]; 675 status = ACPI_PSM_SUCCESS; 676 } 677 } 678 679 AcpiOsFree(rb.Pointer); 680 if (status == ACPI_PSM_SUCCESS) { 681 *pci_irqp = irq; 682 } 683 684 return (status); 685 } 686 687 /* 688 * Searches for the given IRQ in the irqlist passed in. 689 * 690 * If multiple matches exist, this returns true on the first match. 691 * Returns the interrupt flags, if a match was found, in `intr_flagp' if 692 * it's passed in non-NULL 693 */ 694 int 695 acpi_irqlist_find_irq(acpi_irqlist_t *irqlistp, int irq, iflag_t *intr_flagp) 696 { 697 int found = 0; 698 int i; 699 700 while (irqlistp != NULL && !found) { 701 for (i = 0; i < irqlistp->num_irqs; i++) { 702 if (irqlistp->irqs[i] == irq) { 703 if (intr_flagp) 704 *intr_flagp = irqlistp->intr_flags; 705 found = 1; 706 break; /* out of for() */ 707 } 708 } 709 } 710 711 return (found ? ACPI_PSM_SUCCESS : ACPI_PSM_FAILURE); 712 } 713 714 /* 715 * Frees the irqlist allocated by acpi_get_possible_irq_resource. 716 * It takes a count of number of entries in the list. 717 */ 718 void 719 acpi_free_irqlist(acpi_irqlist_t *irqlistp) 720 { 721 acpi_irqlist_t *freednode; 722 723 while (irqlistp != NULL) { 724 /* Free the irq list */ 725 kmem_free(irqlistp->irqs, irqlistp->num_irqs * 726 sizeof (int32_t)); 727 728 freednode = irqlistp; 729 irqlistp = irqlistp->next; 730 kmem_free(freednode, sizeof (acpi_irqlist_t)); 731 } 732 } 733 734 /* 735 * Creates a new entry in the given irqlist with the information passed in. 736 */ 737 static void 738 acpi_add_irqlist_entry(acpi_irqlist_t **irqlistp, uint32_t *irqlist, 739 int irqlist_len, iflag_t *intr_flagp) 740 { 741 acpi_irqlist_t *newent; 742 743 ASSERT(irqlist != NULL); 744 ASSERT(intr_flagp != NULL); 745 746 newent = kmem_alloc(sizeof (acpi_irqlist_t), KM_SLEEP); 747 newent->intr_flags = *intr_flagp; 748 newent->irqs = irqlist; 749 newent->num_irqs = irqlist_len; 750 newent->next = *irqlistp; 751 752 *irqlistp = newent; 753 } 754 755 756 /* 757 * Retrieves a list of possible interrupt settings for the interrupt link 758 * device. 759 * 760 * Stores polarity and sensitivity in the structure pointed to by intr_flagp. 761 * Updates value pointed to by irqlistp with the address of a table it 762 * allocates. where interrupt numbers are stored. Stores the number of entries 763 * in this table in the value pointed to by num_entriesp; 764 * 765 * Each element in this table is of type int32_t. The table should be later 766 * freed by caller via acpi_free_irq_list(). 767 * 768 * Returns ACPI_PSM_SUCCESS on success and ACPI_PSM_FAILURE upon failure 769 */ 770 int 771 acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp, 772 acpi_irqlist_t **irqlistp) 773 { 774 ACPI_HANDLE lnkobj; 775 ACPI_BUFFER rsb; 776 ACPI_RESOURCE *resp; 777 int status; 778 779 int i, el, po, irqlist_len; 780 uint32_t *irqlist, *tmplist; 781 iflag_t intr_flags; 782 783 ASSERT(acpipsmlnkp != NULL); 784 lnkobj = acpipsmlnkp->lnkobj; 785 786 rsb.Pointer = NULL; 787 rsb.Length = ACPI_ALLOCATE_BUFFER; 788 status = AcpiGetPossibleResources(lnkobj, &rsb); 789 if (status != AE_OK) { 790 cmn_err(CE_WARN, "!psm: get_irq: _PRS failed"); 791 return (ACPI_PSM_FAILURE); 792 } 793 794 /* 795 * Scan the resources looking for an interrupt resource 796 */ 797 *irqlistp = 0; 798 for (resp = rsb.Pointer; resp->Length != 0; 799 resp = ACPI_NEXT_RESOURCE(resp)) { 800 switch (resp->Id) { 801 case ACPI_RSTYPE_IRQ: 802 irqlist_len = resp->Data.Irq.NumberOfInterrupts; 803 tmplist = resp->Data.Irq.Interrupts; 804 el = resp->Data.Irq.EdgeLevel; 805 po = resp->Data.Irq.ActiveHighLow; 806 break; 807 case ACPI_RSTYPE_EXT_IRQ: 808 irqlist_len = resp->Data.ExtendedIrq.NumberOfInterrupts; 809 tmplist = resp->Data.ExtendedIrq.Interrupts; 810 el = resp->Data.ExtendedIrq.EdgeLevel; 811 po = resp->Data.ExtendedIrq.ActiveHighLow; 812 break; 813 default: 814 continue; 815 } 816 /* NEEDSWORK: move this into add_irqlist_entry someday */ 817 irqlist = kmem_zalloc(irqlist_len * sizeof (*irqlist), 818 KM_SLEEP); 819 for (i = 0; i < irqlist_len; i++) 820 irqlist[i] = tmplist[i]; 821 intr_flags.intr_el = psm_acpi_edgelevel(el); 822 intr_flags.intr_po = psm_acpi_po(po); 823 acpi_add_irqlist_entry(irqlistp, irqlist, irqlist_len, 824 &intr_flags); 825 } 826 827 AcpiOsFree(rsb.Pointer); 828 return (irqlistp == NULL ? ACPI_PSM_FAILURE : ACPI_PSM_SUCCESS); 829 } 830 831 /* 832 * Adds a new cache entry to the irq cache which maps an irq and 833 * its attributes to PCI bus/dev/ipin and optionally to its associated ACPI 834 * interrupt link device object. 835 */ 836 void 837 acpi_new_irq_cache_ent(int bus, int dev, int ipin, int pci_irq, 838 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp) 839 { 840 int newsize; 841 irq_cache_t *new_arr, *ep; 842 843 mutex_enter(&acpi_irq_cache_mutex); 844 if (irq_cache_valid >= irq_cache_len) { 845 /* initially, or re-, allocate array */ 846 847 newsize = (irq_cache_len ? 848 irq_cache_len * 2 : IRQ_CACHE_INITLEN); 849 new_arr = kmem_zalloc(newsize * sizeof (irq_cache_t), KM_SLEEP); 850 if (irq_cache_len != 0) { 851 /* realloc: copy data, free old */ 852 bcopy(irq_cache_table, new_arr, 853 irq_cache_len * sizeof (irq_cache_t)); 854 kmem_free(irq_cache_table, 855 irq_cache_len * sizeof (irq_cache_t)); 856 } 857 irq_cache_len = newsize; 858 irq_cache_table = new_arr; 859 } 860 ep = &irq_cache_table[irq_cache_valid++]; 861 ep->bus = (uchar_t)bus; 862 ep->dev = (uchar_t)dev; 863 ep->ipin = (uchar_t)ipin; 864 ep->flags = *intr_flagp; 865 ep->irq = pci_irq; 866 ASSERT(acpipsmlnkp != NULL); 867 ep->lnkobj = acpipsmlnkp->lnkobj; 868 mutex_exit(&acpi_irq_cache_mutex); 869 } 870 871 872 /* 873 * Searches the irq caches for the given bus/dev/ipin. 874 * 875 * If info is found, stores polarity and sensitivity in the structure 876 * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp, 877 * and returns ACPI_PSM_SUCCESS. 878 * Otherwise, ACPI_PSM_FAILURE is returned. 879 */ 880 int 881 acpi_get_irq_cache_ent(uchar_t bus, uchar_t dev, int ipin, 882 int *pci_irqp, iflag_t *intr_flagp) 883 { 884 885 irq_cache_t *irqcachep; 886 int i; 887 int ret = ACPI_PSM_FAILURE; 888 889 mutex_enter(&acpi_irq_cache_mutex); 890 for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid; 891 irqcachep++, i++) 892 if ((irqcachep->bus == bus) && 893 (irqcachep->dev == dev) && 894 (irqcachep->ipin == ipin)) { 895 ASSERT(pci_irqp != NULL && intr_flagp != NULL); 896 *pci_irqp = irqcachep->irq; 897 *intr_flagp = irqcachep->flags; 898 ret = ACPI_PSM_SUCCESS; 899 break; 900 } 901 902 mutex_exit(&acpi_irq_cache_mutex); 903 return (ret); 904 } 905 906 /* 907 * Searches the irq caches for the given interrupt lnk device object. 908 * 909 * If info is found, stores polarity and sensitivity in the structure 910 * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp, 911 * and returns ACPI_PSM_SUCCESS. 912 * Otherwise, ACPI_PSM_FAILURE is returned. 913 */ 914 int 915 acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp, 916 iflag_t *intr_flagp) 917 { 918 919 irq_cache_t *irqcachep; 920 int i; 921 int ret = ACPI_PSM_FAILURE; 922 923 if (lnkobj == NULL) 924 return (ACPI_PSM_FAILURE); 925 926 mutex_enter(&acpi_irq_cache_mutex); 927 for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid; 928 irqcachep++, i++) 929 if (irqcachep->lnkobj == lnkobj) { 930 ASSERT(pci_irqp != NULL); 931 *pci_irqp = irqcachep->irq; 932 ASSERT(intr_flagp != NULL); 933 *intr_flagp = irqcachep->flags; 934 ret = ACPI_PSM_SUCCESS; 935 break; 936 } 937 mutex_exit(&acpi_irq_cache_mutex); 938 return (ret); 939 } 940 941 int 942 acpi_poweroff(void) 943 { 944 PSM_VERBOSE_POWEROFF(("acpi_poweroff: starting poweroff\n")); 945 946 if (AcpiEnterSleepStatePrep(5) != AE_OK) 947 return (1); 948 ACPI_DISABLE_IRQS(); 949 if (AcpiEnterSleepState(5) != AE_OK) { 950 ACPI_ENABLE_IRQS(); 951 return (1); 952 } 953 ACPI_ENABLE_IRQS(); 954 955 /* we should be off; if we get here it's an error */ 956 PSM_VERBOSE_POWEROFF(("acpi_poweroff: failed to actually power off\n")); 957 return (1); 958 } 959 960 961 /* 962 * psm_set_elcr() sets ELCR bit for specified vector 963 */ 964 void 965 psm_set_elcr(int vecno, int val) 966 { 967 int elcr_port = ELCR_PORT1 + (vecno >> 3); 968 int elcr_bit = 1 << (vecno & 0x07); 969 970 ASSERT((vecno >= 0) && (vecno < 16)); 971 972 if (val) { 973 /* set bit to force level-triggered mode */ 974 outb(elcr_port, inb(elcr_port) | elcr_bit); 975 } else { 976 /* clear bit to force edge-triggered mode */ 977 outb(elcr_port, inb(elcr_port) & ~elcr_bit); 978 } 979 } 980 981 /* 982 * psm_get_elcr() returns status of ELCR bit for specific vector 983 */ 984 int 985 psm_get_elcr(int vecno) 986 { 987 int elcr_port = ELCR_PORT1 + (vecno >> 3); 988 int elcr_bit = 1 << (vecno & 0x07); 989 990 ASSERT((vecno >= 0) && (vecno < 16)); 991 992 return ((inb(elcr_port) & elcr_bit) ? 1 : 0); 993 } 994