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