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