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