xref: /onnv-gate/usr/src/uts/i86pc/io/psm/psm_common.c (revision 0:68f95e015346)
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