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