xref: /titanic_44/usr/src/uts/i86pc/io/psm/psm_common.c (revision cb56572868bfc488bbd3ab847b09db2a25554d44)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56f796756Sdmick  * Common Development and Distribution License (the "License").
66f796756Sdmick  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
228462591dSSusan Scheufele  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/param.h>
277c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
287c478bd9Sstevel@tonic-gate #include <sys/promif.h>
297c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi.h>
307c478bd9Sstevel@tonic-gate #include <sys/acpica.h>
317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
347c478bd9Sstevel@tonic-gate #include <sys/pci.h>
357c478bd9Sstevel@tonic-gate #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/psm_common.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
387c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /* Global configurables */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate char *psm_module_name;	/* used to store name of psm module */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * acpi_irq_check_elcr: when set elcr will also be consulted for building
46450d6964Smyers  * the reserved irq list.  When 0 (false), the existing state of the ELCR
47450d6964Smyers  * is ignored when selecting a vector during IRQ translation, and the ELCR
48450d6964Smyers  * is programmed to the proper setting for the type of bus (level-triggered
49450d6964Smyers  * for PCI, edge-triggered for non-PCI).  When non-zero (true), vectors
50450d6964Smyers  * set to edge-mode will not be used when in PIC-mode.  The default value
51450d6964Smyers  * is 0 (false).  Note that ACPI's SCI vector is always set to conform to
52450d6964Smyers  * ACPI-specification regardless of this.
53450d6964Smyers  *
547c478bd9Sstevel@tonic-gate  */
55450d6964Smyers int acpi_irq_check_elcr = 0;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate int psm_verbose = 0;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	PSM_VERBOSE_IRQ(fmt)	\
607c478bd9Sstevel@tonic-gate 		if (psm_verbose & PSM_VERBOSE_IRQ_FLAG) \
617c478bd9Sstevel@tonic-gate 			cmn_err fmt;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define	PSM_VERBOSE_POWEROFF(fmt)  \
647c478bd9Sstevel@tonic-gate 		if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \
657c478bd9Sstevel@tonic-gate 		    psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \
667c478bd9Sstevel@tonic-gate 			prom_printf fmt;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	PSM_VERBOSE_POWEROFF_PAUSE(fmt) \
697c478bd9Sstevel@tonic-gate 		if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \
707c478bd9Sstevel@tonic-gate 		    psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) {\
717c478bd9Sstevel@tonic-gate 			prom_printf fmt; \
727c478bd9Sstevel@tonic-gate 			if (psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \
737c478bd9Sstevel@tonic-gate 				(void) goany(); \
747c478bd9Sstevel@tonic-gate 		}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /* Local storage */
787c478bd9Sstevel@tonic-gate static ACPI_HANDLE acpi_sbobj = NULL;
797c478bd9Sstevel@tonic-gate static kmutex_t acpi_irq_cache_mutex;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * irq_cache_table is a list that serves a two-key cache. It is used
837c478bd9Sstevel@tonic-gate  * as a pci busid/devid/ipin <-> irq cache and also as a acpi
847c478bd9Sstevel@tonic-gate  * interrupt lnk <-> irq cache.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate static irq_cache_t *irq_cache_table;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate #define	IRQ_CACHE_INITLEN	20
897c478bd9Sstevel@tonic-gate static int irq_cache_len = 0;
907c478bd9Sstevel@tonic-gate static int irq_cache_valid = 0;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static int acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno,
937c478bd9Sstevel@tonic-gate 	int ipin, int *pci_irqp, iflag_t *iflagp,  acpi_psm_lnk_t *acpipsmlnkp);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static int acpi_eval_lnk(dev_info_t *dip, char *lnkname,
967c478bd9Sstevel@tonic-gate     int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static int acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp,
997c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate extern int goany(void);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #define	NEXT_PRT_ITEM(p)	\
105*7ff178cdSJimmy Vetayases 		(void *)(((char *)(p)) + (p)->Length)
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static int
acpi_get_gsiv(dev_info_t * dip,ACPI_HANDLE pciobj,int devno,int ipin,int * pci_irqp,iflag_t * intr_flagp,acpi_psm_lnk_t * acpipsmlnkp)1087c478bd9Sstevel@tonic-gate acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno, int ipin,
1097c478bd9Sstevel@tonic-gate     int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	ACPI_BUFFER rb;
1127c478bd9Sstevel@tonic-gate 	ACPI_PCI_ROUTING_TABLE *prtp;
1137c478bd9Sstevel@tonic-gate 	int status;
1147c478bd9Sstevel@tonic-gate 	int dev_adr;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * Get the IRQ routing table
1187c478bd9Sstevel@tonic-gate 	 */
1197c478bd9Sstevel@tonic-gate 	rb.Pointer = NULL;
1207c478bd9Sstevel@tonic-gate 	rb.Length = ACPI_ALLOCATE_BUFFER;
1217c478bd9Sstevel@tonic-gate 	if (AcpiGetIrqRoutingTable(pciobj, &rb) != AE_OK) {
1227c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	status = ACPI_PSM_FAILURE;
1267c478bd9Sstevel@tonic-gate 	dev_adr = (devno << 16 | 0xffff);
1277c478bd9Sstevel@tonic-gate 	for (prtp = rb.Pointer; prtp->Length != 0; prtp = NEXT_PRT_ITEM(prtp)) {
1287c478bd9Sstevel@tonic-gate 		/* look until a matching dev/pin is found */
1297c478bd9Sstevel@tonic-gate 		if (dev_adr != prtp->Address || ipin != prtp->Pin)
1307c478bd9Sstevel@tonic-gate 			continue;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		/* NULL Source name means index is GSIV */
1337c478bd9Sstevel@tonic-gate 		if (*prtp->Source == 0) {
134db2bae30SDana Myers 			intr_flagp->intr_el = INTR_EL_LEVEL;
135db2bae30SDana Myers 			intr_flagp->intr_po = INTR_PO_ACTIVE_LOW;
1367c478bd9Sstevel@tonic-gate 			ASSERT(pci_irqp != NULL);
1377c478bd9Sstevel@tonic-gate 			*pci_irqp = prtp->SourceIndex;
1387c478bd9Sstevel@tonic-gate 			status = ACPI_PSM_SUCCESS;
1397c478bd9Sstevel@tonic-gate 		} else
1407c478bd9Sstevel@tonic-gate 			status = acpi_eval_lnk(dip, prtp->Source, pci_irqp,
1417c478bd9Sstevel@tonic-gate 			    intr_flagp, acpipsmlnkp);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		break;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	AcpiOsFree(rb.Pointer);
1487c478bd9Sstevel@tonic-gate 	return (status);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  *
1537c478bd9Sstevel@tonic-gate  * If the interrupt link device is already configured,
1547c478bd9Sstevel@tonic-gate  * stores polarity and sensitivity in the structure pointed to by
1557c478bd9Sstevel@tonic-gate  * intr_flagp, and irqno in the value pointed to by pci_irqp.
1567c478bd9Sstevel@tonic-gate  *
1577c478bd9Sstevel@tonic-gate  * Returns:
1587c478bd9Sstevel@tonic-gate  *	ACPI_PSM_SUCCESS if the interrupt link device is already configured.
1597c478bd9Sstevel@tonic-gate  *	ACPI_PSM_PARTIAL if configuration is needed.
1607c478bd9Sstevel@tonic-gate  * 	ACPI_PSM_FAILURE in case of error.
1617c478bd9Sstevel@tonic-gate  *
1627c478bd9Sstevel@tonic-gate  * When two devices share the same interrupt link device, and the
1637c478bd9Sstevel@tonic-gate  * link device is already configured (i.e. found in the irq cache)
1647c478bd9Sstevel@tonic-gate  * we need to use the already configured irq instead of reconfiguring
1657c478bd9Sstevel@tonic-gate  * the link device.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate static int
acpi_eval_lnk(dev_info_t * dip,char * lnkname,int * pci_irqp,iflag_t * intr_flagp,acpi_psm_lnk_t * acpipsmlnkp)1687c478bd9Sstevel@tonic-gate acpi_eval_lnk(dev_info_t *dip, char *lnkname, int *pci_irqp,
1697c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	ACPI_HANDLE	tmpobj;
1727c478bd9Sstevel@tonic-gate 	ACPI_HANDLE	lnkobj;
1737c478bd9Sstevel@tonic-gate 	int status;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
1767c478bd9Sstevel@tonic-gate 	 * Convert the passed-in link device name to a handle
1777c478bd9Sstevel@tonic-gate 	 */
1787c478bd9Sstevel@tonic-gate 	if (AcpiGetHandle(NULL, lnkname, &lnkobj) != AE_OK) {
1797c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * Assume that the link device is invalid if no _CRS method
1847c478bd9Sstevel@tonic-gate 	 * exists, since _CRS method is a required method
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	if (AcpiGetHandle(lnkobj, "_CRS", &tmpobj) != AE_OK) {
1877c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	ASSERT(acpipsmlnkp != NULL);
1917c478bd9Sstevel@tonic-gate 	acpipsmlnkp->lnkobj = lnkobj;
1927c478bd9Sstevel@tonic-gate 	if ((acpi_get_irq_lnk_cache_ent(lnkobj, pci_irqp, intr_flagp)) ==
1937c478bd9Sstevel@tonic-gate 	    ACPI_PSM_SUCCESS) {
1947c478bd9Sstevel@tonic-gate 		PSM_VERBOSE_IRQ((CE_CONT, "!psm: link object found from cache "
1957c478bd9Sstevel@tonic-gate 		    " for device %s, instance #%d, irq no %d\n",
1967c478bd9Sstevel@tonic-gate 		    ddi_get_name(dip), ddi_get_instance(dip), *pci_irqp));
1977c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_SUCCESS);
1987c478bd9Sstevel@tonic-gate 	} else {
1997c478bd9Sstevel@tonic-gate 		if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) {
2007c478bd9Sstevel@tonic-gate 			acpipsmlnkp->device_status = (uchar_t)status;
2017c478bd9Sstevel@tonic-gate 		}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_PARTIAL);
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate int
acpi_psm_init(char * module_name,int verbose_flags)2087c478bd9Sstevel@tonic-gate acpi_psm_init(char *module_name, int verbose_flags)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	psm_module_name = module_name;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	psm_verbose = verbose_flags;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if (AcpiGetHandle(NULL, "\\_SB", &acpi_sbobj) != AE_OK) {
2157c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!psm: get _SB failed");
2167c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	mutex_init(&acpi_irq_cache_mutex, NULL, MUTEX_DEFAULT, NULL);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	return (ACPI_PSM_SUCCESS);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate  * Return bus/dev/fn for PCI dip (note: not the parent "pci" node).
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate int
get_bdf(dev_info_t * dip,int * bus,int * device,int * func)2307c478bd9Sstevel@tonic-gate get_bdf(dev_info_t *dip, int *bus, int *device, int *func)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
2337c478bd9Sstevel@tonic-gate 	int len;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2367c478bd9Sstevel@tonic-gate 	    "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS)
2377c478bd9Sstevel@tonic-gate 		return (-1);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (len < (sizeof (pci_regspec_t) / sizeof (int))) {
2407c478bd9Sstevel@tonic-gate 		ddi_prop_free(pci_rp);
2417c478bd9Sstevel@tonic-gate 		return (-1);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	if (bus != NULL)
2447c478bd9Sstevel@tonic-gate 		*bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi);
2457c478bd9Sstevel@tonic-gate 	if (device != NULL)
2467c478bd9Sstevel@tonic-gate 		*device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi);
2477c478bd9Sstevel@tonic-gate 	if (func != NULL)
2487c478bd9Sstevel@tonic-gate 		*func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
2497c478bd9Sstevel@tonic-gate 	ddi_prop_free(pci_rp);
2507c478bd9Sstevel@tonic-gate 	return (0);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * Build the reserved ISA irq list, and store it in the table pointed to by
2567c478bd9Sstevel@tonic-gate  * reserved_irqs_table. The caller is responsible for allocating this table
2577c478bd9Sstevel@tonic-gate  * with a minimum of MAX_ISA_IRQ + 1 entries.
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  * The routine looks in the device tree at the subtree rooted at /isa
2607c478bd9Sstevel@tonic-gate  * for each of the devices under that node, if an interrupts property
2617c478bd9Sstevel@tonic-gate  * is present, its values are used to "reserve" irqs so that later ACPI
2627c478bd9Sstevel@tonic-gate  * configuration won't choose those irqs.
2637c478bd9Sstevel@tonic-gate  *
2647c478bd9Sstevel@tonic-gate  * In addition, if acpi_irq_check_elcr is set, will use ELCR register
2657c478bd9Sstevel@tonic-gate  * to identify reserved IRQs.
2667c478bd9Sstevel@tonic-gate  */
2677c478bd9Sstevel@tonic-gate void
build_reserved_irqlist(uchar_t * reserved_irqs_table)2687c478bd9Sstevel@tonic-gate build_reserved_irqlist(uchar_t *reserved_irqs_table)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	dev_info_t *isanode = ddi_find_devinfo("isa", -1, 0);
2717c478bd9Sstevel@tonic-gate 	dev_info_t *isa_child = 0;
2727c478bd9Sstevel@tonic-gate 	int i;
2737c478bd9Sstevel@tonic-gate 	uint_t	elcrval;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/* Initialize the reserved ISA IRQs: */
2766f796756Sdmick 	for (i = 0; i <= MAX_ISA_IRQ; i++)
2777c478bd9Sstevel@tonic-gate 		reserved_irqs_table[i] = 0;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if (acpi_irq_check_elcr) {
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		elcrval = (inb(ELCR_PORT2) << 8) | (inb(ELCR_PORT1));
2827c478bd9Sstevel@tonic-gate 		if (ELCR_EDGE(elcrval, 0) && ELCR_EDGE(elcrval, 1) &&
2837c478bd9Sstevel@tonic-gate 		    ELCR_EDGE(elcrval, 2) && ELCR_EDGE(elcrval, 8) &&
2847c478bd9Sstevel@tonic-gate 		    ELCR_EDGE(elcrval, 13)) {
2857c478bd9Sstevel@tonic-gate 			/* valid ELCR */
2866f796756Sdmick 			for (i = 0; i <= MAX_ISA_IRQ; i++)
2877c478bd9Sstevel@tonic-gate 				if (!ELCR_LEVEL(elcrval, i))
2887c478bd9Sstevel@tonic-gate 					reserved_irqs_table[i] = 1;
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* always check the isa devinfo nodes */
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (isanode != 0) { /* Found ISA */
2957c478bd9Sstevel@tonic-gate 		uint_t intcnt;		/* Interrupt count */
2967c478bd9Sstevel@tonic-gate 		int *intrs;		/* Interrupt values */
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		/* Load first child: */
2997c478bd9Sstevel@tonic-gate 		isa_child = ddi_get_child(isanode);
3007c478bd9Sstevel@tonic-gate 		while (isa_child != 0) { /* Iterate over /isa children */
3017c478bd9Sstevel@tonic-gate 			/* if child has any interrupts, save them */
3027c478bd9Sstevel@tonic-gate 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, isa_child,
3037c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "interrupts", &intrs, &intcnt)
3047c478bd9Sstevel@tonic-gate 			    == DDI_PROP_SUCCESS) {
3057c478bd9Sstevel@tonic-gate 				/*
3067c478bd9Sstevel@tonic-gate 				 * iterate over child interrupt list, adding
3077c478bd9Sstevel@tonic-gate 				 * them to the reserved irq list
3087c478bd9Sstevel@tonic-gate 				 */
3097c478bd9Sstevel@tonic-gate 				while (intcnt-- > 0) {
3107c478bd9Sstevel@tonic-gate 					/*
3117c478bd9Sstevel@tonic-gate 					 * Each value MUST be <= MAX_ISA_IRQ
3127c478bd9Sstevel@tonic-gate 					 */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 					if ((intrs[intcnt] > MAX_ISA_IRQ) ||
3157c478bd9Sstevel@tonic-gate 					    (intrs[intcnt] < 0))
3167c478bd9Sstevel@tonic-gate 						continue;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 					reserved_irqs_table[intrs[intcnt]] = 1;
3197c478bd9Sstevel@tonic-gate 				}
3207c478bd9Sstevel@tonic-gate 				ddi_prop_free(intrs);
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 			isa_child = ddi_get_next_sibling(isa_child);
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 		/* The isa node was held by ddi_find_devinfo, so release it */
3257c478bd9Sstevel@tonic-gate 		ndi_rele_devi(isanode);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Reserve IRQ14 & IRQ15 for IDE.  It shouldn't be hard-coded
3307c478bd9Sstevel@tonic-gate 	 * here but there's no other way to find the irqs for
3317c478bd9Sstevel@tonic-gate 	 * legacy-mode ata (since it's hard-coded in pci-ide also).
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	reserved_irqs_table[14] = 1;
3347c478bd9Sstevel@tonic-gate 	reserved_irqs_table[15] = 1;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * Examine devinfo node to determine if it is a PCI-PCI bridge
3397c478bd9Sstevel@tonic-gate  *
3407c478bd9Sstevel@tonic-gate  * Returns:
3417c478bd9Sstevel@tonic-gate  *	0 if not a bridge or error
3427c478bd9Sstevel@tonic-gate  *	1 if a bridge
3437c478bd9Sstevel@tonic-gate  */
3447c478bd9Sstevel@tonic-gate static int
psm_is_pci_bridge(dev_info_t * dip)3457c478bd9Sstevel@tonic-gate psm_is_pci_bridge(dev_info_t *dip)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t cfg_handle;
3487c478bd9Sstevel@tonic-gate 	int rv = 0;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (pci_config_setup(dip, &cfg_handle) == DDI_SUCCESS) {
3517c478bd9Sstevel@tonic-gate 		rv = ((pci_config_get8(cfg_handle, PCI_CONF_BASCLASS) ==
3527c478bd9Sstevel@tonic-gate 		    PCI_CLASS_BRIDGE) && (pci_config_get8(cfg_handle,
3537c478bd9Sstevel@tonic-gate 		    PCI_CONF_SUBCLASS) == PCI_BRIDGE_PCI));
3547c478bd9Sstevel@tonic-gate 		pci_config_teardown(&cfg_handle);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	return (rv);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * Examines ACPI node for presence of _PRT object
3628462591dSSusan Scheufele  * Check _STA to make sure node is present and/or enabled
3637c478bd9Sstevel@tonic-gate  *
3647c478bd9Sstevel@tonic-gate  * Returns:
3657c478bd9Sstevel@tonic-gate  *	0 if no _PRT or error
3667c478bd9Sstevel@tonic-gate  *	1 if _PRT is present
3677c478bd9Sstevel@tonic-gate  */
3687c478bd9Sstevel@tonic-gate static int
psm_node_has_prt(ACPI_HANDLE * ah)3697c478bd9Sstevel@tonic-gate psm_node_has_prt(ACPI_HANDLE *ah)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate 	ACPI_HANDLE rh;
3728462591dSSusan Scheufele 	int sta;
3738462591dSSusan Scheufele 
3748462591dSSusan Scheufele 	/*
3758462591dSSusan Scheufele 	 * Return 0 for "no _PRT" if device does not exist
3768462591dSSusan Scheufele 	 * According to ACPI Spec,
3778462591dSSusan Scheufele 	 * 1) setting either bit 0 or bit 3 means that device exists.
3788462591dSSusan Scheufele 	 * 2) Absence of _STA method means all status bits set.
3798462591dSSusan Scheufele 	 */
3808462591dSSusan Scheufele 	if (ACPI_SUCCESS(acpica_eval_int(ah, "_STA", &sta)) &&
3818462591dSSusan Scheufele 	    !(sta & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)))
3828462591dSSusan Scheufele 		return (0);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	return (AcpiGetHandle(ah, "_PRT", &rh) == AE_OK);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
387*7ff178cdSJimmy Vetayases 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Look first for an ACPI PCI bus node matching busid, then for a _PRT on the
3907c478bd9Sstevel@tonic-gate  * parent node; then drop into the bridge-chasing code (which will also
3917c478bd9Sstevel@tonic-gate  * look for _PRTs on the way up the tree of bridges)
3927c478bd9Sstevel@tonic-gate  *
3937c478bd9Sstevel@tonic-gate  * Stores polarity and sensitivity in the structure pointed to by
3947c478bd9Sstevel@tonic-gate  * intr_flagp, and irqno in the value pointed to by pci_irqp.  *
3957c478bd9Sstevel@tonic-gate  * Returns:
3967c478bd9Sstevel@tonic-gate  *  	ACPI_PSM_SUCCESS on success.
3977c478bd9Sstevel@tonic-gate  *	ACPI_PSM_PARTIAL to indicate need to configure the interrupt
3987c478bd9Sstevel@tonic-gate  *	link device.
3997c478bd9Sstevel@tonic-gate  * 	ACPI_PSM_FAILURE  if an error prevented the system from
4007c478bd9Sstevel@tonic-gate  *	obtaining irq information for dip.
4017c478bd9Sstevel@tonic-gate  */
4027c478bd9Sstevel@tonic-gate int
acpi_translate_pci_irq(dev_info_t * dip,int ipin,int * pci_irqp,iflag_t * intr_flagp,acpi_psm_lnk_t * acpipsmlnkp)4037c478bd9Sstevel@tonic-gate acpi_translate_pci_irq(dev_info_t *dip, int ipin, int *pci_irqp,
4047c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	ACPI_HANDLE pciobj;
4077c478bd9Sstevel@tonic-gate 	int status = AE_ERROR;
4087c478bd9Sstevel@tonic-gate 	dev_info_t *curdip, *parentdip;
4097c478bd9Sstevel@tonic-gate 	int curpin, curbus, curdev;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	curpin = ipin;
4137c478bd9Sstevel@tonic-gate 	curdip = dip;
4147c478bd9Sstevel@tonic-gate 	while (curdip != ddi_root_node()) {
4157c478bd9Sstevel@tonic-gate 		parentdip = ddi_get_parent(curdip);
4167c478bd9Sstevel@tonic-gate 		ASSERT(parentdip != NULL);
4177c478bd9Sstevel@tonic-gate 
418db2bae30SDana Myers 		if (get_bdf(curdip, &curbus, &curdev, NULL) != 0)
4197c478bd9Sstevel@tonic-gate 			break;
4207c478bd9Sstevel@tonic-gate 
4215cff7825Smh27603 		status = acpica_get_handle(parentdip, &pciobj);
4227c478bd9Sstevel@tonic-gate 		if ((status == AE_OK) && psm_node_has_prt(pciobj)) {
4237c478bd9Sstevel@tonic-gate 			return (acpi_get_gsiv(curdip, pciobj, curdev, curpin,
4247c478bd9Sstevel@tonic-gate 			    pci_irqp, intr_flagp, acpipsmlnkp));
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 		/* if we got here, we need to traverse a bridge upwards */
4287c478bd9Sstevel@tonic-gate 		if (!psm_is_pci_bridge(parentdip))
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		/*
4327c478bd9Sstevel@tonic-gate 		 * This is the rotating scheme that Compaq is using
4337c478bd9Sstevel@tonic-gate 		 * and documented in the PCI-PCI spec.  Also, if the
4347c478bd9Sstevel@tonic-gate 		 * PCI-PCI bridge is behind another PCI-PCI bridge,
4357c478bd9Sstevel@tonic-gate 		 * then it needs to keep ascending until an interrupt
4367c478bd9Sstevel@tonic-gate 		 * entry is found or the top is reached
4377c478bd9Sstevel@tonic-gate 		 */
4387c478bd9Sstevel@tonic-gate 		curpin = (curdev + curpin) % PCI_INTD;
4397c478bd9Sstevel@tonic-gate 		curdip = parentdip;
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * We should never, ever get here; didn't find a _PRT
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 	return (ACPI_PSM_FAILURE);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Sets the irq resource of the lnk object to the requested irq value.
4507c478bd9Sstevel@tonic-gate  *
4517c478bd9Sstevel@tonic-gate  * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure.
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate int
acpi_set_irq_resource(acpi_psm_lnk_t * acpipsmlnkp,int irq)4547c478bd9Sstevel@tonic-gate acpi_set_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int irq)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	ACPI_BUFFER	rsb;
4577c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE	*resp;
4587c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE	*srsp;
4597c478bd9Sstevel@tonic-gate 	ACPI_HANDLE lnkobj;
460186507a7Smyers 	int srs_len, status;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	ASSERT(acpipsmlnkp != NULL);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	lnkobj = acpipsmlnkp->lnkobj;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/*
4677c478bd9Sstevel@tonic-gate 	 * Fetch the possible resources for the link
4687c478bd9Sstevel@tonic-gate 	 */
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	rsb.Pointer = NULL;
4717c478bd9Sstevel@tonic-gate 	rsb.Length = ACPI_ALLOCATE_BUFFER;
4727c478bd9Sstevel@tonic-gate 	status = AcpiGetPossibleResources(lnkobj, &rsb);
4737c478bd9Sstevel@tonic-gate 	if (status != AE_OK) {
4747c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!psm: set_irq: _PRS failed");
4757c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	/*
4797c478bd9Sstevel@tonic-gate 	 * Find an IRQ resource descriptor to use as template
4807c478bd9Sstevel@tonic-gate 	 */
4817c478bd9Sstevel@tonic-gate 	srsp = NULL;
482186507a7Smyers 	for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG;
4837c478bd9Sstevel@tonic-gate 	    resp = ACPI_NEXT_RESOURCE(resp)) {
484186507a7Smyers 		if ((resp->Type == ACPI_RESOURCE_TYPE_IRQ) ||
485186507a7Smyers 		    (resp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ)) {
486186507a7Smyers 			ACPI_RESOURCE *endtag;
4877c478bd9Sstevel@tonic-gate 			/*
488186507a7Smyers 			 * Allocate enough room for this resource entry
489186507a7Smyers 			 * and one end tag following it
4907c478bd9Sstevel@tonic-gate 			 */
491186507a7Smyers 			srs_len = resp->Length + sizeof (*endtag);
492186507a7Smyers 			srsp = kmem_zalloc(srs_len, KM_SLEEP);
493186507a7Smyers 			bcopy(resp, srsp, resp->Length);
494186507a7Smyers 			endtag = ACPI_NEXT_RESOURCE(srsp);
495186507a7Smyers 			endtag->Type = ACPI_RESOURCE_TYPE_END_TAG;
496186507a7Smyers 			endtag->Length = 0;
4977c478bd9Sstevel@tonic-gate 			break;	/* drop out of the loop */
4987c478bd9Sstevel@tonic-gate 		}
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/*
5027c478bd9Sstevel@tonic-gate 	 * We're done with the PRS values, toss 'em lest we forget
5037c478bd9Sstevel@tonic-gate 	 */
5047c478bd9Sstevel@tonic-gate 	AcpiOsFree(rsb.Pointer);
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	if (srsp == NULL)
5077c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * The Interrupts[] array is always at least one entry
5117c478bd9Sstevel@tonic-gate 	 * long; see the definition of ACPI_RESOURCE.
5127c478bd9Sstevel@tonic-gate 	 */
513186507a7Smyers 	switch (srsp->Type) {
514186507a7Smyers 	case ACPI_RESOURCE_TYPE_IRQ:
515186507a7Smyers 		srsp->Data.Irq.InterruptCount = 1;
516*7ff178cdSJimmy Vetayases 		srsp->Data.Irq.Interrupts[0] = (uint8_t)irq;
5177c478bd9Sstevel@tonic-gate 		break;
518186507a7Smyers 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
519186507a7Smyers 		srsp->Data.ExtendedIrq.InterruptCount = 1;
5207c478bd9Sstevel@tonic-gate 		srsp->Data.ExtendedIrq.Interrupts[0] = irq;
5217c478bd9Sstevel@tonic-gate 		break;
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	rsb.Pointer = srsp;
525186507a7Smyers 	rsb.Length = srs_len;
5267c478bd9Sstevel@tonic-gate 	status = AcpiSetCurrentResources(lnkobj, &rsb);
527186507a7Smyers 	kmem_free(srsp, srs_len);
5287c478bd9Sstevel@tonic-gate 	if (status != AE_OK) {
5297c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!psm: set_irq: _SRS failed");
5307c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) {
5347c478bd9Sstevel@tonic-gate 		acpipsmlnkp->device_status = (uchar_t)status;
5357c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_SUCCESS);
5367c478bd9Sstevel@tonic-gate 	} else
5377c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  *
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate static int
psm_acpi_edgelevel(UINT32 el)5457c478bd9Sstevel@tonic-gate psm_acpi_edgelevel(UINT32 el)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	switch (el) {
5487c478bd9Sstevel@tonic-gate 	case ACPI_EDGE_SENSITIVE:
5497c478bd9Sstevel@tonic-gate 		return (INTR_EL_EDGE);
5507c478bd9Sstevel@tonic-gate 	case ACPI_LEVEL_SENSITIVE:
5517c478bd9Sstevel@tonic-gate 		return (INTR_EL_LEVEL);
5527c478bd9Sstevel@tonic-gate 	default:
5537c478bd9Sstevel@tonic-gate 		/* el is a single bit; should never reach here */
5547c478bd9Sstevel@tonic-gate 		return (INTR_EL_CONFORM);
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  *
5617c478bd9Sstevel@tonic-gate  */
5627c478bd9Sstevel@tonic-gate static int
psm_acpi_po(UINT32 po)5637c478bd9Sstevel@tonic-gate psm_acpi_po(UINT32 po)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	switch (po) {
5667c478bd9Sstevel@tonic-gate 	case ACPI_ACTIVE_HIGH:
5677c478bd9Sstevel@tonic-gate 		return (INTR_PO_ACTIVE_HIGH);
5687c478bd9Sstevel@tonic-gate 	case ACPI_ACTIVE_LOW:
5697c478bd9Sstevel@tonic-gate 		return (INTR_PO_ACTIVE_LOW);
5707c478bd9Sstevel@tonic-gate 	default:
5717c478bd9Sstevel@tonic-gate 		/* po is a single bit; should never reach here */
5727c478bd9Sstevel@tonic-gate 		return (INTR_PO_CONFORM);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * Retrieves the current irq setting for the interrrupt link device.
5797c478bd9Sstevel@tonic-gate  *
5807c478bd9Sstevel@tonic-gate  * Stores polarity and sensitivity in the structure pointed to by
5817c478bd9Sstevel@tonic-gate  * intr_flagp, and irqno in the value pointed to by pci_irqp.
5827c478bd9Sstevel@tonic-gate  *
5837c478bd9Sstevel@tonic-gate  * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure.
5847c478bd9Sstevel@tonic-gate  */
5857c478bd9Sstevel@tonic-gate int
acpi_get_current_irq_resource(acpi_psm_lnk_t * acpipsmlnkp,int * pci_irqp,iflag_t * intr_flagp)5867c478bd9Sstevel@tonic-gate acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp,
5877c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	ACPI_HANDLE lnkobj;
5907c478bd9Sstevel@tonic-gate 	ACPI_BUFFER rb;
5917c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE *rp;
5927c478bd9Sstevel@tonic-gate 	int irq;
5937c478bd9Sstevel@tonic-gate 	int status = ACPI_PSM_FAILURE;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	ASSERT(acpipsmlnkp != NULL);
5967c478bd9Sstevel@tonic-gate 	lnkobj = acpipsmlnkp->lnkobj;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	if (!(acpipsmlnkp->device_status & STA_PRESENT) ||
5997c478bd9Sstevel@tonic-gate 	    !(acpipsmlnkp->device_status & STA_ENABLE)) {
6007c478bd9Sstevel@tonic-gate 		PSM_VERBOSE_IRQ((CE_WARN, "!psm: crs device either not "
6017c478bd9Sstevel@tonic-gate 		    "present or disabled, status 0x%x",
6027c478bd9Sstevel@tonic-gate 		    acpipsmlnkp->device_status));
6037c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	rb.Pointer = NULL;
6077c478bd9Sstevel@tonic-gate 	rb.Length = ACPI_ALLOCATE_BUFFER;
6087c478bd9Sstevel@tonic-gate 	if (AcpiGetCurrentResources(lnkobj, &rb) != AE_OK) {
6097c478bd9Sstevel@tonic-gate 		PSM_VERBOSE_IRQ((CE_WARN, "!psm: no crs object found or"
6107c478bd9Sstevel@tonic-gate 		" evaluation failed"));
6117c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	irq = -1;
615186507a7Smyers 	for (rp = rb.Pointer; rp->Type != ACPI_RESOURCE_TYPE_END_TAG;
616186507a7Smyers 	    rp = ACPI_NEXT_RESOURCE(rp)) {
617186507a7Smyers 		if (rp->Type == ACPI_RESOURCE_TYPE_IRQ) {
6187c478bd9Sstevel@tonic-gate 			if (irq > 0) {
6197c478bd9Sstevel@tonic-gate 				PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ"
6207c478bd9Sstevel@tonic-gate 				" from _CRS "));
6217c478bd9Sstevel@tonic-gate 				status = ACPI_PSM_FAILURE;
6227c478bd9Sstevel@tonic-gate 				break;
6237c478bd9Sstevel@tonic-gate 			}
6247c478bd9Sstevel@tonic-gate 
625186507a7Smyers 			if (rp->Data.Irq.InterruptCount != 1) {
6267c478bd9Sstevel@tonic-gate 				PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt"
6277c478bd9Sstevel@tonic-gate 				" from _CRS "));
6287c478bd9Sstevel@tonic-gate 				status = ACPI_PSM_FAILURE;
6297c478bd9Sstevel@tonic-gate 				break;
6307c478bd9Sstevel@tonic-gate 			}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 			intr_flagp->intr_el = psm_acpi_edgelevel(
633186507a7Smyers 			    rp->Data.Irq.Triggering);
6347c478bd9Sstevel@tonic-gate 			intr_flagp->intr_po = psm_acpi_po(
635186507a7Smyers 			    rp->Data.Irq.Polarity);
6367c478bd9Sstevel@tonic-gate 			irq = rp->Data.Irq.Interrupts[0];
6377c478bd9Sstevel@tonic-gate 			status = ACPI_PSM_SUCCESS;
638186507a7Smyers 		} else if (rp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
6397c478bd9Sstevel@tonic-gate 			if (irq > 0) {
6407c478bd9Sstevel@tonic-gate 				PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ"
6417c478bd9Sstevel@tonic-gate 				" from _CRS "));
6427c478bd9Sstevel@tonic-gate 				status = ACPI_PSM_FAILURE;
6437c478bd9Sstevel@tonic-gate 				break;
6447c478bd9Sstevel@tonic-gate 			}
6457c478bd9Sstevel@tonic-gate 
646186507a7Smyers 			if (rp->Data.ExtendedIrq.InterruptCount != 1) {
6477c478bd9Sstevel@tonic-gate 				PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt"
6487c478bd9Sstevel@tonic-gate 				" from _CRS "));
6497c478bd9Sstevel@tonic-gate 				status = ACPI_PSM_FAILURE;
6507c478bd9Sstevel@tonic-gate 				break;
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 			intr_flagp->intr_el = psm_acpi_edgelevel(
654186507a7Smyers 			    rp->Data.ExtendedIrq.Triggering);
6557c478bd9Sstevel@tonic-gate 			intr_flagp->intr_po = psm_acpi_po(
656186507a7Smyers 			    rp->Data.ExtendedIrq.Polarity);
6577c478bd9Sstevel@tonic-gate 			irq = rp->Data.ExtendedIrq.Interrupts[0];
6587c478bd9Sstevel@tonic-gate 			status = ACPI_PSM_SUCCESS;
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	AcpiOsFree(rb.Pointer);
6637c478bd9Sstevel@tonic-gate 	if (status == ACPI_PSM_SUCCESS) {
6647c478bd9Sstevel@tonic-gate 		*pci_irqp =  irq;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	return (status);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * Searches for the given IRQ in the irqlist passed in.
6727c478bd9Sstevel@tonic-gate  *
6737c478bd9Sstevel@tonic-gate  * If multiple matches exist, this returns true on the first match.
6747c478bd9Sstevel@tonic-gate  * Returns the interrupt flags, if a match was found, in `intr_flagp' if
6757c478bd9Sstevel@tonic-gate  * it's passed in non-NULL
6767c478bd9Sstevel@tonic-gate  */
6777c478bd9Sstevel@tonic-gate int
acpi_irqlist_find_irq(acpi_irqlist_t * irqlistp,int irq,iflag_t * intr_flagp)6787c478bd9Sstevel@tonic-gate acpi_irqlist_find_irq(acpi_irqlist_t *irqlistp, int irq, iflag_t *intr_flagp)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	int found = 0;
6817c478bd9Sstevel@tonic-gate 	int i;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	while (irqlistp != NULL && !found) {
6847c478bd9Sstevel@tonic-gate 		for (i = 0; i < irqlistp->num_irqs; i++) {
6857c478bd9Sstevel@tonic-gate 			if (irqlistp->irqs[i] == irq) {
6867c478bd9Sstevel@tonic-gate 				if (intr_flagp)
6877c478bd9Sstevel@tonic-gate 					*intr_flagp = irqlistp->intr_flags;
6887c478bd9Sstevel@tonic-gate 				found = 1;
6897c478bd9Sstevel@tonic-gate 				break;	/* out of for() */
6907c478bd9Sstevel@tonic-gate 			}
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	return (found ? ACPI_PSM_SUCCESS : ACPI_PSM_FAILURE);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * Frees the irqlist allocated by acpi_get_possible_irq_resource.
6997c478bd9Sstevel@tonic-gate  * It takes a count of number of entries in the list.
7007c478bd9Sstevel@tonic-gate  */
7017c478bd9Sstevel@tonic-gate void
acpi_free_irqlist(acpi_irqlist_t * irqlistp)7027c478bd9Sstevel@tonic-gate acpi_free_irqlist(acpi_irqlist_t *irqlistp)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	acpi_irqlist_t *freednode;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	while (irqlistp != NULL) {
7077c478bd9Sstevel@tonic-gate 		/* Free the irq list */
7087c478bd9Sstevel@tonic-gate 		kmem_free(irqlistp->irqs, irqlistp->num_irqs *
7097c478bd9Sstevel@tonic-gate 		    sizeof (int32_t));
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		freednode = irqlistp;
7127c478bd9Sstevel@tonic-gate 		irqlistp = irqlistp->next;
7137c478bd9Sstevel@tonic-gate 		kmem_free(freednode, sizeof (acpi_irqlist_t));
7147c478bd9Sstevel@tonic-gate 	}
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate  * Creates a new entry in the given irqlist with the information passed in.
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate static void
acpi_add_irqlist_entry(acpi_irqlist_t ** irqlistp,uint32_t * irqlist,int irqlist_len,iflag_t * intr_flagp)7217c478bd9Sstevel@tonic-gate acpi_add_irqlist_entry(acpi_irqlist_t **irqlistp, uint32_t *irqlist,
7227c478bd9Sstevel@tonic-gate     int irqlist_len, iflag_t *intr_flagp)
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate 	acpi_irqlist_t *newent;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	ASSERT(irqlist != NULL);
7277c478bd9Sstevel@tonic-gate 	ASSERT(intr_flagp != NULL);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	newent = kmem_alloc(sizeof (acpi_irqlist_t), KM_SLEEP);
7307c478bd9Sstevel@tonic-gate 	newent->intr_flags = *intr_flagp;
7317c478bd9Sstevel@tonic-gate 	newent->irqs = irqlist;
7327c478bd9Sstevel@tonic-gate 	newent->num_irqs = irqlist_len;
7337c478bd9Sstevel@tonic-gate 	newent->next = *irqlistp;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	*irqlistp = newent;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * Retrieves a list of possible interrupt settings for the interrupt link
7417c478bd9Sstevel@tonic-gate  * device.
7427c478bd9Sstevel@tonic-gate  *
7437c478bd9Sstevel@tonic-gate  * Stores polarity and sensitivity in the structure pointed to by intr_flagp.
7447c478bd9Sstevel@tonic-gate  * Updates value pointed to by irqlistp with the address of a table it
7457c478bd9Sstevel@tonic-gate  * allocates. where interrupt numbers are stored. Stores the number of entries
7467c478bd9Sstevel@tonic-gate  * in this table in the value pointed to by num_entriesp;
7477c478bd9Sstevel@tonic-gate  *
7487c478bd9Sstevel@tonic-gate  * Each element in this table is of type int32_t. The table should be later
7497c478bd9Sstevel@tonic-gate  * freed by caller via acpi_free_irq_list().
7507c478bd9Sstevel@tonic-gate  *
7517c478bd9Sstevel@tonic-gate  * Returns ACPI_PSM_SUCCESS on success and ACPI_PSM_FAILURE upon failure
7527c478bd9Sstevel@tonic-gate  */
7537c478bd9Sstevel@tonic-gate int
acpi_get_possible_irq_resources(acpi_psm_lnk_t * acpipsmlnkp,acpi_irqlist_t ** irqlistp)7547c478bd9Sstevel@tonic-gate acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp,
7557c478bd9Sstevel@tonic-gate     acpi_irqlist_t **irqlistp)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate 	ACPI_HANDLE lnkobj;
7587c478bd9Sstevel@tonic-gate 	ACPI_BUFFER rsb;
7597c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE *resp;
7607c478bd9Sstevel@tonic-gate 	int status;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	int i, el, po, irqlist_len;
76330082d0cSmyers 	uint32_t *irqlist;
76430082d0cSmyers 	void *tmplist;
7657c478bd9Sstevel@tonic-gate 	iflag_t intr_flags;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	ASSERT(acpipsmlnkp != NULL);
7687c478bd9Sstevel@tonic-gate 	lnkobj = acpipsmlnkp->lnkobj;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	rsb.Pointer = NULL;
7717c478bd9Sstevel@tonic-gate 	rsb.Length = ACPI_ALLOCATE_BUFFER;
7727c478bd9Sstevel@tonic-gate 	status = AcpiGetPossibleResources(lnkobj, &rsb);
7737c478bd9Sstevel@tonic-gate 	if (status != AE_OK) {
7747c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!psm: get_irq: _PRS failed");
7757c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	/*
7797c478bd9Sstevel@tonic-gate 	 * Scan the resources looking for an interrupt resource
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 	*irqlistp = 0;
782186507a7Smyers 	for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG;
7837c478bd9Sstevel@tonic-gate 	    resp = ACPI_NEXT_RESOURCE(resp)) {
784186507a7Smyers 		switch (resp->Type) {
785186507a7Smyers 		case ACPI_RESOURCE_TYPE_IRQ:
786186507a7Smyers 			irqlist_len = resp->Data.Irq.InterruptCount;
7877c478bd9Sstevel@tonic-gate 			tmplist = resp->Data.Irq.Interrupts;
788186507a7Smyers 			el = resp->Data.Irq.Triggering;
789186507a7Smyers 			po = resp->Data.Irq.Polarity;
7907c478bd9Sstevel@tonic-gate 			break;
791186507a7Smyers 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
792186507a7Smyers 			irqlist_len = resp->Data.ExtendedIrq.InterruptCount;
7937c478bd9Sstevel@tonic-gate 			tmplist = resp->Data.ExtendedIrq.Interrupts;
794186507a7Smyers 			el = resp->Data.ExtendedIrq.Triggering;
795186507a7Smyers 			po = resp->Data.ExtendedIrq.Polarity;
7967c478bd9Sstevel@tonic-gate 			break;
7977c478bd9Sstevel@tonic-gate 		default:
7987c478bd9Sstevel@tonic-gate 			continue;
7997c478bd9Sstevel@tonic-gate 		}
80030082d0cSmyers 
80130082d0cSmyers 		if (resp->Type != ACPI_RESOURCE_TYPE_IRQ &&
80230082d0cSmyers 		    resp->Type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
80330082d0cSmyers 			cmn_err(CE_WARN, "!psm: get_irq: no IRQ resource");
80430082d0cSmyers 			return (ACPI_PSM_FAILURE);
80530082d0cSmyers 		}
80630082d0cSmyers 
8077c478bd9Sstevel@tonic-gate 		/* NEEDSWORK: move this into add_irqlist_entry someday */
8087c478bd9Sstevel@tonic-gate 		irqlist = kmem_zalloc(irqlist_len * sizeof (*irqlist),
8097c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
8107c478bd9Sstevel@tonic-gate 		for (i = 0; i < irqlist_len; i++)
81130082d0cSmyers 			if (resp->Type == ACPI_RESOURCE_TYPE_IRQ)
81230082d0cSmyers 				irqlist[i] = ((uint8_t *)tmplist)[i];
81330082d0cSmyers 			else
81430082d0cSmyers 				irqlist[i] = ((uint32_t *)tmplist)[i];
8157c478bd9Sstevel@tonic-gate 		intr_flags.intr_el = psm_acpi_edgelevel(el);
8167c478bd9Sstevel@tonic-gate 		intr_flags.intr_po = psm_acpi_po(po);
8177c478bd9Sstevel@tonic-gate 		acpi_add_irqlist_entry(irqlistp, irqlist, irqlist_len,
8187c478bd9Sstevel@tonic-gate 		    &intr_flags);
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	AcpiOsFree(rsb.Pointer);
8227c478bd9Sstevel@tonic-gate 	return (irqlistp == NULL ? ACPI_PSM_FAILURE : ACPI_PSM_SUCCESS);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate  * Adds a new cache entry to the irq cache which maps an irq and
8277c478bd9Sstevel@tonic-gate  * its attributes to PCI bus/dev/ipin and optionally to its associated ACPI
8287c478bd9Sstevel@tonic-gate  * interrupt link device object.
8297c478bd9Sstevel@tonic-gate  */
8307c478bd9Sstevel@tonic-gate void
acpi_new_irq_cache_ent(int bus,int dev,int ipin,int pci_irq,iflag_t * intr_flagp,acpi_psm_lnk_t * acpipsmlnkp)8317c478bd9Sstevel@tonic-gate acpi_new_irq_cache_ent(int bus, int dev, int ipin, int pci_irq,
8327c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	int newsize;
8357c478bd9Sstevel@tonic-gate 	irq_cache_t *new_arr, *ep;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	mutex_enter(&acpi_irq_cache_mutex);
8387c478bd9Sstevel@tonic-gate 	if (irq_cache_valid >= irq_cache_len) {
8397c478bd9Sstevel@tonic-gate 		/* initially, or re-, allocate array */
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		newsize = (irq_cache_len ?
8427c478bd9Sstevel@tonic-gate 		    irq_cache_len * 2 : IRQ_CACHE_INITLEN);
8437c478bd9Sstevel@tonic-gate 		new_arr = kmem_zalloc(newsize * sizeof (irq_cache_t), KM_SLEEP);
8447c478bd9Sstevel@tonic-gate 		if (irq_cache_len != 0) {
8457c478bd9Sstevel@tonic-gate 			/* realloc: copy data, free old */
8467c478bd9Sstevel@tonic-gate 			bcopy(irq_cache_table, new_arr,
8477c478bd9Sstevel@tonic-gate 			    irq_cache_len * sizeof (irq_cache_t));
8487c478bd9Sstevel@tonic-gate 			kmem_free(irq_cache_table,
8497c478bd9Sstevel@tonic-gate 			    irq_cache_len * sizeof (irq_cache_t));
8507c478bd9Sstevel@tonic-gate 		}
8517c478bd9Sstevel@tonic-gate 		irq_cache_len = newsize;
8527c478bd9Sstevel@tonic-gate 		irq_cache_table = new_arr;
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 	ep = &irq_cache_table[irq_cache_valid++];
8557c478bd9Sstevel@tonic-gate 	ep->bus = (uchar_t)bus;
8567c478bd9Sstevel@tonic-gate 	ep->dev = (uchar_t)dev;
8577c478bd9Sstevel@tonic-gate 	ep->ipin = (uchar_t)ipin;
8587c478bd9Sstevel@tonic-gate 	ep->flags = *intr_flagp;
859*7ff178cdSJimmy Vetayases 	ep->irq = (uchar_t)pci_irq;
8607c478bd9Sstevel@tonic-gate 	ASSERT(acpipsmlnkp != NULL);
8617c478bd9Sstevel@tonic-gate 	ep->lnkobj = acpipsmlnkp->lnkobj;
8627c478bd9Sstevel@tonic-gate 	mutex_exit(&acpi_irq_cache_mutex);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate /*
8677c478bd9Sstevel@tonic-gate  * Searches the irq caches for the given bus/dev/ipin.
8687c478bd9Sstevel@tonic-gate  *
8697c478bd9Sstevel@tonic-gate  * If info is found, stores polarity and sensitivity in the structure
8707c478bd9Sstevel@tonic-gate  * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp,
8717c478bd9Sstevel@tonic-gate  * and returns ACPI_PSM_SUCCESS.
8727c478bd9Sstevel@tonic-gate  * Otherwise, ACPI_PSM_FAILURE is returned.
8737c478bd9Sstevel@tonic-gate  */
8747c478bd9Sstevel@tonic-gate int
acpi_get_irq_cache_ent(uchar_t bus,uchar_t dev,int ipin,int * pci_irqp,iflag_t * intr_flagp)8757c478bd9Sstevel@tonic-gate acpi_get_irq_cache_ent(uchar_t bus, uchar_t dev, int ipin,
8767c478bd9Sstevel@tonic-gate     int *pci_irqp, iflag_t *intr_flagp)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	irq_cache_t *irqcachep;
8807c478bd9Sstevel@tonic-gate 	int i;
8817c478bd9Sstevel@tonic-gate 	int ret = ACPI_PSM_FAILURE;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	mutex_enter(&acpi_irq_cache_mutex);
8847c478bd9Sstevel@tonic-gate 	for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
8857c478bd9Sstevel@tonic-gate 	    irqcachep++, i++)
8867c478bd9Sstevel@tonic-gate 		if ((irqcachep->bus == bus) &&
8877c478bd9Sstevel@tonic-gate 		    (irqcachep->dev == dev) &&
8887c478bd9Sstevel@tonic-gate 		    (irqcachep->ipin == ipin)) {
8897c478bd9Sstevel@tonic-gate 			ASSERT(pci_irqp != NULL && intr_flagp != NULL);
8907c478bd9Sstevel@tonic-gate 			*pci_irqp = irqcachep->irq;
8917c478bd9Sstevel@tonic-gate 			*intr_flagp = irqcachep->flags;
8927c478bd9Sstevel@tonic-gate 			ret = ACPI_PSM_SUCCESS;
8937c478bd9Sstevel@tonic-gate 			break;
8947c478bd9Sstevel@tonic-gate 		}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	mutex_exit(&acpi_irq_cache_mutex);
8977c478bd9Sstevel@tonic-gate 	return (ret);
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate  * Searches the irq caches for the given interrupt lnk device object.
9027c478bd9Sstevel@tonic-gate  *
9037c478bd9Sstevel@tonic-gate  * If info is found, stores polarity and sensitivity in the structure
9047c478bd9Sstevel@tonic-gate  * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp,
9057c478bd9Sstevel@tonic-gate  * and returns ACPI_PSM_SUCCESS.
9067c478bd9Sstevel@tonic-gate  * Otherwise, ACPI_PSM_FAILURE is returned.
9077c478bd9Sstevel@tonic-gate  */
9087c478bd9Sstevel@tonic-gate int
acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj,int * pci_irqp,iflag_t * intr_flagp)9097c478bd9Sstevel@tonic-gate acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp,
9107c478bd9Sstevel@tonic-gate     iflag_t *intr_flagp)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	irq_cache_t *irqcachep;
9147c478bd9Sstevel@tonic-gate 	int i;
9157c478bd9Sstevel@tonic-gate 	int ret = ACPI_PSM_FAILURE;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (lnkobj == NULL)
9187c478bd9Sstevel@tonic-gate 		return (ACPI_PSM_FAILURE);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	mutex_enter(&acpi_irq_cache_mutex);
9217c478bd9Sstevel@tonic-gate 	for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
9227c478bd9Sstevel@tonic-gate 	    irqcachep++, i++)
9237c478bd9Sstevel@tonic-gate 		if (irqcachep->lnkobj == lnkobj) {
9247c478bd9Sstevel@tonic-gate 			ASSERT(pci_irqp != NULL);
9257c478bd9Sstevel@tonic-gate 			*pci_irqp = irqcachep->irq;
9267c478bd9Sstevel@tonic-gate 			ASSERT(intr_flagp != NULL);
9277c478bd9Sstevel@tonic-gate 			*intr_flagp = irqcachep->flags;
9287c478bd9Sstevel@tonic-gate 			ret = ACPI_PSM_SUCCESS;
9297c478bd9Sstevel@tonic-gate 			break;
9307c478bd9Sstevel@tonic-gate 		}
9317c478bd9Sstevel@tonic-gate 	mutex_exit(&acpi_irq_cache_mutex);
9327c478bd9Sstevel@tonic-gate 	return (ret);
9332df1fe9cSrandyf }
9342df1fe9cSrandyf 
9352df1fe9cSrandyf /*
9362df1fe9cSrandyf  * Walk the irq_cache_table and re-configure the link device to
9372df1fe9cSrandyf  * the saved state.
9382df1fe9cSrandyf  */
9392df1fe9cSrandyf void
acpi_restore_link_devices(void)9402df1fe9cSrandyf acpi_restore_link_devices(void)
9412df1fe9cSrandyf {
9422df1fe9cSrandyf 	irq_cache_t *irqcachep;
9432df1fe9cSrandyf 	acpi_psm_lnk_t psmlnk;
9442df1fe9cSrandyf 	int i, status;
9452df1fe9cSrandyf 
9462df1fe9cSrandyf 	/* XXX: may not need to hold this mutex */
9472df1fe9cSrandyf 	mutex_enter(&acpi_irq_cache_mutex);
9482df1fe9cSrandyf 	for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
9492df1fe9cSrandyf 	    irqcachep++, i++) {
950b3dbb693Sgs150176 		if (irqcachep->lnkobj != NULL) {
9512df1fe9cSrandyf 			/* only field used from psmlnk in set_irq is lnkobj */
9522df1fe9cSrandyf 			psmlnk.lnkobj = irqcachep->lnkobj;
9532df1fe9cSrandyf 			status = acpi_set_irq_resource(&psmlnk, irqcachep->irq);
9542df1fe9cSrandyf 			/* warn if set_irq failed; soldier on */
9552df1fe9cSrandyf 			if (status != ACPI_PSM_SUCCESS)
956b3dbb693Sgs150176 				cmn_err(CE_WARN, "Could not restore interrupt "
957b3dbb693Sgs150176 				    "link device for IRQ 0x%x: Devices using "
958b3dbb693Sgs150176 				    "this IRQ may no longer function properly."
959b3dbb693Sgs150176 				    "\n", irqcachep->irq);
960b3dbb693Sgs150176 		}
9612df1fe9cSrandyf 	}
9622df1fe9cSrandyf 	mutex_exit(&acpi_irq_cache_mutex);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate int
acpi_poweroff(void)9667c478bd9Sstevel@tonic-gate acpi_poweroff(void)
9677c478bd9Sstevel@tonic-gate {
968137e2f25SGuoli Shu 	extern int acpica_use_safe_delay;
969fff9ceabSjj204856 	ACPI_STATUS status;
970859dcd3dSmyers 
9717c478bd9Sstevel@tonic-gate 	PSM_VERBOSE_POWEROFF(("acpi_poweroff: starting poweroff\n"));
9727c478bd9Sstevel@tonic-gate 
973137e2f25SGuoli Shu 	acpica_use_safe_delay = 1;
974859dcd3dSmyers 
975fff9ceabSjj204856 	status = AcpiEnterSleepStatePrep(5);
976fff9ceabSjj204856 	if (status != AE_OK) {
977fff9ceabSjj204856 		PSM_VERBOSE_POWEROFF(("acpi_poweroff: failed to prepare for "
978fff9ceabSjj204856 		    "poweroff, status=0x%x\n", status));
9797c478bd9Sstevel@tonic-gate 		return (1);
9807c478bd9Sstevel@tonic-gate 	}
981fff9ceabSjj204856 	ACPI_DISABLE_IRQS();
982fff9ceabSjj204856 	status = AcpiEnterSleepState(5);
9837c478bd9Sstevel@tonic-gate 	ACPI_ENABLE_IRQS();
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/* we should be off; if we get here it's an error */
986fff9ceabSjj204856 	PSM_VERBOSE_POWEROFF(("acpi_poweroff: failed to actually power "
987fff9ceabSjj204856 	    "off, status=0x%x\n", status));
9887c478bd9Sstevel@tonic-gate 	return (1);
9897c478bd9Sstevel@tonic-gate }
990450d6964Smyers 
991450d6964Smyers 
992450d6964Smyers /*
993450d6964Smyers  * psm_set_elcr() sets ELCR bit for specified vector
994450d6964Smyers  */
995450d6964Smyers void
psm_set_elcr(int vecno,int val)996450d6964Smyers psm_set_elcr(int vecno, int val)
997450d6964Smyers {
998450d6964Smyers 	int elcr_port = ELCR_PORT1 + (vecno >> 3);
999450d6964Smyers 	int elcr_bit = 1 << (vecno & 0x07);
1000450d6964Smyers 
1001450d6964Smyers 	ASSERT((vecno >= 0) && (vecno < 16));
1002450d6964Smyers 
1003450d6964Smyers 	if (val) {
1004450d6964Smyers 		/* set bit to force level-triggered mode */
1005450d6964Smyers 		outb(elcr_port, inb(elcr_port) | elcr_bit);
1006450d6964Smyers 	} else {
1007450d6964Smyers 		/* clear bit to force edge-triggered mode */
1008450d6964Smyers 		outb(elcr_port, inb(elcr_port) & ~elcr_bit);
1009450d6964Smyers 	}
1010450d6964Smyers }
1011450d6964Smyers 
1012450d6964Smyers /*
1013450d6964Smyers  * psm_get_elcr() returns status of ELCR bit for specific vector
1014450d6964Smyers  */
1015450d6964Smyers int
psm_get_elcr(int vecno)1016450d6964Smyers psm_get_elcr(int vecno)
1017450d6964Smyers {
1018450d6964Smyers 	int elcr_port = ELCR_PORT1 + (vecno >> 3);
1019450d6964Smyers 	int elcr_bit = 1 << (vecno & 0x07);
1020450d6964Smyers 
1021450d6964Smyers 	ASSERT((vecno >= 0) && (vecno < 16));
1022450d6964Smyers 
1023450d6964Smyers 	return ((inb(elcr_port) & elcr_bit) ? 1 : 0);
1024450d6964Smyers }
1025