xref: /onnv-gate/usr/src/uts/i86pc/io/apix/apix_utils.c (revision 12683:92e6427b7b70)
1*12683SJimmy.Vetayases@oracle.com /*
2*12683SJimmy.Vetayases@oracle.com  * CDDL HEADER START
3*12683SJimmy.Vetayases@oracle.com  *
4*12683SJimmy.Vetayases@oracle.com  * The contents of this file are subject to the terms of the
5*12683SJimmy.Vetayases@oracle.com  * Common Development and Distribution License (the "License").
6*12683SJimmy.Vetayases@oracle.com  * You may not use this file except in compliance with the License.
7*12683SJimmy.Vetayases@oracle.com  *
8*12683SJimmy.Vetayases@oracle.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12683SJimmy.Vetayases@oracle.com  * or http://www.opensolaris.org/os/licensing.
10*12683SJimmy.Vetayases@oracle.com  * See the License for the specific language governing permissions
11*12683SJimmy.Vetayases@oracle.com  * and limitations under the License.
12*12683SJimmy.Vetayases@oracle.com  *
13*12683SJimmy.Vetayases@oracle.com  * When distributing Covered Code, include this CDDL HEADER in each
14*12683SJimmy.Vetayases@oracle.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12683SJimmy.Vetayases@oracle.com  * If applicable, add the following below this CDDL HEADER, with the
16*12683SJimmy.Vetayases@oracle.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*12683SJimmy.Vetayases@oracle.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12683SJimmy.Vetayases@oracle.com  *
19*12683SJimmy.Vetayases@oracle.com  * CDDL HEADER END
20*12683SJimmy.Vetayases@oracle.com  */
21*12683SJimmy.Vetayases@oracle.com 
22*12683SJimmy.Vetayases@oracle.com /*
23*12683SJimmy.Vetayases@oracle.com  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*12683SJimmy.Vetayases@oracle.com  */
25*12683SJimmy.Vetayases@oracle.com /*
26*12683SJimmy.Vetayases@oracle.com  * Copyright (c) 2010, Intel Corporation.
27*12683SJimmy.Vetayases@oracle.com  * All rights reserved.
28*12683SJimmy.Vetayases@oracle.com  */
29*12683SJimmy.Vetayases@oracle.com 
30*12683SJimmy.Vetayases@oracle.com #include <sys/processor.h>
31*12683SJimmy.Vetayases@oracle.com #include <sys/time.h>
32*12683SJimmy.Vetayases@oracle.com #include <sys/psm.h>
33*12683SJimmy.Vetayases@oracle.com #include <sys/smp_impldefs.h>
34*12683SJimmy.Vetayases@oracle.com #include <sys/cram.h>
35*12683SJimmy.Vetayases@oracle.com #include <sys/acpi/acpi.h>
36*12683SJimmy.Vetayases@oracle.com #include <sys/acpica.h>
37*12683SJimmy.Vetayases@oracle.com #include <sys/psm_common.h>
38*12683SJimmy.Vetayases@oracle.com #include <sys/pit.h>
39*12683SJimmy.Vetayases@oracle.com #include <sys/ddi.h>
40*12683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h>
41*12683SJimmy.Vetayases@oracle.com #include <sys/ddi_impldefs.h>
42*12683SJimmy.Vetayases@oracle.com #include <sys/pci.h>
43*12683SJimmy.Vetayases@oracle.com #include <sys/promif.h>
44*12683SJimmy.Vetayases@oracle.com #include <sys/x86_archext.h>
45*12683SJimmy.Vetayases@oracle.com #include <sys/cpc_impl.h>
46*12683SJimmy.Vetayases@oracle.com #include <sys/uadmin.h>
47*12683SJimmy.Vetayases@oracle.com #include <sys/panic.h>
48*12683SJimmy.Vetayases@oracle.com #include <sys/debug.h>
49*12683SJimmy.Vetayases@oracle.com #include <sys/archsystm.h>
50*12683SJimmy.Vetayases@oracle.com #include <sys/trap.h>
51*12683SJimmy.Vetayases@oracle.com #include <sys/machsystm.h>
52*12683SJimmy.Vetayases@oracle.com #include <sys/sysmacros.h>
53*12683SJimmy.Vetayases@oracle.com #include <sys/cpuvar.h>
54*12683SJimmy.Vetayases@oracle.com #include <sys/rm_platter.h>
55*12683SJimmy.Vetayases@oracle.com #include <sys/privregs.h>
56*12683SJimmy.Vetayases@oracle.com #include <sys/note.h>
57*12683SJimmy.Vetayases@oracle.com #include <sys/pci_intr_lib.h>
58*12683SJimmy.Vetayases@oracle.com #include <sys/spl.h>
59*12683SJimmy.Vetayases@oracle.com #include <sys/clock.h>
60*12683SJimmy.Vetayases@oracle.com #include <sys/dditypes.h>
61*12683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h>
62*12683SJimmy.Vetayases@oracle.com #include <sys/x_call.h>
63*12683SJimmy.Vetayases@oracle.com #include <sys/reboot.h>
64*12683SJimmy.Vetayases@oracle.com #include <sys/apix.h>
65*12683SJimmy.Vetayases@oracle.com 
66*12683SJimmy.Vetayases@oracle.com static int apix_get_avail_vector_oncpu(uint32_t, int, int);
67*12683SJimmy.Vetayases@oracle.com static apix_vector_t *apix_init_vector(processorid_t, uchar_t);
68*12683SJimmy.Vetayases@oracle.com static void apix_cleanup_vector(apix_vector_t *);
69*12683SJimmy.Vetayases@oracle.com static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t,
70*12683SJimmy.Vetayases@oracle.com     uint64_t *, int, dev_info_t *);
71*12683SJimmy.Vetayases@oracle.com static void apix_remove_av(apix_vector_t *, struct autovec *);
72*12683SJimmy.Vetayases@oracle.com static void apix_clear_dev_map(dev_info_t *, int, int);
73*12683SJimmy.Vetayases@oracle.com static boolean_t apix_is_cpu_enabled(processorid_t);
74*12683SJimmy.Vetayases@oracle.com static void apix_wait_till_seen(processorid_t, int);
75*12683SJimmy.Vetayases@oracle.com 
76*12683SJimmy.Vetayases@oracle.com #define	GET_INTR_INUM(ihdlp)		\
77*12683SJimmy.Vetayases@oracle.com 	(((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0)
78*12683SJimmy.Vetayases@oracle.com 
79*12683SJimmy.Vetayases@oracle.com apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL};
80*12683SJimmy.Vetayases@oracle.com 
81*12683SJimmy.Vetayases@oracle.com /*
82*12683SJimmy.Vetayases@oracle.com  * Allocate IPI
83*12683SJimmy.Vetayases@oracle.com  *
84*12683SJimmy.Vetayases@oracle.com  * Return vector number or 0 on error
85*12683SJimmy.Vetayases@oracle.com  */
86*12683SJimmy.Vetayases@oracle.com uchar_t
87*12683SJimmy.Vetayases@oracle.com apix_alloc_ipi(int ipl)
88*12683SJimmy.Vetayases@oracle.com {
89*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
90*12683SJimmy.Vetayases@oracle.com 	uchar_t vector;
91*12683SJimmy.Vetayases@oracle.com 	int cpun;
92*12683SJimmy.Vetayases@oracle.com 	int nproc;
93*12683SJimmy.Vetayases@oracle.com 
94*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(0);
95*12683SJimmy.Vetayases@oracle.com 
96*12683SJimmy.Vetayases@oracle.com 	vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX);
97*12683SJimmy.Vetayases@oracle.com 	if (vector == 0) {
98*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(0);
99*12683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "apix: no available IPI\n");
100*12683SJimmy.Vetayases@oracle.com 		apic_error |= APIC_ERR_GET_IPIVECT_FAIL;
101*12683SJimmy.Vetayases@oracle.com 		return (0);
102*12683SJimmy.Vetayases@oracle.com 	}
103*12683SJimmy.Vetayases@oracle.com 
104*12683SJimmy.Vetayases@oracle.com 	nproc = max(apic_nproc, apic_max_nproc);
105*12683SJimmy.Vetayases@oracle.com 	for (cpun = 0; cpun < nproc; cpun++) {
106*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpun, vector);
107*12683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
108*12683SJimmy.Vetayases@oracle.com 			vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
109*12683SJimmy.Vetayases@oracle.com 			if (vecp == NULL) {
110*12683SJimmy.Vetayases@oracle.com 				cmn_err(CE_WARN, "apix: No memory for ipi");
111*12683SJimmy.Vetayases@oracle.com 				goto fail;
112*12683SJimmy.Vetayases@oracle.com 			}
113*12683SJimmy.Vetayases@oracle.com 			xv_vector(cpun, vector) = vecp;
114*12683SJimmy.Vetayases@oracle.com 		}
115*12683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_ALLOCED;
116*12683SJimmy.Vetayases@oracle.com 		vecp->v_type = APIX_TYPE_IPI;
117*12683SJimmy.Vetayases@oracle.com 		vecp->v_cpuid = vecp->v_bound_cpuid = cpun;
118*12683SJimmy.Vetayases@oracle.com 		vecp->v_vector = vector;
119*12683SJimmy.Vetayases@oracle.com 		vecp->v_pri = ipl;
120*12683SJimmy.Vetayases@oracle.com 	}
121*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(0);
122*12683SJimmy.Vetayases@oracle.com 	return (vector);
123*12683SJimmy.Vetayases@oracle.com 
124*12683SJimmy.Vetayases@oracle.com fail:
125*12683SJimmy.Vetayases@oracle.com 	while (--cpun >= 0)
126*12683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(xv_vector(cpun, vector));
127*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(0);
128*12683SJimmy.Vetayases@oracle.com 	return (0);
129*12683SJimmy.Vetayases@oracle.com }
130*12683SJimmy.Vetayases@oracle.com 
131*12683SJimmy.Vetayases@oracle.com /*
132*12683SJimmy.Vetayases@oracle.com  * Add IPI service routine
133*12683SJimmy.Vetayases@oracle.com  */
134*12683SJimmy.Vetayases@oracle.com static int
135*12683SJimmy.Vetayases@oracle.com apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector,
136*12683SJimmy.Vetayases@oracle.com     caddr_t arg1, caddr_t arg2)
137*12683SJimmy.Vetayases@oracle.com {
138*12683SJimmy.Vetayases@oracle.com 	int cpun;
139*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
140*12683SJimmy.Vetayases@oracle.com 	int nproc;
141*12683SJimmy.Vetayases@oracle.com 
142*12683SJimmy.Vetayases@oracle.com 	ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX);
143*12683SJimmy.Vetayases@oracle.com 
144*12683SJimmy.Vetayases@oracle.com 	nproc = max(apic_nproc, apic_max_nproc);
145*12683SJimmy.Vetayases@oracle.com 	for (cpun = 0; cpun < nproc; cpun++) {
146*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpun);
147*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpun, vector);
148*12683SJimmy.Vetayases@oracle.com 		apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL);
149*12683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_ENABLED;
150*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpun);
151*12683SJimmy.Vetayases@oracle.com 	}
152*12683SJimmy.Vetayases@oracle.com 
153*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x "
154*12683SJimmy.Vetayases@oracle.com 	    "ipl %x\n", name, vector, ipl));
155*12683SJimmy.Vetayases@oracle.com 
156*12683SJimmy.Vetayases@oracle.com 	return (1);
157*12683SJimmy.Vetayases@oracle.com }
158*12683SJimmy.Vetayases@oracle.com 
159*12683SJimmy.Vetayases@oracle.com /*
160*12683SJimmy.Vetayases@oracle.com  * Find and return first free vector in range (start, end)
161*12683SJimmy.Vetayases@oracle.com  */
162*12683SJimmy.Vetayases@oracle.com static int
163*12683SJimmy.Vetayases@oracle.com apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end)
164*12683SJimmy.Vetayases@oracle.com {
165*12683SJimmy.Vetayases@oracle.com 	int i;
166*12683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
167*12683SJimmy.Vetayases@oracle.com 
168*12683SJimmy.Vetayases@oracle.com 	for (i = start; i <= end; i++) {
169*12683SJimmy.Vetayases@oracle.com 		if (APIC_CHECK_RESERVE_VECTORS(i))
170*12683SJimmy.Vetayases@oracle.com 			continue;
171*12683SJimmy.Vetayases@oracle.com 		if (IS_VECT_FREE(apixp->x_vectbl[i]))
172*12683SJimmy.Vetayases@oracle.com 			return (i);
173*12683SJimmy.Vetayases@oracle.com 	}
174*12683SJimmy.Vetayases@oracle.com 
175*12683SJimmy.Vetayases@oracle.com 	return (0);
176*12683SJimmy.Vetayases@oracle.com }
177*12683SJimmy.Vetayases@oracle.com 
178*12683SJimmy.Vetayases@oracle.com /*
179*12683SJimmy.Vetayases@oracle.com  * Allocate a vector on specified cpu
180*12683SJimmy.Vetayases@oracle.com  *
181*12683SJimmy.Vetayases@oracle.com  * Return NULL on error
182*12683SJimmy.Vetayases@oracle.com  */
183*12683SJimmy.Vetayases@oracle.com static apix_vector_t *
184*12683SJimmy.Vetayases@oracle.com apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type)
185*12683SJimmy.Vetayases@oracle.com {
186*12683SJimmy.Vetayases@oracle.com 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
187*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
188*12683SJimmy.Vetayases@oracle.com 	int vector;
189*12683SJimmy.Vetayases@oracle.com 
190*12683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
191*12683SJimmy.Vetayases@oracle.com 
192*12683SJimmy.Vetayases@oracle.com 	/* find free vector */
193*12683SJimmy.Vetayases@oracle.com 	vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN,
194*12683SJimmy.Vetayases@oracle.com 	    APIX_AVINTR_MAX);
195*12683SJimmy.Vetayases@oracle.com 	if (vector == 0)
196*12683SJimmy.Vetayases@oracle.com 		return (NULL);
197*12683SJimmy.Vetayases@oracle.com 
198*12683SJimmy.Vetayases@oracle.com 	vecp = apix_init_vector(tocpu, vector);
199*12683SJimmy.Vetayases@oracle.com 	vecp->v_type = (ushort_t)type;
200*12683SJimmy.Vetayases@oracle.com 	vecp->v_inum = inum;
201*12683SJimmy.Vetayases@oracle.com 	vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
202*12683SJimmy.Vetayases@oracle.com 
203*12683SJimmy.Vetayases@oracle.com 	if (dip != NULL)
204*12683SJimmy.Vetayases@oracle.com 		apix_set_dev_map(vecp, dip, inum);
205*12683SJimmy.Vetayases@oracle.com 
206*12683SJimmy.Vetayases@oracle.com 	return (vecp);
207*12683SJimmy.Vetayases@oracle.com }
208*12683SJimmy.Vetayases@oracle.com 
209*12683SJimmy.Vetayases@oracle.com /*
210*12683SJimmy.Vetayases@oracle.com  * Allocates "count" contiguous MSI vectors starting at the proper alignment.
211*12683SJimmy.Vetayases@oracle.com  * Caller needs to make sure that count has to be power of 2 and should not
212*12683SJimmy.Vetayases@oracle.com  * be < 1.
213*12683SJimmy.Vetayases@oracle.com  *
214*12683SJimmy.Vetayases@oracle.com  * Return first vector number
215*12683SJimmy.Vetayases@oracle.com  */
216*12683SJimmy.Vetayases@oracle.com apix_vector_t *
217*12683SJimmy.Vetayases@oracle.com apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum,
218*12683SJimmy.Vetayases@oracle.com     int count, int type)
219*12683SJimmy.Vetayases@oracle.com {
220*12683SJimmy.Vetayases@oracle.com 	int i, msibits, start = 0, navail = 0;
221*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp, *startp = NULL;
222*12683SJimmy.Vetayases@oracle.com 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
223*12683SJimmy.Vetayases@oracle.com 	uint_t flags;
224*12683SJimmy.Vetayases@oracle.com 
225*12683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
226*12683SJimmy.Vetayases@oracle.com 
227*12683SJimmy.Vetayases@oracle.com 	/*
228*12683SJimmy.Vetayases@oracle.com 	 * msibits is the no. of lower order message data bits for the
229*12683SJimmy.Vetayases@oracle.com 	 * allocated MSI vectors and is used to calculate the aligned
230*12683SJimmy.Vetayases@oracle.com 	 * starting vector
231*12683SJimmy.Vetayases@oracle.com 	 */
232*12683SJimmy.Vetayases@oracle.com 	msibits = count - 1;
233*12683SJimmy.Vetayases@oracle.com 
234*12683SJimmy.Vetayases@oracle.com 	/* It has to be contiguous */
235*12683SJimmy.Vetayases@oracle.com 	for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) {
236*12683SJimmy.Vetayases@oracle.com 		if (!IS_VECT_FREE(xv_vector(tocpu, i)))
237*12683SJimmy.Vetayases@oracle.com 			continue;
238*12683SJimmy.Vetayases@oracle.com 
239*12683SJimmy.Vetayases@oracle.com 		/*
240*12683SJimmy.Vetayases@oracle.com 		 * starting vector has to be aligned accordingly for
241*12683SJimmy.Vetayases@oracle.com 		 * multiple MSIs
242*12683SJimmy.Vetayases@oracle.com 		 */
243*12683SJimmy.Vetayases@oracle.com 		if (msibits)
244*12683SJimmy.Vetayases@oracle.com 			i = (i + msibits) & ~msibits;
245*12683SJimmy.Vetayases@oracle.com 
246*12683SJimmy.Vetayases@oracle.com 		for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) {
247*12683SJimmy.Vetayases@oracle.com 			if (!IS_VECT_FREE(xv_vector(tocpu, i)))
248*12683SJimmy.Vetayases@oracle.com 				break;
249*12683SJimmy.Vetayases@oracle.com 			if (APIC_CHECK_RESERVE_VECTORS(i))
250*12683SJimmy.Vetayases@oracle.com 				break;
251*12683SJimmy.Vetayases@oracle.com 			if (++navail == count)
252*12683SJimmy.Vetayases@oracle.com 				goto done;
253*12683SJimmy.Vetayases@oracle.com 		}
254*12683SJimmy.Vetayases@oracle.com 	}
255*12683SJimmy.Vetayases@oracle.com 
256*12683SJimmy.Vetayases@oracle.com 	return (NULL);
257*12683SJimmy.Vetayases@oracle.com 
258*12683SJimmy.Vetayases@oracle.com done:
259*12683SJimmy.Vetayases@oracle.com 	flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
260*12683SJimmy.Vetayases@oracle.com 
261*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
262*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_init_vector(tocpu, start + i)) == NULL)
263*12683SJimmy.Vetayases@oracle.com 			goto fail;
264*12683SJimmy.Vetayases@oracle.com 
265*12683SJimmy.Vetayases@oracle.com 		vecp->v_type = (ushort_t)type;
266*12683SJimmy.Vetayases@oracle.com 		vecp->v_inum = inum + i;
267*12683SJimmy.Vetayases@oracle.com 		vecp->v_flags = flags;
268*12683SJimmy.Vetayases@oracle.com 
269*12683SJimmy.Vetayases@oracle.com 		if (dip != NULL)
270*12683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(vecp, dip, inum + i);
271*12683SJimmy.Vetayases@oracle.com 
272*12683SJimmy.Vetayases@oracle.com 		if (i == 0)
273*12683SJimmy.Vetayases@oracle.com 			startp = vecp;
274*12683SJimmy.Vetayases@oracle.com 	}
275*12683SJimmy.Vetayases@oracle.com 
276*12683SJimmy.Vetayases@oracle.com 	return (startp);
277*12683SJimmy.Vetayases@oracle.com 
278*12683SJimmy.Vetayases@oracle.com fail:
279*12683SJimmy.Vetayases@oracle.com 	while (i-- > 0) {	/* Free allocated vectors */
280*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(tocpu, start + i);
281*12683SJimmy.Vetayases@oracle.com 		apix_clear_dev_map(dip, inum + i, type);
282*12683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(vecp);
283*12683SJimmy.Vetayases@oracle.com 	}
284*12683SJimmy.Vetayases@oracle.com 	return (NULL);
285*12683SJimmy.Vetayases@oracle.com }
286*12683SJimmy.Vetayases@oracle.com 
287*12683SJimmy.Vetayases@oracle.com #define	APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\
288*12683SJimmy.Vetayases@oracle.com do {\
289*12683SJimmy.Vetayases@oracle.com 	if ((_ctrl) & PCI_MSI_64BIT_MASK)\
290*12683SJimmy.Vetayases@oracle.com 		pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\
291*12683SJimmy.Vetayases@oracle.com 	else\
292*12683SJimmy.Vetayases@oracle.com 		pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\
293*12683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0)
294*12683SJimmy.Vetayases@oracle.com 
295*12683SJimmy.Vetayases@oracle.com static void
296*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type,
297*12683SJimmy.Vetayases@oracle.com     int inum, int count, uchar_t vector, int target_apic_id)
298*12683SJimmy.Vetayases@oracle.com {
299*12683SJimmy.Vetayases@oracle.com 	uint64_t		msi_addr, msi_data;
300*12683SJimmy.Vetayases@oracle.com 	ushort_t		msi_ctrl;
301*12683SJimmy.Vetayases@oracle.com 	int			i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
302*12683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
303*12683SJimmy.Vetayases@oracle.com 	msi_regs_t		msi_regs;
304*12683SJimmy.Vetayases@oracle.com 	void			*intrmap_tbl[PCI_MSI_MAX_INTRS];
305*12683SJimmy.Vetayases@oracle.com 
306*12683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n"
307*12683SJimmy.Vetayases@oracle.com 	    "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip,
308*12683SJimmy.Vetayases@oracle.com 	    ddi_driver_name(dip), inum, vector, target_apic_id));
309*12683SJimmy.Vetayases@oracle.com 
310*12683SJimmy.Vetayases@oracle.com 	ASSERT((handle != NULL) && (cap_ptr != 0));
311*12683SJimmy.Vetayases@oracle.com 
312*12683SJimmy.Vetayases@oracle.com 	msi_regs.mr_data = vector;
313*12683SJimmy.Vetayases@oracle.com 	msi_regs.mr_addr = target_apic_id;
314*12683SJimmy.Vetayases@oracle.com 
315*12683SJimmy.Vetayases@oracle.com 	intrmap_tbl[0] = vecp->v_intrmap_private;
316*12683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type,
317*12683SJimmy.Vetayases@oracle.com 	    count, 0xff);
318*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++)
319*12683SJimmy.Vetayases@oracle.com 		xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i];
320*12683SJimmy.Vetayases@oracle.com 
321*12683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private,
322*12683SJimmy.Vetayases@oracle.com 	    (void *)&msi_regs, type, count);
323*12683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private,
324*12683SJimmy.Vetayases@oracle.com 	    &msi_regs);
325*12683SJimmy.Vetayases@oracle.com 
326*12683SJimmy.Vetayases@oracle.com 	/* MSI Address */
327*12683SJimmy.Vetayases@oracle.com 	msi_addr = msi_regs.mr_addr;
328*12683SJimmy.Vetayases@oracle.com 
329*12683SJimmy.Vetayases@oracle.com 	/* MSI Data: MSI is edge triggered according to spec */
330*12683SJimmy.Vetayases@oracle.com 	msi_data = msi_regs.mr_data;
331*12683SJimmy.Vetayases@oracle.com 
332*12683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx "
333*12683SJimmy.Vetayases@oracle.com 	    "data=0x%lx\n", (long)msi_addr, (long)msi_data));
334*12683SJimmy.Vetayases@oracle.com 
335*12683SJimmy.Vetayases@oracle.com 	if (type == APIX_TYPE_MSI) {
336*12683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
337*12683SJimmy.Vetayases@oracle.com 
338*12683SJimmy.Vetayases@oracle.com 		/* Set the bits to inform how many MSIs are enabled */
339*12683SJimmy.Vetayases@oracle.com 		msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT);
340*12683SJimmy.Vetayases@oracle.com 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
341*12683SJimmy.Vetayases@oracle.com 
342*12683SJimmy.Vetayases@oracle.com 		if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0)
343*12683SJimmy.Vetayases@oracle.com 			APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl,
344*12683SJimmy.Vetayases@oracle.com 			    APIX_RESV_VECTOR);
345*12683SJimmy.Vetayases@oracle.com 
346*12683SJimmy.Vetayases@oracle.com 		pci_config_put32(handle,
347*12683SJimmy.Vetayases@oracle.com 		    cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr);
348*12683SJimmy.Vetayases@oracle.com 		if (msi_ctrl &  PCI_MSI_64BIT_MASK)
349*12683SJimmy.Vetayases@oracle.com 			pci_config_put32(handle,
350*12683SJimmy.Vetayases@oracle.com 			    cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32);
351*12683SJimmy.Vetayases@oracle.com 
352*12683SJimmy.Vetayases@oracle.com 		APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data);
353*12683SJimmy.Vetayases@oracle.com 	} else if (type == APIX_TYPE_MSIX) {
354*12683SJimmy.Vetayases@oracle.com 		uintptr_t	off;
355*12683SJimmy.Vetayases@oracle.com 		ddi_intr_msix_t	*msix_p = i_ddi_get_msix(dip);
356*12683SJimmy.Vetayases@oracle.com 
357*12683SJimmy.Vetayases@oracle.com 		/* Offset into the "inum"th entry in the MSI-X table */
358*12683SJimmy.Vetayases@oracle.com 		off = (uintptr_t)msix_p->msix_tbl_addr +
359*12683SJimmy.Vetayases@oracle.com 		    (inum * PCI_MSIX_VECTOR_SIZE);
360*12683SJimmy.Vetayases@oracle.com 
361*12683SJimmy.Vetayases@oracle.com 		ddi_put32(msix_p->msix_tbl_hdl,
362*12683SJimmy.Vetayases@oracle.com 		    (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data);
363*12683SJimmy.Vetayases@oracle.com 		ddi_put64(msix_p->msix_tbl_hdl,
364*12683SJimmy.Vetayases@oracle.com 		    (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr);
365*12683SJimmy.Vetayases@oracle.com 	}
366*12683SJimmy.Vetayases@oracle.com }
367*12683SJimmy.Vetayases@oracle.com 
368*12683SJimmy.Vetayases@oracle.com static void
369*12683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum)
370*12683SJimmy.Vetayases@oracle.com {
371*12683SJimmy.Vetayases@oracle.com 	ushort_t		msi_ctrl;
372*12683SJimmy.Vetayases@oracle.com 	int			cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
373*12683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
374*12683SJimmy.Vetayases@oracle.com 
375*12683SJimmy.Vetayases@oracle.com 	ASSERT((handle != NULL) && (cap_ptr != 0));
376*12683SJimmy.Vetayases@oracle.com 
377*12683SJimmy.Vetayases@oracle.com 	if (type == APIX_TYPE_MSI) {
378*12683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
379*12683SJimmy.Vetayases@oracle.com 		if ((msi_ctrl & PCI_MSI_ENABLE_BIT))
380*12683SJimmy.Vetayases@oracle.com 			return;
381*12683SJimmy.Vetayases@oracle.com 
382*12683SJimmy.Vetayases@oracle.com 		msi_ctrl |= PCI_MSI_ENABLE_BIT;
383*12683SJimmy.Vetayases@oracle.com 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
384*12683SJimmy.Vetayases@oracle.com 
385*12683SJimmy.Vetayases@oracle.com 	} else if (type == DDI_INTR_TYPE_MSIX) {
386*12683SJimmy.Vetayases@oracle.com 		uintptr_t	off;
387*12683SJimmy.Vetayases@oracle.com 		uint32_t	mask;
388*12683SJimmy.Vetayases@oracle.com 		ddi_intr_msix_t	*msix_p;
389*12683SJimmy.Vetayases@oracle.com 
390*12683SJimmy.Vetayases@oracle.com 		msix_p = i_ddi_get_msix(dip);
391*12683SJimmy.Vetayases@oracle.com 
392*12683SJimmy.Vetayases@oracle.com 		/* Offset into "inum"th entry in the MSI-X table & clear mask */
393*12683SJimmy.Vetayases@oracle.com 		off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
394*12683SJimmy.Vetayases@oracle.com 		    PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
395*12683SJimmy.Vetayases@oracle.com 
396*12683SJimmy.Vetayases@oracle.com 		mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
397*12683SJimmy.Vetayases@oracle.com 
398*12683SJimmy.Vetayases@oracle.com 		ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1));
399*12683SJimmy.Vetayases@oracle.com 
400*12683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
401*12683SJimmy.Vetayases@oracle.com 
402*12683SJimmy.Vetayases@oracle.com 		if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) {
403*12683SJimmy.Vetayases@oracle.com 			msi_ctrl |= PCI_MSIX_ENABLE_BIT;
404*12683SJimmy.Vetayases@oracle.com 			pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,
405*12683SJimmy.Vetayases@oracle.com 			    msi_ctrl);
406*12683SJimmy.Vetayases@oracle.com 		}
407*12683SJimmy.Vetayases@oracle.com 	}
408*12683SJimmy.Vetayases@oracle.com }
409*12683SJimmy.Vetayases@oracle.com 
410*12683SJimmy.Vetayases@oracle.com /*
411*12683SJimmy.Vetayases@oracle.com  * Setup interrupt, pogramming IO-APIC or MSI/X address/data.
412*12683SJimmy.Vetayases@oracle.com  */
413*12683SJimmy.Vetayases@oracle.com void
414*12683SJimmy.Vetayases@oracle.com apix_enable_vector(apix_vector_t *vecp)
415*12683SJimmy.Vetayases@oracle.com {
416*12683SJimmy.Vetayases@oracle.com 	int tocpu = vecp->v_cpuid, type = vecp->v_type;
417*12683SJimmy.Vetayases@oracle.com 	apic_cpus_info_t *cpu_infop;
418*12683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
419*12683SJimmy.Vetayases@oracle.com 
420*12683SJimmy.Vetayases@oracle.com 	ASSERT(tocpu < apic_nproc);
421*12683SJimmy.Vetayases@oracle.com 
422*12683SJimmy.Vetayases@oracle.com 	cpu_infop = &apic_cpus[tocpu];
423*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_flags & APIX_VECT_USER_BOUND)
424*12683SJimmy.Vetayases@oracle.com 		cpu_infop->aci_bound++;
425*12683SJimmy.Vetayases@oracle.com 	else
426*12683SJimmy.Vetayases@oracle.com 		cpu_infop->aci_temp_bound++;
427*12683SJimmy.Vetayases@oracle.com 
428*12683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
429*12683SJimmy.Vetayases@oracle.com 	lock_set(&apic_ioapic_lock);
430*12683SJimmy.Vetayases@oracle.com 
431*12683SJimmy.Vetayases@oracle.com 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {	/* fixed */
432*12683SJimmy.Vetayases@oracle.com 		apix_intx_enable(vecp->v_inum);
433*12683SJimmy.Vetayases@oracle.com 	} else {
434*12683SJimmy.Vetayases@oracle.com 		int inum = vecp->v_inum;
435*12683SJimmy.Vetayases@oracle.com 		dev_info_t *dip = APIX_GET_DIP(vecp);
436*12683SJimmy.Vetayases@oracle.com 		int count = i_ddi_intr_get_current_nintrs(dip);
437*12683SJimmy.Vetayases@oracle.com 
438*12683SJimmy.Vetayases@oracle.com 		if (type == APIX_TYPE_MSI) {	/* MSI */
439*12683SJimmy.Vetayases@oracle.com 			if (inum == apix_get_max_dev_inum(dip, type)) {
440*12683SJimmy.Vetayases@oracle.com 				/* last one */
441*12683SJimmy.Vetayases@oracle.com 				uchar_t start_inum = inum + 1 - count;
442*12683SJimmy.Vetayases@oracle.com 				uchar_t start_vect = vecp->v_vector + 1 - count;
443*12683SJimmy.Vetayases@oracle.com 				apix_vector_t *start_vecp =
444*12683SJimmy.Vetayases@oracle.com 				    xv_vector(vecp->v_cpuid, start_vect);
445*12683SJimmy.Vetayases@oracle.com 
446*12683SJimmy.Vetayases@oracle.com 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
447*12683SJimmy.Vetayases@oracle.com 				    "apix_pci_msi_enable_vector\n"));
448*12683SJimmy.Vetayases@oracle.com 				apix_pci_msi_enable_vector(start_vecp, dip,
449*12683SJimmy.Vetayases@oracle.com 				    type, start_inum, count, start_vect,
450*12683SJimmy.Vetayases@oracle.com 				    cpu_infop->aci_local_id);
451*12683SJimmy.Vetayases@oracle.com 
452*12683SJimmy.Vetayases@oracle.com 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
453*12683SJimmy.Vetayases@oracle.com 				    "apix_pci_msi_enable_mode\n"));
454*12683SJimmy.Vetayases@oracle.com 				apix_pci_msi_enable_mode(dip, type, inum);
455*12683SJimmy.Vetayases@oracle.com 			}
456*12683SJimmy.Vetayases@oracle.com 		} else {				/* MSI-X */
457*12683SJimmy.Vetayases@oracle.com 			apix_pci_msi_enable_vector(vecp, dip,
458*12683SJimmy.Vetayases@oracle.com 			    type, inum, 1, vecp->v_vector,
459*12683SJimmy.Vetayases@oracle.com 			    cpu_infop->aci_local_id);
460*12683SJimmy.Vetayases@oracle.com 			apix_pci_msi_enable_mode(dip, type, inum);
461*12683SJimmy.Vetayases@oracle.com 		}
462*12683SJimmy.Vetayases@oracle.com 	}
463*12683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_ENABLED;
464*12683SJimmy.Vetayases@oracle.com 	apic_redist_cpu_skip &= ~(1 << tocpu);
465*12683SJimmy.Vetayases@oracle.com 
466*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apic_ioapic_lock);
467*12683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
468*12683SJimmy.Vetayases@oracle.com }
469*12683SJimmy.Vetayases@oracle.com 
470*12683SJimmy.Vetayases@oracle.com /*
471*12683SJimmy.Vetayases@oracle.com  * Disable the interrupt
472*12683SJimmy.Vetayases@oracle.com  */
473*12683SJimmy.Vetayases@oracle.com void
474*12683SJimmy.Vetayases@oracle.com apix_disable_vector(apix_vector_t *vecp)
475*12683SJimmy.Vetayases@oracle.com {
476*12683SJimmy.Vetayases@oracle.com 	struct autovec *avp = vecp->v_autovect;
477*12683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
478*12683SJimmy.Vetayases@oracle.com 
479*12683SJimmy.Vetayases@oracle.com 	ASSERT(avp != NULL);
480*12683SJimmy.Vetayases@oracle.com 
481*12683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
482*12683SJimmy.Vetayases@oracle.com 	lock_set(&apic_ioapic_lock);
483*12683SJimmy.Vetayases@oracle.com 
484*12683SJimmy.Vetayases@oracle.com 	switch (vecp->v_type) {
485*12683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSI:
486*12683SJimmy.Vetayases@oracle.com 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
487*12683SJimmy.Vetayases@oracle.com 		/*
488*12683SJimmy.Vetayases@oracle.com 		 * Disable the MSI vector
489*12683SJimmy.Vetayases@oracle.com 		 * Make sure we only disable on the last
490*12683SJimmy.Vetayases@oracle.com 		 * of the multi-MSI support
491*12683SJimmy.Vetayases@oracle.com 		 */
492*12683SJimmy.Vetayases@oracle.com 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
493*12683SJimmy.Vetayases@oracle.com 			apic_pci_msi_disable_mode(avp->av_dip,
494*12683SJimmy.Vetayases@oracle.com 			    DDI_INTR_TYPE_MSI);
495*12683SJimmy.Vetayases@oracle.com 		}
496*12683SJimmy.Vetayases@oracle.com 		break;
497*12683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSIX:
498*12683SJimmy.Vetayases@oracle.com 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
499*12683SJimmy.Vetayases@oracle.com 		/*
500*12683SJimmy.Vetayases@oracle.com 		 * Disable the MSI-X vector
501*12683SJimmy.Vetayases@oracle.com 		 * needs to clear its mask and addr/data for each MSI-X
502*12683SJimmy.Vetayases@oracle.com 		 */
503*12683SJimmy.Vetayases@oracle.com 		apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX,
504*12683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
505*12683SJimmy.Vetayases@oracle.com 		/*
506*12683SJimmy.Vetayases@oracle.com 		 * Make sure we only disable on the last MSI-X
507*12683SJimmy.Vetayases@oracle.com 		 */
508*12683SJimmy.Vetayases@oracle.com 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
509*12683SJimmy.Vetayases@oracle.com 			apic_pci_msi_disable_mode(avp->av_dip,
510*12683SJimmy.Vetayases@oracle.com 			    DDI_INTR_TYPE_MSIX);
511*12683SJimmy.Vetayases@oracle.com 		}
512*12683SJimmy.Vetayases@oracle.com 		break;
513*12683SJimmy.Vetayases@oracle.com 	default:
514*12683SJimmy.Vetayases@oracle.com 		apix_intx_disable(vecp->v_inum);
515*12683SJimmy.Vetayases@oracle.com 		break;
516*12683SJimmy.Vetayases@oracle.com 	}
517*12683SJimmy.Vetayases@oracle.com 
518*12683SJimmy.Vetayases@oracle.com 	if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND))
519*12683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_DISABLED;
520*12683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private);
521*12683SJimmy.Vetayases@oracle.com 	vecp->v_intrmap_private = NULL;
522*12683SJimmy.Vetayases@oracle.com 
523*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apic_ioapic_lock);
524*12683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
525*12683SJimmy.Vetayases@oracle.com }
526*12683SJimmy.Vetayases@oracle.com 
527*12683SJimmy.Vetayases@oracle.com /*
528*12683SJimmy.Vetayases@oracle.com  * Mark vector as obsoleted or freed. The vector is marked
529*12683SJimmy.Vetayases@oracle.com  * obsoleted if there are pending requests on it. Otherwise,
530*12683SJimmy.Vetayases@oracle.com  * free the vector. The obsoleted vectors get freed after
531*12683SJimmy.Vetayases@oracle.com  * being serviced.
532*12683SJimmy.Vetayases@oracle.com  *
533*12683SJimmy.Vetayases@oracle.com  * Return 1 on being obosoleted and 0 on being freed.
534*12683SJimmy.Vetayases@oracle.com  */
535*12683SJimmy.Vetayases@oracle.com #define	INTR_BUSY(_avp)\
536*12683SJimmy.Vetayases@oracle.com 	((((volatile ushort_t)(_avp)->av_flags) &\
537*12683SJimmy.Vetayases@oracle.com 	(AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0)
538*12683SJimmy.Vetayases@oracle.com #define	LOCAL_WITH_INTR_DISABLED(_cpuid)\
539*12683SJimmy.Vetayases@oracle.com 	((_cpuid) == psm_get_cpu_id() && !interrupts_enabled())
540*12683SJimmy.Vetayases@oracle.com static uint64_t dummy_tick;
541*12683SJimmy.Vetayases@oracle.com 
542*12683SJimmy.Vetayases@oracle.com int
543*12683SJimmy.Vetayases@oracle.com apix_obsolete_vector(apix_vector_t *vecp)
544*12683SJimmy.Vetayases@oracle.com {
545*12683SJimmy.Vetayases@oracle.com 	struct autovec *avp = vecp->v_autovect;
546*12683SJimmy.Vetayases@oracle.com 	int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid;
547*12683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
548*12683SJimmy.Vetayases@oracle.com 
549*12683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(cpuid));
550*12683SJimmy.Vetayases@oracle.com 
551*12683SJimmy.Vetayases@oracle.com 	for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) {
552*12683SJimmy.Vetayases@oracle.com 		if (avp->av_vector == NULL)
553*12683SJimmy.Vetayases@oracle.com 			continue;
554*12683SJimmy.Vetayases@oracle.com 
555*12683SJimmy.Vetayases@oracle.com 		if (LOCAL_WITH_INTR_DISABLED(cpuid)) {
556*12683SJimmy.Vetayases@oracle.com 			int bit, index, irr;
557*12683SJimmy.Vetayases@oracle.com 
558*12683SJimmy.Vetayases@oracle.com 			if (INTR_BUSY(avp)) {
559*12683SJimmy.Vetayases@oracle.com 				busy++;
560*12683SJimmy.Vetayases@oracle.com 				continue;
561*12683SJimmy.Vetayases@oracle.com 			}
562*12683SJimmy.Vetayases@oracle.com 
563*12683SJimmy.Vetayases@oracle.com 			/* check IRR for pending interrupts */
564*12683SJimmy.Vetayases@oracle.com 			index = vecp->v_vector / 32;
565*12683SJimmy.Vetayases@oracle.com 			bit = vecp->v_vector % 32;
566*12683SJimmy.Vetayases@oracle.com 			irr = apic_reg_ops->apic_read(APIC_IRR_REG + index);
567*12683SJimmy.Vetayases@oracle.com 			if ((irr & (1 << bit)) != 0)
568*12683SJimmy.Vetayases@oracle.com 				busy++;
569*12683SJimmy.Vetayases@oracle.com 
570*12683SJimmy.Vetayases@oracle.com 			if (!busy)
571*12683SJimmy.Vetayases@oracle.com 				apix_remove_av(vecp, avp);
572*12683SJimmy.Vetayases@oracle.com 
573*12683SJimmy.Vetayases@oracle.com 			continue;
574*12683SJimmy.Vetayases@oracle.com 		}
575*12683SJimmy.Vetayases@oracle.com 
576*12683SJimmy.Vetayases@oracle.com 		repeats = 0;
577*12683SJimmy.Vetayases@oracle.com 		do {
578*12683SJimmy.Vetayases@oracle.com 			repeats++;
579*12683SJimmy.Vetayases@oracle.com 			for (tries = 0; tries < apic_max_reps_clear_pending;
580*12683SJimmy.Vetayases@oracle.com 			    tries++)
581*12683SJimmy.Vetayases@oracle.com 				if (!INTR_BUSY(avp))
582*12683SJimmy.Vetayases@oracle.com 					break;
583*12683SJimmy.Vetayases@oracle.com 		} while (INTR_BUSY(avp) &&
584*12683SJimmy.Vetayases@oracle.com 		    (repeats < apic_max_reps_clear_pending));
585*12683SJimmy.Vetayases@oracle.com 
586*12683SJimmy.Vetayases@oracle.com 		if (INTR_BUSY(avp))
587*12683SJimmy.Vetayases@oracle.com 			busy++;
588*12683SJimmy.Vetayases@oracle.com 		else {
589*12683SJimmy.Vetayases@oracle.com 			/*
590*12683SJimmy.Vetayases@oracle.com 			 * Interrupt is not in pending list or being serviced.
591*12683SJimmy.Vetayases@oracle.com 			 * However it might be cached in Local APIC's IRR
592*12683SJimmy.Vetayases@oracle.com 			 * register. It's impossible to check another CPU's
593*12683SJimmy.Vetayases@oracle.com 			 * IRR register. Then wait till lower levels finish
594*12683SJimmy.Vetayases@oracle.com 			 * running.
595*12683SJimmy.Vetayases@oracle.com 			 */
596*12683SJimmy.Vetayases@oracle.com 			for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++)
597*12683SJimmy.Vetayases@oracle.com 				apix_wait_till_seen(cpuid, ipl);
598*12683SJimmy.Vetayases@oracle.com 			if (INTR_BUSY(avp))
599*12683SJimmy.Vetayases@oracle.com 				busy++;
600*12683SJimmy.Vetayases@oracle.com 		}
601*12683SJimmy.Vetayases@oracle.com 
602*12683SJimmy.Vetayases@oracle.com 		if (!busy)
603*12683SJimmy.Vetayases@oracle.com 			apix_remove_av(vecp, avp);
604*12683SJimmy.Vetayases@oracle.com 	}
605*12683SJimmy.Vetayases@oracle.com 
606*12683SJimmy.Vetayases@oracle.com 	if (busy) {
607*12683SJimmy.Vetayases@oracle.com 		apix_vector_t *tp = apixp->x_obsoletes;
608*12683SJimmy.Vetayases@oracle.com 
609*12683SJimmy.Vetayases@oracle.com 		if (vecp->v_state == APIX_STATE_OBSOLETED)
610*12683SJimmy.Vetayases@oracle.com 			return (1);
611*12683SJimmy.Vetayases@oracle.com 
612*12683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_OBSOLETED;
613*12683SJimmy.Vetayases@oracle.com 		vecp->v_next = NULL;
614*12683SJimmy.Vetayases@oracle.com 		if (tp == NULL)
615*12683SJimmy.Vetayases@oracle.com 			apixp->x_obsoletes = vecp;
616*12683SJimmy.Vetayases@oracle.com 		else {
617*12683SJimmy.Vetayases@oracle.com 			while (tp->v_next != NULL)
618*12683SJimmy.Vetayases@oracle.com 				tp = tp->v_next;
619*12683SJimmy.Vetayases@oracle.com 			tp->v_next = vecp;
620*12683SJimmy.Vetayases@oracle.com 		}
621*12683SJimmy.Vetayases@oracle.com 		return (1);
622*12683SJimmy.Vetayases@oracle.com 	}
623*12683SJimmy.Vetayases@oracle.com 
624*12683SJimmy.Vetayases@oracle.com 	/* interrupt is not busy */
625*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_state == APIX_STATE_OBSOLETED) {
626*12683SJimmy.Vetayases@oracle.com 		/* remove from obsoleted list */
627*12683SJimmy.Vetayases@oracle.com 		apixp->x_obsoletes = vecp->v_next;
628*12683SJimmy.Vetayases@oracle.com 		vecp->v_next = NULL;
629*12683SJimmy.Vetayases@oracle.com 	}
630*12683SJimmy.Vetayases@oracle.com 	apix_cleanup_vector(vecp);
631*12683SJimmy.Vetayases@oracle.com 	return (0);
632*12683SJimmy.Vetayases@oracle.com }
633*12683SJimmy.Vetayases@oracle.com 
634*12683SJimmy.Vetayases@oracle.com /*
635*12683SJimmy.Vetayases@oracle.com  * Duplicate number of continuous vectors to specified target vectors.
636*12683SJimmy.Vetayases@oracle.com  */
637*12683SJimmy.Vetayases@oracle.com static void
638*12683SJimmy.Vetayases@oracle.com apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count)
639*12683SJimmy.Vetayases@oracle.com {
640*12683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
641*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *fromp, *top;
642*12683SJimmy.Vetayases@oracle.com 	processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid;
643*12683SJimmy.Vetayases@oracle.com 	uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector;
644*12683SJimmy.Vetayases@oracle.com 	int i, inum;
645*12683SJimmy.Vetayases@oracle.com 
646*12683SJimmy.Vetayases@oracle.com 	ASSERT(oldp->v_type != APIX_TYPE_IPI);
647*12683SJimmy.Vetayases@oracle.com 
648*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
649*12683SJimmy.Vetayases@oracle.com 		fromp = xv_vector(oldcpu, oldvec + i);
650*12683SJimmy.Vetayases@oracle.com 		top = xv_vector(newcpu, newvec + i);
651*12683SJimmy.Vetayases@oracle.com 		ASSERT(fromp != NULL && top != NULL);
652*12683SJimmy.Vetayases@oracle.com 
653*12683SJimmy.Vetayases@oracle.com 		/* copy over original one */
654*12683SJimmy.Vetayases@oracle.com 		top->v_state = fromp->v_state;
655*12683SJimmy.Vetayases@oracle.com 		top->v_type = fromp->v_type;
656*12683SJimmy.Vetayases@oracle.com 		top->v_bound_cpuid = fromp->v_bound_cpuid;
657*12683SJimmy.Vetayases@oracle.com 		top->v_inum = fromp->v_inum;
658*12683SJimmy.Vetayases@oracle.com 		top->v_flags = fromp->v_flags;
659*12683SJimmy.Vetayases@oracle.com 		top->v_intrmap_private = fromp->v_intrmap_private;
660*12683SJimmy.Vetayases@oracle.com 
661*12683SJimmy.Vetayases@oracle.com 		for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) {
662*12683SJimmy.Vetayases@oracle.com 			if (avp->av_vector == NULL)
663*12683SJimmy.Vetayases@oracle.com 				continue;
664*12683SJimmy.Vetayases@oracle.com 
665*12683SJimmy.Vetayases@oracle.com 			apix_insert_av(top, avp->av_intr_id, avp->av_vector,
666*12683SJimmy.Vetayases@oracle.com 			    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
667*12683SJimmy.Vetayases@oracle.com 			    avp->av_prilevel, avp->av_dip);
668*12683SJimmy.Vetayases@oracle.com 
669*12683SJimmy.Vetayases@oracle.com 			if (fromp->v_type == APIX_TYPE_FIXED &&
670*12683SJimmy.Vetayases@oracle.com 			    avp->av_dip != NULL) {
671*12683SJimmy.Vetayases@oracle.com 				inum = GET_INTR_INUM(avp->av_intr_id);
672*12683SJimmy.Vetayases@oracle.com 				apix_set_dev_map(top, avp->av_dip, inum);
673*12683SJimmy.Vetayases@oracle.com 			}
674*12683SJimmy.Vetayases@oracle.com 		}
675*12683SJimmy.Vetayases@oracle.com 
676*12683SJimmy.Vetayases@oracle.com 		if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) &&
677*12683SJimmy.Vetayases@oracle.com 		    fromp->v_devp != NULL)
678*12683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(top, fromp->v_devp->dv_dip,
679*12683SJimmy.Vetayases@oracle.com 			    fromp->v_devp->dv_inum);
680*12683SJimmy.Vetayases@oracle.com 	}
681*12683SJimmy.Vetayases@oracle.com }
682*12683SJimmy.Vetayases@oracle.com 
683*12683SJimmy.Vetayases@oracle.com static apix_vector_t *
684*12683SJimmy.Vetayases@oracle.com apix_init_vector(processorid_t cpuid, uchar_t vector)
685*12683SJimmy.Vetayases@oracle.com {
686*12683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
687*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp = apixp->x_vectbl[vector];
688*12683SJimmy.Vetayases@oracle.com 
689*12683SJimmy.Vetayases@oracle.com 	ASSERT(IS_VECT_FREE(vecp));
690*12683SJimmy.Vetayases@oracle.com 
691*12683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
692*12683SJimmy.Vetayases@oracle.com 		vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
693*12683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
694*12683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "apix: no memory to allocate vector");
695*12683SJimmy.Vetayases@oracle.com 			return (NULL);
696*12683SJimmy.Vetayases@oracle.com 		}
697*12683SJimmy.Vetayases@oracle.com 		apixp->x_vectbl[vector] = vecp;
698*12683SJimmy.Vetayases@oracle.com 	}
699*12683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_ALLOCED;
700*12683SJimmy.Vetayases@oracle.com 	vecp->v_cpuid = vecp->v_bound_cpuid = cpuid;
701*12683SJimmy.Vetayases@oracle.com 	vecp->v_vector = vector;
702*12683SJimmy.Vetayases@oracle.com 
703*12683SJimmy.Vetayases@oracle.com 	return (vecp);
704*12683SJimmy.Vetayases@oracle.com }
705*12683SJimmy.Vetayases@oracle.com 
706*12683SJimmy.Vetayases@oracle.com static void
707*12683SJimmy.Vetayases@oracle.com apix_cleanup_vector(apix_vector_t *vecp)
708*12683SJimmy.Vetayases@oracle.com {
709*12683SJimmy.Vetayases@oracle.com 	ASSERT(vecp->v_share == 0);
710*12683SJimmy.Vetayases@oracle.com 	vecp->v_bound_cpuid = IRQ_UNINIT;
711*12683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_FREED;
712*12683SJimmy.Vetayases@oracle.com 	vecp->v_type = 0;
713*12683SJimmy.Vetayases@oracle.com 	vecp->v_flags = 0;
714*12683SJimmy.Vetayases@oracle.com 	vecp->v_busy = 0;
715*12683SJimmy.Vetayases@oracle.com }
716*12683SJimmy.Vetayases@oracle.com 
717*12683SJimmy.Vetayases@oracle.com static void
718*12683SJimmy.Vetayases@oracle.com apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count)
719*12683SJimmy.Vetayases@oracle.com {
720*12683SJimmy.Vetayases@oracle.com #ifdef DEBUG
721*12683SJimmy.Vetayases@oracle.com 	major_t major;
722*12683SJimmy.Vetayases@oracle.com 	char *name, *drv_name;
723*12683SJimmy.Vetayases@oracle.com 	int instance, len, t_len;
724*12683SJimmy.Vetayases@oracle.com 	char mesg[1024] = "apix: ";
725*12683SJimmy.Vetayases@oracle.com 
726*12683SJimmy.Vetayases@oracle.com 	t_len = sizeof (mesg);
727*12683SJimmy.Vetayases@oracle.com 	len = strlen(mesg);
728*12683SJimmy.Vetayases@oracle.com 	if (dip != NULL) {
729*12683SJimmy.Vetayases@oracle.com 		name = ddi_get_name(dip);
730*12683SJimmy.Vetayases@oracle.com 		major = ddi_name_to_major(name);
731*12683SJimmy.Vetayases@oracle.com 		drv_name = ddi_major_to_name(major);
732*12683SJimmy.Vetayases@oracle.com 		instance = ddi_get_instance(dip);
733*12683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ",
734*12683SJimmy.Vetayases@oracle.com 		    name, drv_name, instance);
735*12683SJimmy.Vetayases@oracle.com 	}
736*12683SJimmy.Vetayases@oracle.com 	len = strlen(mesg);
737*12683SJimmy.Vetayases@oracle.com 
738*12683SJimmy.Vetayases@oracle.com 	switch (vecp->v_type) {
739*12683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_FIXED:
740*12683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "irqno %d",
741*12683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
742*12683SJimmy.Vetayases@oracle.com 		break;
743*12683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSI:
744*12683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len,
745*12683SJimmy.Vetayases@oracle.com 		    "msi inum %d (count %d)", vecp->v_inum, count);
746*12683SJimmy.Vetayases@oracle.com 		break;
747*12683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSIX:
748*12683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "msi-x inum %d",
749*12683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
750*12683SJimmy.Vetayases@oracle.com 		break;
751*12683SJimmy.Vetayases@oracle.com 	default:
752*12683SJimmy.Vetayases@oracle.com 		break;
753*12683SJimmy.Vetayases@oracle.com 
754*12683SJimmy.Vetayases@oracle.com 	}
755*12683SJimmy.Vetayases@oracle.com 
756*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on "
757*12683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid));
758*12683SJimmy.Vetayases@oracle.com #endif	/* DEBUG */
759*12683SJimmy.Vetayases@oracle.com }
760*12683SJimmy.Vetayases@oracle.com 
761*12683SJimmy.Vetayases@oracle.com /*
762*12683SJimmy.Vetayases@oracle.com  * Operations on avintr
763*12683SJimmy.Vetayases@oracle.com  */
764*12683SJimmy.Vetayases@oracle.com 
765*12683SJimmy.Vetayases@oracle.com #define	INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip)	\
766*12683SJimmy.Vetayases@oracle.com do { \
767*12683SJimmy.Vetayases@oracle.com 	(p)->av_intr_id = intr_id;	\
768*12683SJimmy.Vetayases@oracle.com 	(p)->av_vector = f;		\
769*12683SJimmy.Vetayases@oracle.com 	(p)->av_intarg1 = arg1;		\
770*12683SJimmy.Vetayases@oracle.com 	(p)->av_intarg2 = arg2;		\
771*12683SJimmy.Vetayases@oracle.com 	(p)->av_ticksp = ticksp;	\
772*12683SJimmy.Vetayases@oracle.com 	(p)->av_prilevel = ipl;		\
773*12683SJimmy.Vetayases@oracle.com 	(p)->av_dip = dip;		\
774*12683SJimmy.Vetayases@oracle.com 	(p)->av_flags = 0;		\
775*12683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0)
776*12683SJimmy.Vetayases@oracle.com 
777*12683SJimmy.Vetayases@oracle.com /*
778*12683SJimmy.Vetayases@oracle.com  * Insert an interrupt service routine into chain by its priority from
779*12683SJimmy.Vetayases@oracle.com  * high to low
780*12683SJimmy.Vetayases@oracle.com  */
781*12683SJimmy.Vetayases@oracle.com static void
782*12683SJimmy.Vetayases@oracle.com apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1,
783*12683SJimmy.Vetayases@oracle.com     caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip)
784*12683SJimmy.Vetayases@oracle.com {
785*12683SJimmy.Vetayases@oracle.com 	struct autovec *p, *prep, *mem;
786*12683SJimmy.Vetayases@oracle.com 
787*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, "
788*12683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid));
789*12683SJimmy.Vetayases@oracle.com 
790*12683SJimmy.Vetayases@oracle.com 	mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP);
791*12683SJimmy.Vetayases@oracle.com 	INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip);
792*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum])
793*12683SJimmy.Vetayases@oracle.com 		mem->av_flags |= AV_PENTRY_LEVEL;
794*12683SJimmy.Vetayases@oracle.com 
795*12683SJimmy.Vetayases@oracle.com 	vecp->v_share++;
796*12683SJimmy.Vetayases@oracle.com 	vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri;
797*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_autovect == NULL) {	/* Nothing on list - put it at head */
798*12683SJimmy.Vetayases@oracle.com 		vecp->v_autovect = mem;
799*12683SJimmy.Vetayases@oracle.com 		return;
800*12683SJimmy.Vetayases@oracle.com 	}
801*12683SJimmy.Vetayases@oracle.com 
802*12683SJimmy.Vetayases@oracle.com 	if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {	/* MSI/X */
803*12683SJimmy.Vetayases@oracle.com 		ASSERT(vecp->v_share == 1);	/* No sharing for MSI/X */
804*12683SJimmy.Vetayases@oracle.com 
805*12683SJimmy.Vetayases@oracle.com 		INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp,
806*12683SJimmy.Vetayases@oracle.com 		    ipl, dip);
807*12683SJimmy.Vetayases@oracle.com 		prep = vecp->v_autovect->av_link;
808*12683SJimmy.Vetayases@oracle.com 		vecp->v_autovect->av_link = NULL;
809*12683SJimmy.Vetayases@oracle.com 
810*12683SJimmy.Vetayases@oracle.com 		/* Free the following autovect chain */
811*12683SJimmy.Vetayases@oracle.com 		while (prep != NULL) {
812*12683SJimmy.Vetayases@oracle.com 			ASSERT(prep->av_vector == NULL);
813*12683SJimmy.Vetayases@oracle.com 
814*12683SJimmy.Vetayases@oracle.com 			p = prep;
815*12683SJimmy.Vetayases@oracle.com 			prep = prep->av_link;
816*12683SJimmy.Vetayases@oracle.com 			kmem_free(p, sizeof (struct autovec));
817*12683SJimmy.Vetayases@oracle.com 		}
818*12683SJimmy.Vetayases@oracle.com 
819*12683SJimmy.Vetayases@oracle.com 		kmem_free(mem, sizeof (struct autovec));
820*12683SJimmy.Vetayases@oracle.com 		return;
821*12683SJimmy.Vetayases@oracle.com 	}
822*12683SJimmy.Vetayases@oracle.com 
823*12683SJimmy.Vetayases@oracle.com 	/* find where it goes in list */
824*12683SJimmy.Vetayases@oracle.com 	prep = NULL;
825*12683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p != NULL; p = p->av_link) {
826*12683SJimmy.Vetayases@oracle.com 		if (p->av_vector && p->av_prilevel <= ipl)
827*12683SJimmy.Vetayases@oracle.com 			break;
828*12683SJimmy.Vetayases@oracle.com 		prep = p;
829*12683SJimmy.Vetayases@oracle.com 	}
830*12683SJimmy.Vetayases@oracle.com 	if (prep != NULL) {
831*12683SJimmy.Vetayases@oracle.com 		if (prep->av_vector == NULL) {	/* freed struct available */
832*12683SJimmy.Vetayases@oracle.com 			INIT_AUTOVEC(prep, intr_id, f, arg1, arg2,
833*12683SJimmy.Vetayases@oracle.com 			    ticksp, ipl, dip);
834*12683SJimmy.Vetayases@oracle.com 			prep->av_flags = mem->av_flags;
835*12683SJimmy.Vetayases@oracle.com 			kmem_free(mem, sizeof (struct autovec));
836*12683SJimmy.Vetayases@oracle.com 			return;
837*12683SJimmy.Vetayases@oracle.com 		}
838*12683SJimmy.Vetayases@oracle.com 
839*12683SJimmy.Vetayases@oracle.com 		mem->av_link = prep->av_link;
840*12683SJimmy.Vetayases@oracle.com 		prep->av_link = mem;
841*12683SJimmy.Vetayases@oracle.com 	} else {
842*12683SJimmy.Vetayases@oracle.com 		/* insert new intpt at beginning of chain */
843*12683SJimmy.Vetayases@oracle.com 		mem->av_link = vecp->v_autovect;
844*12683SJimmy.Vetayases@oracle.com 		vecp->v_autovect = mem;
845*12683SJimmy.Vetayases@oracle.com 	}
846*12683SJimmy.Vetayases@oracle.com }
847*12683SJimmy.Vetayases@oracle.com 
848*12683SJimmy.Vetayases@oracle.com /*
849*12683SJimmy.Vetayases@oracle.com  * After having made a change to an autovector list, wait until we have
850*12683SJimmy.Vetayases@oracle.com  * seen specified cpu not executing an interrupt at that level--so we
851*12683SJimmy.Vetayases@oracle.com  * know our change has taken effect completely (no old state in registers,
852*12683SJimmy.Vetayases@oracle.com  * etc).
853*12683SJimmy.Vetayases@oracle.com  */
854*12683SJimmy.Vetayases@oracle.com #define	APIX_CPU_ENABLED(_cp) \
855*12683SJimmy.Vetayases@oracle.com 	(quiesce_active == 0 && \
856*12683SJimmy.Vetayases@oracle.com 	(((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0))
857*12683SJimmy.Vetayases@oracle.com 
858*12683SJimmy.Vetayases@oracle.com static void
859*12683SJimmy.Vetayases@oracle.com apix_wait_till_seen(processorid_t cpuid, int ipl)
860*12683SJimmy.Vetayases@oracle.com {
861*12683SJimmy.Vetayases@oracle.com 	struct cpu *cp = cpu[cpuid];
862*12683SJimmy.Vetayases@oracle.com 
863*12683SJimmy.Vetayases@oracle.com 	if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid))
864*12683SJimmy.Vetayases@oracle.com 		return;
865*12683SJimmy.Vetayases@oracle.com 
866*12683SJimmy.Vetayases@oracle.com 	/*
867*12683SJimmy.Vetayases@oracle.com 	 * Don't wait if the CPU is quiesced or offlined. This can happen
868*12683SJimmy.Vetayases@oracle.com 	 * when a CPU is running pause thread but hardware triggered an
869*12683SJimmy.Vetayases@oracle.com 	 * interrupt and the interrupt gets queued.
870*12683SJimmy.Vetayases@oracle.com 	 */
871*12683SJimmy.Vetayases@oracle.com 	for (;;) {
872*12683SJimmy.Vetayases@oracle.com 		if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) &&
873*12683SJimmy.Vetayases@oracle.com 		    (!APIX_CPU_ENABLED(cp) ||
874*12683SJimmy.Vetayases@oracle.com 		    !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl)))
875*12683SJimmy.Vetayases@oracle.com 			return;
876*12683SJimmy.Vetayases@oracle.com 	}
877*12683SJimmy.Vetayases@oracle.com }
878*12683SJimmy.Vetayases@oracle.com 
879*12683SJimmy.Vetayases@oracle.com static void
880*12683SJimmy.Vetayases@oracle.com apix_remove_av(apix_vector_t *vecp, struct autovec *target)
881*12683SJimmy.Vetayases@oracle.com {
882*12683SJimmy.Vetayases@oracle.com 	int hi_pri = 0;
883*12683SJimmy.Vetayases@oracle.com 	struct autovec *p;
884*12683SJimmy.Vetayases@oracle.com 
885*12683SJimmy.Vetayases@oracle.com 	if (target == NULL)
886*12683SJimmy.Vetayases@oracle.com 		return;
887*12683SJimmy.Vetayases@oracle.com 
888*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, "
889*12683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid));
890*12683SJimmy.Vetayases@oracle.com 
891*12683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p; p = p->av_link) {
892*12683SJimmy.Vetayases@oracle.com 		if (p == target || p->av_vector == NULL)
893*12683SJimmy.Vetayases@oracle.com 			continue;
894*12683SJimmy.Vetayases@oracle.com 		hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri;
895*12683SJimmy.Vetayases@oracle.com 	}
896*12683SJimmy.Vetayases@oracle.com 
897*12683SJimmy.Vetayases@oracle.com 	vecp->v_share--;
898*12683SJimmy.Vetayases@oracle.com 	vecp->v_pri = hi_pri;
899*12683SJimmy.Vetayases@oracle.com 
900*12683SJimmy.Vetayases@oracle.com 	/*
901*12683SJimmy.Vetayases@oracle.com 	 * This drops the handler from the chain, it can no longer be called.
902*12683SJimmy.Vetayases@oracle.com 	 * However, there is no guarantee that the handler is not currently
903*12683SJimmy.Vetayases@oracle.com 	 * still executing.
904*12683SJimmy.Vetayases@oracle.com 	 */
905*12683SJimmy.Vetayases@oracle.com 	target->av_vector = NULL;
906*12683SJimmy.Vetayases@oracle.com 	/*
907*12683SJimmy.Vetayases@oracle.com 	 * There is a race where we could be just about to pick up the ticksp
908*12683SJimmy.Vetayases@oracle.com 	 * pointer to increment it after returning from the service routine
909*12683SJimmy.Vetayases@oracle.com 	 * in av_dispatch_autovect.  Rather than NULL it out let's just point
910*12683SJimmy.Vetayases@oracle.com 	 * it off to something safe so that any final tick update attempt
911*12683SJimmy.Vetayases@oracle.com 	 * won't fault.
912*12683SJimmy.Vetayases@oracle.com 	 */
913*12683SJimmy.Vetayases@oracle.com 	target->av_ticksp = &dummy_tick;
914*12683SJimmy.Vetayases@oracle.com 	apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel);
915*12683SJimmy.Vetayases@oracle.com }
916*12683SJimmy.Vetayases@oracle.com 
917*12683SJimmy.Vetayases@oracle.com static struct autovec *
918*12683SJimmy.Vetayases@oracle.com apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f)
919*12683SJimmy.Vetayases@oracle.com {
920*12683SJimmy.Vetayases@oracle.com 	struct autovec *p;
921*12683SJimmy.Vetayases@oracle.com 
922*12683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p; p = p->av_link) {
923*12683SJimmy.Vetayases@oracle.com 		if ((p->av_vector == f) && (p->av_intr_id == intr_id)) {
924*12683SJimmy.Vetayases@oracle.com 			/* found the handler */
925*12683SJimmy.Vetayases@oracle.com 			return (p);
926*12683SJimmy.Vetayases@oracle.com 		}
927*12683SJimmy.Vetayases@oracle.com 	}
928*12683SJimmy.Vetayases@oracle.com 
929*12683SJimmy.Vetayases@oracle.com 	return (NULL);
930*12683SJimmy.Vetayases@oracle.com }
931*12683SJimmy.Vetayases@oracle.com 
932*12683SJimmy.Vetayases@oracle.com static apix_vector_t *
933*12683SJimmy.Vetayases@oracle.com apix_find_vector_by_avintr(void *intr_id, avfunc f)
934*12683SJimmy.Vetayases@oracle.com {
935*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
936*12683SJimmy.Vetayases@oracle.com 	processorid_t n;
937*12683SJimmy.Vetayases@oracle.com 	uchar_t v;
938*12683SJimmy.Vetayases@oracle.com 
939*12683SJimmy.Vetayases@oracle.com 	for (n = 0; n < apic_nproc; n++) {
940*12683SJimmy.Vetayases@oracle.com 		if (!apix_is_cpu_enabled(n))
941*12683SJimmy.Vetayases@oracle.com 			continue;
942*12683SJimmy.Vetayases@oracle.com 
943*12683SJimmy.Vetayases@oracle.com 		for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) {
944*12683SJimmy.Vetayases@oracle.com 			vecp = xv_vector(n, v);
945*12683SJimmy.Vetayases@oracle.com 			if (vecp == NULL ||
946*12683SJimmy.Vetayases@oracle.com 			    vecp->v_state <= APIX_STATE_OBSOLETED)
947*12683SJimmy.Vetayases@oracle.com 				continue;
948*12683SJimmy.Vetayases@oracle.com 
949*12683SJimmy.Vetayases@oracle.com 			if (apix_find_av(vecp, intr_id, f) != NULL)
950*12683SJimmy.Vetayases@oracle.com 				return (vecp);
951*12683SJimmy.Vetayases@oracle.com 		}
952*12683SJimmy.Vetayases@oracle.com 	}
953*12683SJimmy.Vetayases@oracle.com 
954*12683SJimmy.Vetayases@oracle.com 	return (NULL);
955*12683SJimmy.Vetayases@oracle.com }
956*12683SJimmy.Vetayases@oracle.com 
957*12683SJimmy.Vetayases@oracle.com /*
958*12683SJimmy.Vetayases@oracle.com  * Add interrupt service routine.
959*12683SJimmy.Vetayases@oracle.com  *
960*12683SJimmy.Vetayases@oracle.com  * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually
961*12683SJimmy.Vetayases@oracle.com  * IRQ no. A vector is then allocated. Otherwise, the vector is already
962*12683SJimmy.Vetayases@oracle.com  * allocated. The input argument virt_vect is virtual vector of format
963*12683SJimmy.Vetayases@oracle.com  * APIX_VIRTVEC_VECTOR(cpuid, vector).
964*12683SJimmy.Vetayases@oracle.com  *
965*12683SJimmy.Vetayases@oracle.com  * Return 1 on success, 0 on failure.
966*12683SJimmy.Vetayases@oracle.com  */
967*12683SJimmy.Vetayases@oracle.com int
968*12683SJimmy.Vetayases@oracle.com apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name,
969*12683SJimmy.Vetayases@oracle.com     int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp,
970*12683SJimmy.Vetayases@oracle.com     dev_info_t *dip)
971*12683SJimmy.Vetayases@oracle.com {
972*12683SJimmy.Vetayases@oracle.com 	int cpuid;
973*12683SJimmy.Vetayases@oracle.com 	uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect);
974*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
975*12683SJimmy.Vetayases@oracle.com 
976*12683SJimmy.Vetayases@oracle.com 	if (xxintr == NULL) {
977*12683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "Attempt to add null for %s "
978*12683SJimmy.Vetayases@oracle.com 		    "on vector 0x%x,0x%x", name,
979*12683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_CPU(virt_vect),
980*12683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
981*12683SJimmy.Vetayases@oracle.com 		return (0);
982*12683SJimmy.Vetayases@oracle.com 	}
983*12683SJimmy.Vetayases@oracle.com 
984*12683SJimmy.Vetayases@oracle.com 	if (v >= APIX_IPI_MIN)	/* IPIs */
985*12683SJimmy.Vetayases@oracle.com 		return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2));
986*12683SJimmy.Vetayases@oracle.com 
987*12683SJimmy.Vetayases@oracle.com 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
988*12683SJimmy.Vetayases@oracle.com 		int irqno = virt_vect;
989*12683SJimmy.Vetayases@oracle.com 		int inum = GET_INTR_INUM(intr_id);
990*12683SJimmy.Vetayases@oracle.com 
991*12683SJimmy.Vetayases@oracle.com 		/*
992*12683SJimmy.Vetayases@oracle.com 		 * Senarios include:
993*12683SJimmy.Vetayases@oracle.com 		 * a. add_avintr() is called before irqp initialized (legacy)
994*12683SJimmy.Vetayases@oracle.com 		 * b. irqp is initialized, vector is not allocated (fixed)
995*12683SJimmy.Vetayases@oracle.com 		 * c. irqp is initialized, vector is allocated (fixed & shared)
996*12683SJimmy.Vetayases@oracle.com 		 */
997*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL)
998*12683SJimmy.Vetayases@oracle.com 			return (0);
999*12683SJimmy.Vetayases@oracle.com 
1000*12683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
1001*12683SJimmy.Vetayases@oracle.com 		v = vecp->v_vector;
1002*12683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(cpuid, v);
1003*12683SJimmy.Vetayases@oracle.com 	} else {	/* got virtual vector */
1004*12683SJimmy.Vetayases@oracle.com 		cpuid = APIX_VIRTVEC_CPU(virt_vect);
1005*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpuid, v);
1006*12683SJimmy.Vetayases@oracle.com 		ASSERT(vecp != NULL);
1007*12683SJimmy.Vetayases@oracle.com 	}
1008*12683SJimmy.Vetayases@oracle.com 
1009*12683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
1010*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_state <= APIX_STATE_OBSOLETED) {
1011*12683SJimmy.Vetayases@oracle.com 		vecp = NULL;
1012*12683SJimmy.Vetayases@oracle.com 
1013*12683SJimmy.Vetayases@oracle.com 		/*
1014*12683SJimmy.Vetayases@oracle.com 		 * Basically the allocated but not enabled interrupts
1015*12683SJimmy.Vetayases@oracle.com 		 * will not get re-targeted. But MSIs in allocated state
1016*12683SJimmy.Vetayases@oracle.com 		 * could be re-targeted due to group re-targeting.
1017*12683SJimmy.Vetayases@oracle.com 		 */
1018*12683SJimmy.Vetayases@oracle.com 		if (intr_id != NULL && dip != NULL) {
1019*12683SJimmy.Vetayases@oracle.com 			ddi_intr_handle_impl_t *hdlp = intr_id;
1020*12683SJimmy.Vetayases@oracle.com 			vecp = apix_get_dev_map(dip, hdlp->ih_inum,
1021*12683SJimmy.Vetayases@oracle.com 			    hdlp->ih_type);
1022*12683SJimmy.Vetayases@oracle.com 			ASSERT(vecp->v_state == APIX_STATE_ALLOCED);
1023*12683SJimmy.Vetayases@oracle.com 		}
1024*12683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
1025*12683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
1026*12683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x "
1027*12683SJimmy.Vetayases@oracle.com 			    " for %p to add", cpuid, v, intr_id);
1028*12683SJimmy.Vetayases@oracle.com 			return (0);
1029*12683SJimmy.Vetayases@oracle.com 		}
1030*12683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
1031*12683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector);
1032*12683SJimmy.Vetayases@oracle.com 	}
1033*12683SJimmy.Vetayases@oracle.com 
1034*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
1035*12683SJimmy.Vetayases@oracle.com 	apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip);
1036*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
1037*12683SJimmy.Vetayases@oracle.com 
1038*12683SJimmy.Vetayases@oracle.com 	(void) apix_addspl(virt_vect, ipl, 0, 0);
1039*12683SJimmy.Vetayases@oracle.com 
1040*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
1041*12683SJimmy.Vetayases@oracle.com 
1042*12683SJimmy.Vetayases@oracle.com 	return (1);
1043*12683SJimmy.Vetayases@oracle.com }
1044*12683SJimmy.Vetayases@oracle.com 
1045*12683SJimmy.Vetayases@oracle.com /*
1046*12683SJimmy.Vetayases@oracle.com  * Remove avintr
1047*12683SJimmy.Vetayases@oracle.com  *
1048*12683SJimmy.Vetayases@oracle.com  * For fixed, if it's the last one of shared interrupts, free the vector.
1049*12683SJimmy.Vetayases@oracle.com  * For msi/x, only disable the interrupt but not free the vector, which
1050*12683SJimmy.Vetayases@oracle.com  * is freed by PSM_XXX_FREE_XXX.
1051*12683SJimmy.Vetayases@oracle.com  */
1052*12683SJimmy.Vetayases@oracle.com void
1053*12683SJimmy.Vetayases@oracle.com apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect)
1054*12683SJimmy.Vetayases@oracle.com {
1055*12683SJimmy.Vetayases@oracle.com 	avfunc f;
1056*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1057*12683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
1058*12683SJimmy.Vetayases@oracle.com 	processorid_t cpuid;
1059*12683SJimmy.Vetayases@oracle.com 
1060*12683SJimmy.Vetayases@oracle.com 	if ((f = xxintr) == NULL)
1061*12683SJimmy.Vetayases@oracle.com 		return;
1062*12683SJimmy.Vetayases@oracle.com 
1063*12683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
1064*12683SJimmy.Vetayases@oracle.com 
1065*12683SJimmy.Vetayases@oracle.com 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
1066*12683SJimmy.Vetayases@oracle.com 		vecp = apix_intx_get_vector(virt_vect);
1067*12683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
1068*12683SJimmy.Vetayases@oracle.com 	} else	/* got virtual vector */
1069*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect),
1070*12683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
1071*12683SJimmy.Vetayases@oracle.com 
1072*12683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
1073*12683SJimmy.Vetayases@oracle.com 		lock_clear(&apix_lock);
1074*12683SJimmy.Vetayases@oracle.com 		cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove",
1075*12683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_CPU(virt_vect),
1076*12683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
1077*12683SJimmy.Vetayases@oracle.com 		return;
1078*12683SJimmy.Vetayases@oracle.com 	}
1079*12683SJimmy.Vetayases@oracle.com 
1080*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_state <= APIX_STATE_OBSOLETED ||
1081*12683SJimmy.Vetayases@oracle.com 	    ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) {
1082*12683SJimmy.Vetayases@oracle.com 		/*
1083*12683SJimmy.Vetayases@oracle.com 		 * It's possible that the interrupt is rebound to a
1084*12683SJimmy.Vetayases@oracle.com 		 * different cpu before rem_avintr() is called. Search
1085*12683SJimmy.Vetayases@oracle.com 		 * through all vectors once it happens.
1086*12683SJimmy.Vetayases@oracle.com 		 */
1087*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_find_vector_by_avintr(intr_id, f))
1088*12683SJimmy.Vetayases@oracle.com 		    == NULL) {
1089*12683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
1090*12683SJimmy.Vetayases@oracle.com 			cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x "
1091*12683SJimmy.Vetayases@oracle.com 			    "for %p to remove", APIX_VIRTVEC_CPU(virt_vect),
1092*12683SJimmy.Vetayases@oracle.com 			    APIX_VIRTVEC_VECTOR(virt_vect), intr_id);
1093*12683SJimmy.Vetayases@oracle.com 			return;
1094*12683SJimmy.Vetayases@oracle.com 		}
1095*12683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
1096*12683SJimmy.Vetayases@oracle.com 		avp = apix_find_av(vecp, intr_id, f);
1097*12683SJimmy.Vetayases@oracle.com 	}
1098*12683SJimmy.Vetayases@oracle.com 	cpuid = vecp->v_cpuid;
1099*12683SJimmy.Vetayases@oracle.com 
1100*12683SJimmy.Vetayases@oracle.com 	/* disable interrupt */
1101*12683SJimmy.Vetayases@oracle.com 	(void) apix_delspl(virt_vect, ipl, 0, 0);
1102*12683SJimmy.Vetayases@oracle.com 
1103*12683SJimmy.Vetayases@oracle.com 	/* remove ISR entry */
1104*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
1105*12683SJimmy.Vetayases@oracle.com 	apix_remove_av(vecp, avp);
1106*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
1107*12683SJimmy.Vetayases@oracle.com 
1108*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
1109*12683SJimmy.Vetayases@oracle.com }
1110*12683SJimmy.Vetayases@oracle.com 
1111*12683SJimmy.Vetayases@oracle.com /*
1112*12683SJimmy.Vetayases@oracle.com  * Device to vector mapping table
1113*12683SJimmy.Vetayases@oracle.com  */
1114*12683SJimmy.Vetayases@oracle.com 
1115*12683SJimmy.Vetayases@oracle.com static void
1116*12683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dev_info_t *dip, int inum, int type)
1117*12683SJimmy.Vetayases@oracle.com {
1118*12683SJimmy.Vetayases@oracle.com 	char *name;
1119*12683SJimmy.Vetayases@oracle.com 	major_t major;
1120*12683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp, *prev = NULL;
1121*12683SJimmy.Vetayases@oracle.com 	int found = 0;
1122*12683SJimmy.Vetayases@oracle.com 
1123*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1124*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1125*12683SJimmy.Vetayases@oracle.com 
1126*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
1127*12683SJimmy.Vetayases@oracle.com 
1128*12683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
1129*12683SJimmy.Vetayases@oracle.com 	    prev = dvp, dvp = dvp->dv_next) {
1130*12683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
1131*12683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == type) {
1132*12683SJimmy.Vetayases@oracle.com 			found++;
1133*12683SJimmy.Vetayases@oracle.com 			break;
1134*12683SJimmy.Vetayases@oracle.com 		}
1135*12683SJimmy.Vetayases@oracle.com 	}
1136*12683SJimmy.Vetayases@oracle.com 
1137*12683SJimmy.Vetayases@oracle.com 	if (!found) {
1138*12683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
1139*12683SJimmy.Vetayases@oracle.com 		return;
1140*12683SJimmy.Vetayases@oracle.com 	}
1141*12683SJimmy.Vetayases@oracle.com 
1142*12683SJimmy.Vetayases@oracle.com 	if (prev != NULL)
1143*12683SJimmy.Vetayases@oracle.com 		prev->dv_next = dvp->dv_next;
1144*12683SJimmy.Vetayases@oracle.com 
1145*12683SJimmy.Vetayases@oracle.com 	if (apix_dev_vector[major] == dvp)
1146*12683SJimmy.Vetayases@oracle.com 		apix_dev_vector[major] = dvp->dv_next;
1147*12683SJimmy.Vetayases@oracle.com 
1148*12683SJimmy.Vetayases@oracle.com 	dvp->dv_vector->v_devp = NULL;
1149*12683SJimmy.Vetayases@oracle.com 
1150*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
1151*12683SJimmy.Vetayases@oracle.com 
1152*12683SJimmy.Vetayases@oracle.com 	kmem_free(dvp, sizeof (apix_dev_vector_t));
1153*12683SJimmy.Vetayases@oracle.com }
1154*12683SJimmy.Vetayases@oracle.com 
1155*12683SJimmy.Vetayases@oracle.com void
1156*12683SJimmy.Vetayases@oracle.com apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum)
1157*12683SJimmy.Vetayases@oracle.com {
1158*12683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
1159*12683SJimmy.Vetayases@oracle.com 	char *name;
1160*12683SJimmy.Vetayases@oracle.com 	major_t major;
1161*12683SJimmy.Vetayases@oracle.com 	uint32_t found = 0;
1162*12683SJimmy.Vetayases@oracle.com 
1163*12683SJimmy.Vetayases@oracle.com 	ASSERT(dip != NULL);
1164*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1165*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1166*12683SJimmy.Vetayases@oracle.com 
1167*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
1168*12683SJimmy.Vetayases@oracle.com 
1169*12683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
1170*12683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
1171*12683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
1172*12683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == vecp->v_type) {
1173*12683SJimmy.Vetayases@oracle.com 			found++;
1174*12683SJimmy.Vetayases@oracle.com 			break;
1175*12683SJimmy.Vetayases@oracle.com 		}
1176*12683SJimmy.Vetayases@oracle.com 	}
1177*12683SJimmy.Vetayases@oracle.com 
1178*12683SJimmy.Vetayases@oracle.com 	if (found == 0) {	/* not found */
1179*12683SJimmy.Vetayases@oracle.com 		dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP);
1180*12683SJimmy.Vetayases@oracle.com 		dvp->dv_dip = dip;
1181*12683SJimmy.Vetayases@oracle.com 		dvp->dv_inum = inum;
1182*12683SJimmy.Vetayases@oracle.com 		dvp->dv_type = vecp->v_type;
1183*12683SJimmy.Vetayases@oracle.com 
1184*12683SJimmy.Vetayases@oracle.com 		dvp->dv_next = apix_dev_vector[major];
1185*12683SJimmy.Vetayases@oracle.com 		apix_dev_vector[major] = dvp;
1186*12683SJimmy.Vetayases@oracle.com 	}
1187*12683SJimmy.Vetayases@oracle.com 	dvp->dv_vector = vecp;
1188*12683SJimmy.Vetayases@oracle.com 	vecp->v_devp = dvp;
1189*12683SJimmy.Vetayases@oracle.com 
1190*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
1191*12683SJimmy.Vetayases@oracle.com 
1192*12683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p "
1193*12683SJimmy.Vetayases@oracle.com 	    "inum=0x%x  vector=0x%x/0x%x\n",
1194*12683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, vecp->v_cpuid, vecp->v_vector));
1195*12683SJimmy.Vetayases@oracle.com }
1196*12683SJimmy.Vetayases@oracle.com 
1197*12683SJimmy.Vetayases@oracle.com apix_vector_t *
1198*12683SJimmy.Vetayases@oracle.com apix_get_dev_map(dev_info_t *dip, int inum, int type)
1199*12683SJimmy.Vetayases@oracle.com {
1200*12683SJimmy.Vetayases@oracle.com 	char *name;
1201*12683SJimmy.Vetayases@oracle.com 	major_t major;
1202*12683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
1203*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1204*12683SJimmy.Vetayases@oracle.com 
1205*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1206*12683SJimmy.Vetayases@oracle.com 	if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE)
1207*12683SJimmy.Vetayases@oracle.com 		return (NULL);
1208*12683SJimmy.Vetayases@oracle.com 
1209*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
1210*12683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
1211*12683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
1212*12683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
1213*12683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == type) {
1214*12683SJimmy.Vetayases@oracle.com 			vecp = dvp->dv_vector;
1215*12683SJimmy.Vetayases@oracle.com 			mutex_exit(&apix_mutex);
1216*12683SJimmy.Vetayases@oracle.com 			return (vecp);
1217*12683SJimmy.Vetayases@oracle.com 		}
1218*12683SJimmy.Vetayases@oracle.com 	}
1219*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
1220*12683SJimmy.Vetayases@oracle.com 
1221*12683SJimmy.Vetayases@oracle.com 	return (NULL);
1222*12683SJimmy.Vetayases@oracle.com }
1223*12683SJimmy.Vetayases@oracle.com 
1224*12683SJimmy.Vetayases@oracle.com /*
1225*12683SJimmy.Vetayases@oracle.com  * Get minimum inum for specified device, used for MSI
1226*12683SJimmy.Vetayases@oracle.com  */
1227*12683SJimmy.Vetayases@oracle.com int
1228*12683SJimmy.Vetayases@oracle.com apix_get_min_dev_inum(dev_info_t *dip, int type)
1229*12683SJimmy.Vetayases@oracle.com {
1230*12683SJimmy.Vetayases@oracle.com 	char *name;
1231*12683SJimmy.Vetayases@oracle.com 	major_t major;
1232*12683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
1233*12683SJimmy.Vetayases@oracle.com 	int inum = -1;
1234*12683SJimmy.Vetayases@oracle.com 
1235*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1236*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1237*12683SJimmy.Vetayases@oracle.com 
1238*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
1239*12683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
1240*12683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
1241*12683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
1242*12683SJimmy.Vetayases@oracle.com 			if (inum == -1)
1243*12683SJimmy.Vetayases@oracle.com 				inum = dvp->dv_inum;
1244*12683SJimmy.Vetayases@oracle.com 			else
1245*12683SJimmy.Vetayases@oracle.com 				inum = (dvp->dv_inum < inum) ?
1246*12683SJimmy.Vetayases@oracle.com 				    dvp->dv_inum : inum;
1247*12683SJimmy.Vetayases@oracle.com 		}
1248*12683SJimmy.Vetayases@oracle.com 	}
1249*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
1250*12683SJimmy.Vetayases@oracle.com 
1251*12683SJimmy.Vetayases@oracle.com 	return (inum);
1252*12683SJimmy.Vetayases@oracle.com }
1253*12683SJimmy.Vetayases@oracle.com 
1254*12683SJimmy.Vetayases@oracle.com int
1255*12683SJimmy.Vetayases@oracle.com apix_get_max_dev_inum(dev_info_t *dip, int type)
1256*12683SJimmy.Vetayases@oracle.com {
1257*12683SJimmy.Vetayases@oracle.com 	char *name;
1258*12683SJimmy.Vetayases@oracle.com 	major_t major;
1259*12683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
1260*12683SJimmy.Vetayases@oracle.com 	int inum = -1;
1261*12683SJimmy.Vetayases@oracle.com 
1262*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1263*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1264*12683SJimmy.Vetayases@oracle.com 
1265*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
1266*12683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
1267*12683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
1268*12683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
1269*12683SJimmy.Vetayases@oracle.com 			if (inum == -1)
1270*12683SJimmy.Vetayases@oracle.com 				inum = dvp->dv_inum;
1271*12683SJimmy.Vetayases@oracle.com 			else
1272*12683SJimmy.Vetayases@oracle.com 				inum = (dvp->dv_inum > inum) ?
1273*12683SJimmy.Vetayases@oracle.com 				    dvp->dv_inum : inum;
1274*12683SJimmy.Vetayases@oracle.com 		}
1275*12683SJimmy.Vetayases@oracle.com 	}
1276*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
1277*12683SJimmy.Vetayases@oracle.com 
1278*12683SJimmy.Vetayases@oracle.com 	return (inum);
1279*12683SJimmy.Vetayases@oracle.com }
1280*12683SJimmy.Vetayases@oracle.com 
1281*12683SJimmy.Vetayases@oracle.com /*
1282*12683SJimmy.Vetayases@oracle.com  * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu
1283*12683SJimmy.Vetayases@oracle.com  * binding policy
1284*12683SJimmy.Vetayases@oracle.com  */
1285*12683SJimmy.Vetayases@oracle.com 
1286*12683SJimmy.Vetayases@oracle.com static uint32_t
1287*12683SJimmy.Vetayases@oracle.com apix_get_dev_binding(dev_info_t *dip)
1288*12683SJimmy.Vetayases@oracle.com {
1289*12683SJimmy.Vetayases@oracle.com 	major_t major;
1290*12683SJimmy.Vetayases@oracle.com 	char *name;
1291*12683SJimmy.Vetayases@oracle.com 	uint32_t cpu = IRQ_UNINIT;
1292*12683SJimmy.Vetayases@oracle.com 
1293*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1294*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1295*12683SJimmy.Vetayases@oracle.com 	if (major < devcnt) {
1296*12683SJimmy.Vetayases@oracle.com 		mutex_enter(&apix_mutex);
1297*12683SJimmy.Vetayases@oracle.com 		cpu = apix_major_to_cpu[major];
1298*12683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
1299*12683SJimmy.Vetayases@oracle.com 	}
1300*12683SJimmy.Vetayases@oracle.com 
1301*12683SJimmy.Vetayases@oracle.com 	return (cpu);
1302*12683SJimmy.Vetayases@oracle.com }
1303*12683SJimmy.Vetayases@oracle.com 
1304*12683SJimmy.Vetayases@oracle.com static void
1305*12683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dev_info_t *dip, uint32_t cpu)
1306*12683SJimmy.Vetayases@oracle.com {
1307*12683SJimmy.Vetayases@oracle.com 	major_t major;
1308*12683SJimmy.Vetayases@oracle.com 	char *name;
1309*12683SJimmy.Vetayases@oracle.com 
1310*12683SJimmy.Vetayases@oracle.com 	/* setup major to cpu mapping */
1311*12683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
1312*12683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
1313*12683SJimmy.Vetayases@oracle.com 	if (apix_major_to_cpu[major] == IRQ_UNINIT) {
1314*12683SJimmy.Vetayases@oracle.com 		mutex_enter(&apix_mutex);
1315*12683SJimmy.Vetayases@oracle.com 		apix_major_to_cpu[major] = cpu;
1316*12683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
1317*12683SJimmy.Vetayases@oracle.com 	}
1318*12683SJimmy.Vetayases@oracle.com }
1319*12683SJimmy.Vetayases@oracle.com 
1320*12683SJimmy.Vetayases@oracle.com /*
1321*12683SJimmy.Vetayases@oracle.com  * return the cpu to which this intr should be bound.
1322*12683SJimmy.Vetayases@oracle.com  * Check properties or any other mechanism to see if user wants it
1323*12683SJimmy.Vetayases@oracle.com  * bound to a specific CPU. If so, return the cpu id with high bit set.
1324*12683SJimmy.Vetayases@oracle.com  * If not, use the policy to choose a cpu and return the id.
1325*12683SJimmy.Vetayases@oracle.com  */
1326*12683SJimmy.Vetayases@oracle.com uint32_t
1327*12683SJimmy.Vetayases@oracle.com apix_bind_cpu(dev_info_t *dip)
1328*12683SJimmy.Vetayases@oracle.com {
1329*12683SJimmy.Vetayases@oracle.com 	int	instance, instno, prop_len, bind_cpu, count;
1330*12683SJimmy.Vetayases@oracle.com 	uint_t	i, rc;
1331*12683SJimmy.Vetayases@oracle.com 	major_t	major;
1332*12683SJimmy.Vetayases@oracle.com 	char	*name, *drv_name, *prop_val, *cptr;
1333*12683SJimmy.Vetayases@oracle.com 	char	prop_name[32];
1334*12683SJimmy.Vetayases@oracle.com 
1335*12683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
1336*12683SJimmy.Vetayases@oracle.com 
1337*12683SJimmy.Vetayases@oracle.com 	if (apic_intr_policy == INTR_LOWEST_PRIORITY) {
1338*12683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "apix: unsupported interrupt binding policy "
1339*12683SJimmy.Vetayases@oracle.com 		    "LOWEST PRIORITY, use ROUND ROBIN instead");
1340*12683SJimmy.Vetayases@oracle.com 		apic_intr_policy = INTR_ROUND_ROBIN;
1341*12683SJimmy.Vetayases@oracle.com 	}
1342*12683SJimmy.Vetayases@oracle.com 
1343*12683SJimmy.Vetayases@oracle.com 	if (apic_nproc == 1) {
1344*12683SJimmy.Vetayases@oracle.com 		lock_clear(&apix_lock);
1345*12683SJimmy.Vetayases@oracle.com 		return (0);
1346*12683SJimmy.Vetayases@oracle.com 	}
1347*12683SJimmy.Vetayases@oracle.com 
1348*12683SJimmy.Vetayases@oracle.com 	drv_name = NULL;
1349*12683SJimmy.Vetayases@oracle.com 	rc = DDI_PROP_NOT_FOUND;
1350*12683SJimmy.Vetayases@oracle.com 	major = (major_t)-1;
1351*12683SJimmy.Vetayases@oracle.com 	if (dip != NULL) {
1352*12683SJimmy.Vetayases@oracle.com 		name = ddi_get_name(dip);
1353*12683SJimmy.Vetayases@oracle.com 		major = ddi_name_to_major(name);
1354*12683SJimmy.Vetayases@oracle.com 		drv_name = ddi_major_to_name(major);
1355*12683SJimmy.Vetayases@oracle.com 		instance = ddi_get_instance(dip);
1356*12683SJimmy.Vetayases@oracle.com 		if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
1357*12683SJimmy.Vetayases@oracle.com 			bind_cpu = apix_get_dev_binding(dip);
1358*12683SJimmy.Vetayases@oracle.com 			if (bind_cpu != IRQ_UNINIT) {
1359*12683SJimmy.Vetayases@oracle.com 				lock_clear(&apix_lock);
1360*12683SJimmy.Vetayases@oracle.com 				return (bind_cpu);
1361*12683SJimmy.Vetayases@oracle.com 			}
1362*12683SJimmy.Vetayases@oracle.com 		}
1363*12683SJimmy.Vetayases@oracle.com 		/*
1364*12683SJimmy.Vetayases@oracle.com 		 * search for "drvname"_intpt_bind_cpus property first, the
1365*12683SJimmy.Vetayases@oracle.com 		 * syntax of the property should be "a[,b,c,...]" where
1366*12683SJimmy.Vetayases@oracle.com 		 * instance 0 binds to cpu a, instance 1 binds to cpu b,
1367*12683SJimmy.Vetayases@oracle.com 		 * instance 3 binds to cpu c...
1368*12683SJimmy.Vetayases@oracle.com 		 * ddi_getlongprop() will search /option first, then /
1369*12683SJimmy.Vetayases@oracle.com 		 * if "drvname"_intpt_bind_cpus doesn't exist, then find
1370*12683SJimmy.Vetayases@oracle.com 		 * intpt_bind_cpus property.  The syntax is the same, and
1371*12683SJimmy.Vetayases@oracle.com 		 * it applies to all the devices if its "drvname" specific
1372*12683SJimmy.Vetayases@oracle.com 		 * property doesn't exist
1373*12683SJimmy.Vetayases@oracle.com 		 */
1374*12683SJimmy.Vetayases@oracle.com 		(void) strcpy(prop_name, drv_name);
1375*12683SJimmy.Vetayases@oracle.com 		(void) strcat(prop_name, "_intpt_bind_cpus");
1376*12683SJimmy.Vetayases@oracle.com 		rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
1377*12683SJimmy.Vetayases@oracle.com 		    (caddr_t)&prop_val, &prop_len);
1378*12683SJimmy.Vetayases@oracle.com 		if (rc != DDI_PROP_SUCCESS) {
1379*12683SJimmy.Vetayases@oracle.com 			rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
1380*12683SJimmy.Vetayases@oracle.com 			    "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
1381*12683SJimmy.Vetayases@oracle.com 		}
1382*12683SJimmy.Vetayases@oracle.com 	}
1383*12683SJimmy.Vetayases@oracle.com 	if (rc == DDI_PROP_SUCCESS) {
1384*12683SJimmy.Vetayases@oracle.com 		for (i = count = 0; i < (prop_len - 1); i++)
1385*12683SJimmy.Vetayases@oracle.com 			if (prop_val[i] == ',')
1386*12683SJimmy.Vetayases@oracle.com 				count++;
1387*12683SJimmy.Vetayases@oracle.com 		if (prop_val[i-1] != ',')
1388*12683SJimmy.Vetayases@oracle.com 			count++;
1389*12683SJimmy.Vetayases@oracle.com 		/*
1390*12683SJimmy.Vetayases@oracle.com 		 * if somehow the binding instances defined in the
1391*12683SJimmy.Vetayases@oracle.com 		 * property are not enough for this instno., then
1392*12683SJimmy.Vetayases@oracle.com 		 * reuse the pattern for the next instance until
1393*12683SJimmy.Vetayases@oracle.com 		 * it reaches the requested instno
1394*12683SJimmy.Vetayases@oracle.com 		 */
1395*12683SJimmy.Vetayases@oracle.com 		instno = instance % count;
1396*12683SJimmy.Vetayases@oracle.com 		i = 0;
1397*12683SJimmy.Vetayases@oracle.com 		cptr = prop_val;
1398*12683SJimmy.Vetayases@oracle.com 		while (i < instno)
1399*12683SJimmy.Vetayases@oracle.com 			if (*cptr++ == ',')
1400*12683SJimmy.Vetayases@oracle.com 				i++;
1401*12683SJimmy.Vetayases@oracle.com 		bind_cpu = stoi(&cptr);
1402*12683SJimmy.Vetayases@oracle.com 		kmem_free(prop_val, prop_len);
1403*12683SJimmy.Vetayases@oracle.com 		/* if specific cpu is bogus, then default to cpu 0 */
1404*12683SJimmy.Vetayases@oracle.com 		if (bind_cpu >= apic_nproc) {
1405*12683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present",
1406*12683SJimmy.Vetayases@oracle.com 			    prop_name, prop_val, bind_cpu);
1407*12683SJimmy.Vetayases@oracle.com 			bind_cpu = 0;
1408*12683SJimmy.Vetayases@oracle.com 		} else {
1409*12683SJimmy.Vetayases@oracle.com 			/* indicate that we are bound at user request */
1410*12683SJimmy.Vetayases@oracle.com 			bind_cpu |= IRQ_USER_BOUND;
1411*12683SJimmy.Vetayases@oracle.com 		}
1412*12683SJimmy.Vetayases@oracle.com 		/*
1413*12683SJimmy.Vetayases@oracle.com 		 * no need to check apic_cpus[].aci_status, if specific cpu is
1414*12683SJimmy.Vetayases@oracle.com 		 * not up, then post_cpu_start will handle it.
1415*12683SJimmy.Vetayases@oracle.com 		 */
1416*12683SJimmy.Vetayases@oracle.com 	} else {
1417*12683SJimmy.Vetayases@oracle.com 		bind_cpu = apic_get_next_bind_cpu();
1418*12683SJimmy.Vetayases@oracle.com 	}
1419*12683SJimmy.Vetayases@oracle.com 
1420*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
1421*12683SJimmy.Vetayases@oracle.com 
1422*12683SJimmy.Vetayases@oracle.com 	return ((uint32_t)bind_cpu);
1423*12683SJimmy.Vetayases@oracle.com }
1424*12683SJimmy.Vetayases@oracle.com 
1425*12683SJimmy.Vetayases@oracle.com static boolean_t
1426*12683SJimmy.Vetayases@oracle.com apix_is_cpu_enabled(processorid_t cpuid)
1427*12683SJimmy.Vetayases@oracle.com {
1428*12683SJimmy.Vetayases@oracle.com 	apic_cpus_info_t *cpu_infop;
1429*12683SJimmy.Vetayases@oracle.com 
1430*12683SJimmy.Vetayases@oracle.com 	cpu_infop = &apic_cpus[cpuid];
1431*12683SJimmy.Vetayases@oracle.com 
1432*12683SJimmy.Vetayases@oracle.com 	if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0)
1433*12683SJimmy.Vetayases@oracle.com 		return (B_FALSE);
1434*12683SJimmy.Vetayases@oracle.com 
1435*12683SJimmy.Vetayases@oracle.com 	return (B_TRUE);
1436*12683SJimmy.Vetayases@oracle.com }
1437*12683SJimmy.Vetayases@oracle.com 
1438*12683SJimmy.Vetayases@oracle.com /*
1439*12683SJimmy.Vetayases@oracle.com  * Must be called with apix_lock held. This function can be
1440*12683SJimmy.Vetayases@oracle.com  * called from above lock level by apix_intr_redistribute().
1441*12683SJimmy.Vetayases@oracle.com  *
1442*12683SJimmy.Vetayases@oracle.com  * Arguments:
1443*12683SJimmy.Vetayases@oracle.com  *    vecp  : Vector to be rebound
1444*12683SJimmy.Vetayases@oracle.com  *    tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid.
1445*12683SJimmy.Vetayases@oracle.com  *    count : Number of continuous vectors
1446*12683SJimmy.Vetayases@oracle.com  *
1447*12683SJimmy.Vetayases@oracle.com  * Return new vector being bound to
1448*12683SJimmy.Vetayases@oracle.com  */
1449*12683SJimmy.Vetayases@oracle.com apix_vector_t *
1450*12683SJimmy.Vetayases@oracle.com apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count)
1451*12683SJimmy.Vetayases@oracle.com {
1452*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *newp, *oldp;
1453*12683SJimmy.Vetayases@oracle.com 	processorid_t oldcpu = vecp->v_cpuid;
1454*12683SJimmy.Vetayases@oracle.com 	uchar_t newvec, oldvec = vecp->v_vector;
1455*12683SJimmy.Vetayases@oracle.com 	int i;
1456*12683SJimmy.Vetayases@oracle.com 
1457*12683SJimmy.Vetayases@oracle.com 	ASSERT(LOCK_HELD(&apix_lock) && count > 0);
1458*12683SJimmy.Vetayases@oracle.com 
1459*12683SJimmy.Vetayases@oracle.com 	if (!apix_is_cpu_enabled(newcpu))
1460*12683SJimmy.Vetayases@oracle.com 		return (NULL);
1461*12683SJimmy.Vetayases@oracle.com 
1462*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_cpuid == newcpu) 	/* rebind to the same cpu */
1463*12683SJimmy.Vetayases@oracle.com 		return (vecp);
1464*12683SJimmy.Vetayases@oracle.com 
1465*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(oldcpu);
1466*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(newcpu);
1467*12683SJimmy.Vetayases@oracle.com 
1468*12683SJimmy.Vetayases@oracle.com 	/* allocate vector */
1469*12683SJimmy.Vetayases@oracle.com 	if (count == 1)
1470*12683SJimmy.Vetayases@oracle.com 		newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type);
1471*12683SJimmy.Vetayases@oracle.com 	else {
1472*12683SJimmy.Vetayases@oracle.com 		ASSERT(vecp->v_type == APIX_TYPE_MSI);
1473*12683SJimmy.Vetayases@oracle.com 		newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count,
1474*12683SJimmy.Vetayases@oracle.com 		    vecp->v_type);
1475*12683SJimmy.Vetayases@oracle.com 	}
1476*12683SJimmy.Vetayases@oracle.com 	if (newp == NULL) {
1477*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(newcpu);
1478*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
1479*12683SJimmy.Vetayases@oracle.com 		return (NULL);
1480*12683SJimmy.Vetayases@oracle.com 	}
1481*12683SJimmy.Vetayases@oracle.com 
1482*12683SJimmy.Vetayases@oracle.com 	newvec = newp->v_vector;
1483*12683SJimmy.Vetayases@oracle.com 	apix_dup_vectors(vecp, newp, count);
1484*12683SJimmy.Vetayases@oracle.com 
1485*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(newcpu);
1486*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(oldcpu);
1487*12683SJimmy.Vetayases@oracle.com 
1488*12683SJimmy.Vetayases@oracle.com 	if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {
1489*12683SJimmy.Vetayases@oracle.com 		ASSERT(count == 1);
1490*12683SJimmy.Vetayases@oracle.com 		if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) {
1491*12683SJimmy.Vetayases@oracle.com 			struct autovec *avp;
1492*12683SJimmy.Vetayases@oracle.com 			int inum;
1493*12683SJimmy.Vetayases@oracle.com 
1494*12683SJimmy.Vetayases@oracle.com 			/* undo duplication */
1495*12683SJimmy.Vetayases@oracle.com 			APIX_ENTER_CPU_LOCK(oldcpu);
1496*12683SJimmy.Vetayases@oracle.com 			APIX_ENTER_CPU_LOCK(newcpu);
1497*12683SJimmy.Vetayases@oracle.com 			for (avp = newp->v_autovect; avp != NULL;
1498*12683SJimmy.Vetayases@oracle.com 			    avp = avp->av_link) {
1499*12683SJimmy.Vetayases@oracle.com 				if (avp->av_dip != NULL) {
1500*12683SJimmy.Vetayases@oracle.com 					inum = GET_INTR_INUM(avp->av_intr_id);
1501*12683SJimmy.Vetayases@oracle.com 					apix_set_dev_map(vecp, avp->av_dip,
1502*12683SJimmy.Vetayases@oracle.com 					    inum);
1503*12683SJimmy.Vetayases@oracle.com 				}
1504*12683SJimmy.Vetayases@oracle.com 				apix_remove_av(newp, avp);
1505*12683SJimmy.Vetayases@oracle.com 			}
1506*12683SJimmy.Vetayases@oracle.com 			apix_cleanup_vector(newp);
1507*12683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(newcpu);
1508*12683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(oldcpu);
1509*12683SJimmy.Vetayases@oracle.com 			APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed "
1510*12683SJimmy.Vetayases@oracle.com 			    "interrupt 0x%x to cpu %d failed\n",
1511*12683SJimmy.Vetayases@oracle.com 			    vecp->v_inum, newcpu));
1512*12683SJimmy.Vetayases@oracle.com 			return (NULL);
1513*12683SJimmy.Vetayases@oracle.com 		}
1514*12683SJimmy.Vetayases@oracle.com 
1515*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(oldcpu);
1516*12683SJimmy.Vetayases@oracle.com 		(void) apix_obsolete_vector(vecp);
1517*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
1518*12683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt"
1519*12683SJimmy.Vetayases@oracle.com 		    " 0x%x/0x%x to 0x%x/0x%x\n",
1520*12683SJimmy.Vetayases@oracle.com 		    oldcpu, oldvec, newcpu, newvec));
1521*12683SJimmy.Vetayases@oracle.com 		return (newp);
1522*12683SJimmy.Vetayases@oracle.com 	}
1523*12683SJimmy.Vetayases@oracle.com 
1524*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
1525*12683SJimmy.Vetayases@oracle.com 		oldp = xv_vector(oldcpu, oldvec + i);
1526*12683SJimmy.Vetayases@oracle.com 		newp = xv_vector(newcpu, newvec + i);
1527*12683SJimmy.Vetayases@oracle.com 
1528*12683SJimmy.Vetayases@oracle.com 		if (newp->v_share > 0) {
1529*12683SJimmy.Vetayases@oracle.com 			APIX_SET_REBIND_INFO(oldp, newp);
1530*12683SJimmy.Vetayases@oracle.com 
1531*12683SJimmy.Vetayases@oracle.com 			apix_enable_vector(newp);
1532*12683SJimmy.Vetayases@oracle.com 
1533*12683SJimmy.Vetayases@oracle.com 			APIX_CLR_REBIND_INFO();
1534*12683SJimmy.Vetayases@oracle.com 		}
1535*12683SJimmy.Vetayases@oracle.com 
1536*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(oldcpu);
1537*12683SJimmy.Vetayases@oracle.com 		(void) apix_obsolete_vector(oldp);
1538*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
1539*12683SJimmy.Vetayases@oracle.com 	}
1540*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x "
1541*12683SJimmy.Vetayases@oracle.com 	    "to 0x%x/0x%x, count=%d\n",
1542*12683SJimmy.Vetayases@oracle.com 	    oldcpu, oldvec, newcpu, newvec, count));
1543*12683SJimmy.Vetayases@oracle.com 
1544*12683SJimmy.Vetayases@oracle.com 	return (xv_vector(newcpu, newvec));
1545*12683SJimmy.Vetayases@oracle.com }
1546*12683SJimmy.Vetayases@oracle.com 
1547*12683SJimmy.Vetayases@oracle.com /*
1548*12683SJimmy.Vetayases@oracle.com  * Senarios include:
1549*12683SJimmy.Vetayases@oracle.com  * a. add_avintr() is called before irqp initialized (legacy)
1550*12683SJimmy.Vetayases@oracle.com  * b. irqp is initialized, vector is not allocated (fixed interrupts)
1551*12683SJimmy.Vetayases@oracle.com  * c. irqp is initialized, vector is allocated (shared interrupts)
1552*12683SJimmy.Vetayases@oracle.com  */
1553*12683SJimmy.Vetayases@oracle.com apix_vector_t *
1554*12683SJimmy.Vetayases@oracle.com apix_alloc_intx(dev_info_t *dip, int inum, int irqno)
1555*12683SJimmy.Vetayases@oracle.com {
1556*12683SJimmy.Vetayases@oracle.com 	apic_irq_t *irqp;
1557*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1558*12683SJimmy.Vetayases@oracle.com 
1559*12683SJimmy.Vetayases@oracle.com 	/*
1560*12683SJimmy.Vetayases@oracle.com 	 * Allocate IRQ. Caller is later responsible for the
1561*12683SJimmy.Vetayases@oracle.com 	 * initialization
1562*12683SJimmy.Vetayases@oracle.com 	 */
1563*12683SJimmy.Vetayases@oracle.com 	mutex_enter(&airq_mutex);
1564*12683SJimmy.Vetayases@oracle.com 	if ((irqp = apic_irq_table[irqno]) == NULL) {
1565*12683SJimmy.Vetayases@oracle.com 		/* allocate irq */
1566*12683SJimmy.Vetayases@oracle.com 		irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
1567*12683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = FREE_INDEX;
1568*12683SJimmy.Vetayases@oracle.com 		apic_irq_table[irqno] = irqp;
1569*12683SJimmy.Vetayases@oracle.com 	}
1570*12683SJimmy.Vetayases@oracle.com 	if (irqp->airq_mps_intr_index == FREE_INDEX) {
1571*12683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = DEFAULT_INDEX;
1572*12683SJimmy.Vetayases@oracle.com 		irqp->airq_cpu = IRQ_UNINIT;
1573*12683SJimmy.Vetayases@oracle.com 		irqp->airq_origirq = (uchar_t)irqno;
1574*12683SJimmy.Vetayases@oracle.com 	}
1575*12683SJimmy.Vetayases@oracle.com 
1576*12683SJimmy.Vetayases@oracle.com 	mutex_exit(&airq_mutex);
1577*12683SJimmy.Vetayases@oracle.com 
1578*12683SJimmy.Vetayases@oracle.com 	/*
1579*12683SJimmy.Vetayases@oracle.com 	 * allocate vector
1580*12683SJimmy.Vetayases@oracle.com 	 */
1581*12683SJimmy.Vetayases@oracle.com 	if (irqp->airq_cpu == IRQ_UNINIT) {
1582*12683SJimmy.Vetayases@oracle.com 		uint32_t bindcpu, cpuid;
1583*12683SJimmy.Vetayases@oracle.com 
1584*12683SJimmy.Vetayases@oracle.com 		/* select cpu by system policy */
1585*12683SJimmy.Vetayases@oracle.com 		bindcpu = apix_bind_cpu(dip);
1586*12683SJimmy.Vetayases@oracle.com 		cpuid = bindcpu & ~IRQ_USER_BOUND;
1587*12683SJimmy.Vetayases@oracle.com 
1588*12683SJimmy.Vetayases@oracle.com 		/* allocate vector */
1589*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpuid);
1590*12683SJimmy.Vetayases@oracle.com 
1591*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum,
1592*12683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_FIXED)) == NULL) {
1593*12683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "No interrupt vector for irq %x",
1594*12683SJimmy.Vetayases@oracle.com 			    irqno);
1595*12683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(cpuid);
1596*12683SJimmy.Vetayases@oracle.com 			return (NULL);
1597*12683SJimmy.Vetayases@oracle.com 		}
1598*12683SJimmy.Vetayases@oracle.com 		vecp->v_inum = irqno;
1599*12683SJimmy.Vetayases@oracle.com 		vecp->v_flags |= APIX_VECT_MASKABLE;
1600*12683SJimmy.Vetayases@oracle.com 
1601*12683SJimmy.Vetayases@oracle.com 		apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector);
1602*12683SJimmy.Vetayases@oracle.com 
1603*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
1604*12683SJimmy.Vetayases@oracle.com 	} else {
1605*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
1606*12683SJimmy.Vetayases@oracle.com 		ASSERT(!IS_VECT_FREE(vecp));
1607*12683SJimmy.Vetayases@oracle.com 
1608*12683SJimmy.Vetayases@oracle.com 		if (dip != NULL)
1609*12683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(vecp, dip, inum);
1610*12683SJimmy.Vetayases@oracle.com 	}
1611*12683SJimmy.Vetayases@oracle.com 
1612*12683SJimmy.Vetayases@oracle.com 	if ((dip != NULL) &&
1613*12683SJimmy.Vetayases@oracle.com 	    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
1614*12683SJimmy.Vetayases@oracle.com 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
1615*12683SJimmy.Vetayases@oracle.com 		apix_set_dev_binding(dip, vecp->v_cpuid);
1616*12683SJimmy.Vetayases@oracle.com 
1617*12683SJimmy.Vetayases@oracle.com 	apix_dprint_vector(vecp, dip, 1);
1618*12683SJimmy.Vetayases@oracle.com 
1619*12683SJimmy.Vetayases@oracle.com 	return (vecp);
1620*12683SJimmy.Vetayases@oracle.com }
1621*12683SJimmy.Vetayases@oracle.com 
1622*12683SJimmy.Vetayases@oracle.com int
1623*12683SJimmy.Vetayases@oracle.com apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior)
1624*12683SJimmy.Vetayases@oracle.com {
1625*12683SJimmy.Vetayases@oracle.com 	int i, cap_ptr, rcount = count;
1626*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1627*12683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu, cpuid;
1628*12683SJimmy.Vetayases@oracle.com 	ushort_t msi_ctrl;
1629*12683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t handle;
1630*12683SJimmy.Vetayases@oracle.com 
1631*12683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p "
1632*12683SJimmy.Vetayases@oracle.com 	    "inum=0x%x  count=0x%x behavior=%d\n",
1633*12683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, count, behavior));
1634*12683SJimmy.Vetayases@oracle.com 
1635*12683SJimmy.Vetayases@oracle.com 	if (count > 1) {
1636*12683SJimmy.Vetayases@oracle.com 		if (behavior == DDI_INTR_ALLOC_STRICT &&
1637*12683SJimmy.Vetayases@oracle.com 		    apic_multi_msi_enable == 0)
1638*12683SJimmy.Vetayases@oracle.com 			return (0);
1639*12683SJimmy.Vetayases@oracle.com 		if (apic_multi_msi_enable == 0)
1640*12683SJimmy.Vetayases@oracle.com 			count = 1;
1641*12683SJimmy.Vetayases@oracle.com 	}
1642*12683SJimmy.Vetayases@oracle.com 
1643*12683SJimmy.Vetayases@oracle.com 	/* Check whether it supports per-vector masking */
1644*12683SJimmy.Vetayases@oracle.com 	cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
1645*12683SJimmy.Vetayases@oracle.com 	handle = i_ddi_get_pci_config_handle(dip);
1646*12683SJimmy.Vetayases@oracle.com 	msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
1647*12683SJimmy.Vetayases@oracle.com 
1648*12683SJimmy.Vetayases@oracle.com 	/* bind to cpu */
1649*12683SJimmy.Vetayases@oracle.com 	bindcpu = apix_bind_cpu(dip);
1650*12683SJimmy.Vetayases@oracle.com 	cpuid = bindcpu & ~IRQ_USER_BOUND;
1651*12683SJimmy.Vetayases@oracle.com 
1652*12683SJimmy.Vetayases@oracle.com 	/* if not ISP2, then round it down */
1653*12683SJimmy.Vetayases@oracle.com 	if (!ISP2(rcount))
1654*12683SJimmy.Vetayases@oracle.com 		rcount = 1 << (highbit(rcount) - 1);
1655*12683SJimmy.Vetayases@oracle.com 
1656*12683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
1657*12683SJimmy.Vetayases@oracle.com 	for (vecp = NULL; rcount > 0; rcount >>= 1) {
1658*12683SJimmy.Vetayases@oracle.com 		vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount,
1659*12683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_MSI);
1660*12683SJimmy.Vetayases@oracle.com 		if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT)
1661*12683SJimmy.Vetayases@oracle.com 			break;
1662*12683SJimmy.Vetayases@oracle.com 	}
1663*12683SJimmy.Vetayases@oracle.com 	for (i = 0; vecp && i < rcount; i++)
1664*12683SJimmy.Vetayases@oracle.com 		xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |=
1665*12683SJimmy.Vetayases@oracle.com 		    (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0;
1666*12683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
1667*12683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
1668*12683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(INTR, (CE_CONT,
1669*12683SJimmy.Vetayases@oracle.com 		    "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n",
1670*12683SJimmy.Vetayases@oracle.com 		    count, bindcpu));
1671*12683SJimmy.Vetayases@oracle.com 		return (0);
1672*12683SJimmy.Vetayases@oracle.com 	}
1673*12683SJimmy.Vetayases@oracle.com 
1674*12683SJimmy.Vetayases@oracle.com 	/* major to cpu binding */
1675*12683SJimmy.Vetayases@oracle.com 	if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
1676*12683SJimmy.Vetayases@oracle.com 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
1677*12683SJimmy.Vetayases@oracle.com 		apix_set_dev_binding(dip, vecp->v_cpuid);
1678*12683SJimmy.Vetayases@oracle.com 
1679*12683SJimmy.Vetayases@oracle.com 	apix_dprint_vector(vecp, dip, rcount);
1680*12683SJimmy.Vetayases@oracle.com 
1681*12683SJimmy.Vetayases@oracle.com 	return (rcount);
1682*12683SJimmy.Vetayases@oracle.com }
1683*12683SJimmy.Vetayases@oracle.com 
1684*12683SJimmy.Vetayases@oracle.com int
1685*12683SJimmy.Vetayases@oracle.com apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior)
1686*12683SJimmy.Vetayases@oracle.com {
1687*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1688*12683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu, cpuid;
1689*12683SJimmy.Vetayases@oracle.com 	int i;
1690*12683SJimmy.Vetayases@oracle.com 
1691*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
1692*12683SJimmy.Vetayases@oracle.com 		/* select cpu by system policy */
1693*12683SJimmy.Vetayases@oracle.com 		bindcpu = apix_bind_cpu(dip);
1694*12683SJimmy.Vetayases@oracle.com 		cpuid = bindcpu & ~IRQ_USER_BOUND;
1695*12683SJimmy.Vetayases@oracle.com 
1696*12683SJimmy.Vetayases@oracle.com 		/* allocate vector */
1697*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpuid);
1698*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i,
1699*12683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_MSIX)) == NULL) {
1700*12683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(cpuid);
1701*12683SJimmy.Vetayases@oracle.com 			APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: "
1702*12683SJimmy.Vetayases@oracle.com 			    "allocate msix for device dip=%p, inum=%d on"
1703*12683SJimmy.Vetayases@oracle.com 			    " cpu %d failed", (void *)dip, inum + i, bindcpu));
1704*12683SJimmy.Vetayases@oracle.com 			break;
1705*12683SJimmy.Vetayases@oracle.com 		}
1706*12683SJimmy.Vetayases@oracle.com 		vecp->v_flags |= APIX_VECT_MASKABLE;
1707*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
1708*12683SJimmy.Vetayases@oracle.com 
1709*12683SJimmy.Vetayases@oracle.com 		/* major to cpu mapping */
1710*12683SJimmy.Vetayases@oracle.com 		if ((i == 0) &&
1711*12683SJimmy.Vetayases@oracle.com 		    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
1712*12683SJimmy.Vetayases@oracle.com 		    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
1713*12683SJimmy.Vetayases@oracle.com 			apix_set_dev_binding(dip, vecp->v_cpuid);
1714*12683SJimmy.Vetayases@oracle.com 
1715*12683SJimmy.Vetayases@oracle.com 		apix_dprint_vector(vecp, dip, 1);
1716*12683SJimmy.Vetayases@oracle.com 	}
1717*12683SJimmy.Vetayases@oracle.com 
1718*12683SJimmy.Vetayases@oracle.com 	if (i < count && behavior == DDI_INTR_ALLOC_STRICT) {
1719*12683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: "
1720*12683SJimmy.Vetayases@oracle.com 		    "strictly allocate %d vectors failed, got %d\n",
1721*12683SJimmy.Vetayases@oracle.com 		    count, i));
1722*12683SJimmy.Vetayases@oracle.com 		apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX);
1723*12683SJimmy.Vetayases@oracle.com 		i = 0;
1724*12683SJimmy.Vetayases@oracle.com 	}
1725*12683SJimmy.Vetayases@oracle.com 
1726*12683SJimmy.Vetayases@oracle.com 	return (i);
1727*12683SJimmy.Vetayases@oracle.com }
1728*12683SJimmy.Vetayases@oracle.com 
1729*12683SJimmy.Vetayases@oracle.com /*
1730*12683SJimmy.Vetayases@oracle.com  * A rollback free for vectors allocated by apix_alloc_xxx().
1731*12683SJimmy.Vetayases@oracle.com  */
1732*12683SJimmy.Vetayases@oracle.com void
1733*12683SJimmy.Vetayases@oracle.com apix_free_vectors(dev_info_t *dip, int inum, int count, int type)
1734*12683SJimmy.Vetayases@oracle.com {
1735*12683SJimmy.Vetayases@oracle.com 	int i, cpuid;
1736*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1737*12683SJimmy.Vetayases@oracle.com 
1738*12683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x "
1739*12683SJimmy.Vetayases@oracle.com 	    "count: %x type: %x\n",
1740*12683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, count, type));
1741*12683SJimmy.Vetayases@oracle.com 
1742*12683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
1743*12683SJimmy.Vetayases@oracle.com 
1744*12683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++, inum++) {
1745*12683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) {
1746*12683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
1747*12683SJimmy.Vetayases@oracle.com 			DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
1748*12683SJimmy.Vetayases@oracle.com 			    "dip=0x%p inum=0x%x type=0x%x apix_find_intr() "
1749*12683SJimmy.Vetayases@oracle.com 			    "failed\n", (void *)dip, inum, type));
1750*12683SJimmy.Vetayases@oracle.com 			continue;
1751*12683SJimmy.Vetayases@oracle.com 		}
1752*12683SJimmy.Vetayases@oracle.com 
1753*12683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(vecp->v_cpuid);
1754*12683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
1755*12683SJimmy.Vetayases@oracle.com 
1756*12683SJimmy.Vetayases@oracle.com 		DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
1757*12683SJimmy.Vetayases@oracle.com 		    "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n",
1758*12683SJimmy.Vetayases@oracle.com 		    (void *)dip, inum, type, vecp->v_vector, vecp->v_share));
1759*12683SJimmy.Vetayases@oracle.com 
1760*12683SJimmy.Vetayases@oracle.com 		/* tear down device interrupt to vector mapping */
1761*12683SJimmy.Vetayases@oracle.com 		apix_clear_dev_map(dip, inum, type);
1762*12683SJimmy.Vetayases@oracle.com 
1763*12683SJimmy.Vetayases@oracle.com 		if (vecp->v_type == APIX_TYPE_FIXED) {
1764*12683SJimmy.Vetayases@oracle.com 			if (vecp->v_share > 0) {	/* share IRQ line */
1765*12683SJimmy.Vetayases@oracle.com 				APIX_LEAVE_CPU_LOCK(cpuid);
1766*12683SJimmy.Vetayases@oracle.com 				continue;
1767*12683SJimmy.Vetayases@oracle.com 			}
1768*12683SJimmy.Vetayases@oracle.com 
1769*12683SJimmy.Vetayases@oracle.com 			/* Free apic_irq_table entry */
1770*12683SJimmy.Vetayases@oracle.com 			apix_intx_free(vecp->v_inum);
1771*12683SJimmy.Vetayases@oracle.com 		}
1772*12683SJimmy.Vetayases@oracle.com 
1773*12683SJimmy.Vetayases@oracle.com 		/* free vector */
1774*12683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(vecp);
1775*12683SJimmy.Vetayases@oracle.com 
1776*12683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
1777*12683SJimmy.Vetayases@oracle.com 	}
1778*12683SJimmy.Vetayases@oracle.com 
1779*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
1780*12683SJimmy.Vetayases@oracle.com }
1781*12683SJimmy.Vetayases@oracle.com 
1782*12683SJimmy.Vetayases@oracle.com /*
1783*12683SJimmy.Vetayases@oracle.com  * Must be called with apix_lock held
1784*12683SJimmy.Vetayases@oracle.com  */
1785*12683SJimmy.Vetayases@oracle.com apix_vector_t *
1786*12683SJimmy.Vetayases@oracle.com apix_setup_io_intr(apix_vector_t *vecp)
1787*12683SJimmy.Vetayases@oracle.com {
1788*12683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu;
1789*12683SJimmy.Vetayases@oracle.com 	int ret;
1790*12683SJimmy.Vetayases@oracle.com 
1791*12683SJimmy.Vetayases@oracle.com 	ASSERT(LOCK_HELD(&apix_lock));
1792*12683SJimmy.Vetayases@oracle.com 
1793*12683SJimmy.Vetayases@oracle.com 	/*
1794*12683SJimmy.Vetayases@oracle.com 	 * Interrupts are enabled on the CPU, programme IOAPIC RDT
1795*12683SJimmy.Vetayases@oracle.com 	 * entry or MSI/X address/data to enable the interrupt.
1796*12683SJimmy.Vetayases@oracle.com 	 */
1797*12683SJimmy.Vetayases@oracle.com 	if (apix_is_cpu_enabled(vecp->v_cpuid)) {
1798*12683SJimmy.Vetayases@oracle.com 		apix_enable_vector(vecp);
1799*12683SJimmy.Vetayases@oracle.com 		return (vecp);
1800*12683SJimmy.Vetayases@oracle.com 	}
1801*12683SJimmy.Vetayases@oracle.com 
1802*12683SJimmy.Vetayases@oracle.com 	/*
1803*12683SJimmy.Vetayases@oracle.com 	 * CPU is not up or interrupts are disabled. Fall back to the
1804*12683SJimmy.Vetayases@oracle.com 	 * first avialable CPU.
1805*12683SJimmy.Vetayases@oracle.com 	 */
1806*12683SJimmy.Vetayases@oracle.com 	bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE);
1807*12683SJimmy.Vetayases@oracle.com 
1808*12683SJimmy.Vetayases@oracle.com 	if (vecp->v_type == APIX_TYPE_MSI)
1809*12683SJimmy.Vetayases@oracle.com 		return (apix_grp_set_cpu(vecp, bindcpu, &ret));
1810*12683SJimmy.Vetayases@oracle.com 
1811*12683SJimmy.Vetayases@oracle.com 	return (apix_set_cpu(vecp, bindcpu, &ret));
1812*12683SJimmy.Vetayases@oracle.com }
1813*12683SJimmy.Vetayases@oracle.com 
1814*12683SJimmy.Vetayases@oracle.com /*
1815*12683SJimmy.Vetayases@oracle.com  * For interrupts which call add_avintr() before apic is initialized.
1816*12683SJimmy.Vetayases@oracle.com  * ioapix_setup_intr() will
1817*12683SJimmy.Vetayases@oracle.com  *   - allocate vector
1818*12683SJimmy.Vetayases@oracle.com  *   - copy over ISR
1819*12683SJimmy.Vetayases@oracle.com  */
1820*12683SJimmy.Vetayases@oracle.com static void
1821*12683SJimmy.Vetayases@oracle.com ioapix_setup_intr(int irqno, iflag_t *flagp)
1822*12683SJimmy.Vetayases@oracle.com {
1823*12683SJimmy.Vetayases@oracle.com 	extern struct av_head autovect[];
1824*12683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
1825*12683SJimmy.Vetayases@oracle.com 	apic_irq_t *irqp;
1826*12683SJimmy.Vetayases@oracle.com 	uchar_t ioapicindex, ipin;
1827*12683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
1828*12683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
1829*12683SJimmy.Vetayases@oracle.com 
1830*12683SJimmy.Vetayases@oracle.com 	irqp = apic_irq_table[irqno];
1831*12683SJimmy.Vetayases@oracle.com 	ioapicindex = acpi_find_ioapic(irqno);
1832*12683SJimmy.Vetayases@oracle.com 	ASSERT(ioapicindex != 0xFF);
1833*12683SJimmy.Vetayases@oracle.com 	ipin = irqno - apic_io_vectbase[ioapicindex];
1834*12683SJimmy.Vetayases@oracle.com 
1835*12683SJimmy.Vetayases@oracle.com 	if ((irqp != NULL) && (irqp->airq_mps_intr_index == ACPI_INDEX)) {
1836*12683SJimmy.Vetayases@oracle.com 		ASSERT(irqp->airq_intin_no == ipin &&
1837*12683SJimmy.Vetayases@oracle.com 		    irqp->airq_ioapicindex == ioapicindex);
1838*12683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
1839*12683SJimmy.Vetayases@oracle.com 		ASSERT(!IS_VECT_FREE(vecp));
1840*12683SJimmy.Vetayases@oracle.com 	} else {
1841*12683SJimmy.Vetayases@oracle.com 		vecp = apix_alloc_intx(NULL, 0, irqno);
1842*12683SJimmy.Vetayases@oracle.com 
1843*12683SJimmy.Vetayases@oracle.com 		irqp = apic_irq_table[irqno];
1844*12683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = ACPI_INDEX;
1845*12683SJimmy.Vetayases@oracle.com 		irqp->airq_ioapicindex = ioapicindex;
1846*12683SJimmy.Vetayases@oracle.com 		irqp->airq_intin_no = ipin;
1847*12683SJimmy.Vetayases@oracle.com 		irqp->airq_iflag = *flagp;
1848*12683SJimmy.Vetayases@oracle.com 		irqp->airq_share++;
1849*12683SJimmy.Vetayases@oracle.com 		apic_record_rdt_entry(irqp, irqno);
1850*12683SJimmy.Vetayases@oracle.com 	}
1851*12683SJimmy.Vetayases@oracle.com 
1852*12683SJimmy.Vetayases@oracle.com 	/* copy over autovect */
1853*12683SJimmy.Vetayases@oracle.com 	for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link)
1854*12683SJimmy.Vetayases@oracle.com 		apix_insert_av(vecp, avp->av_intr_id, avp->av_vector,
1855*12683SJimmy.Vetayases@oracle.com 		    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
1856*12683SJimmy.Vetayases@oracle.com 		    avp->av_prilevel, avp->av_dip);
1857*12683SJimmy.Vetayases@oracle.com 
1858*12683SJimmy.Vetayases@oracle.com 	/* Program I/O APIC */
1859*12683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
1860*12683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
1861*12683SJimmy.Vetayases@oracle.com 
1862*12683SJimmy.Vetayases@oracle.com 	(void) apix_setup_io_intr(vecp);
1863*12683SJimmy.Vetayases@oracle.com 
1864*12683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
1865*12683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
1866*12683SJimmy.Vetayases@oracle.com 
1867*12683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x "
1868*12683SJimmy.Vetayases@oracle.com 	    "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n",
1869*12683SJimmy.Vetayases@oracle.com 	    irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector));
1870*12683SJimmy.Vetayases@oracle.com }
1871*12683SJimmy.Vetayases@oracle.com 
1872*12683SJimmy.Vetayases@oracle.com void
1873*12683SJimmy.Vetayases@oracle.com ioapix_init_intr(int mask_apic)
1874*12683SJimmy.Vetayases@oracle.com {
1875*12683SJimmy.Vetayases@oracle.com 	int ioapicindex;
1876*12683SJimmy.Vetayases@oracle.com 	int i, j;
1877*12683SJimmy.Vetayases@oracle.com 
1878*12683SJimmy.Vetayases@oracle.com 	/* mask interrupt vectors */
1879*12683SJimmy.Vetayases@oracle.com 	for (j = 0; j < apic_io_max && mask_apic; j++) {
1880*12683SJimmy.Vetayases@oracle.com 		int intin_max;
1881*12683SJimmy.Vetayases@oracle.com 
1882*12683SJimmy.Vetayases@oracle.com 		ioapicindex = j;
1883*12683SJimmy.Vetayases@oracle.com 		/* Bits 23-16 define the maximum redirection entries */
1884*12683SJimmy.Vetayases@oracle.com 		intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16)
1885*12683SJimmy.Vetayases@oracle.com 		    & 0xff;
1886*12683SJimmy.Vetayases@oracle.com 		for (i = 0; i <= intin_max; i++)
1887*12683SJimmy.Vetayases@oracle.com 			ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i,
1888*12683SJimmy.Vetayases@oracle.com 			    AV_MASK);
1889*12683SJimmy.Vetayases@oracle.com 	}
1890*12683SJimmy.Vetayases@oracle.com 
1891*12683SJimmy.Vetayases@oracle.com 	/*
1892*12683SJimmy.Vetayases@oracle.com 	 * Hack alert: deal with ACPI SCI interrupt chicken/egg here
1893*12683SJimmy.Vetayases@oracle.com 	 */
1894*12683SJimmy.Vetayases@oracle.com 	if (apic_sci_vect > 0)
1895*12683SJimmy.Vetayases@oracle.com 		ioapix_setup_intr(apic_sci_vect, &apic_sci_flags);
1896*12683SJimmy.Vetayases@oracle.com 
1897*12683SJimmy.Vetayases@oracle.com 	/*
1898*12683SJimmy.Vetayases@oracle.com 	 * Hack alert: deal with ACPI HPET interrupt chicken/egg here.
1899*12683SJimmy.Vetayases@oracle.com 	 */
1900*12683SJimmy.Vetayases@oracle.com 	if (apic_hpet_vect > 0)
1901*12683SJimmy.Vetayases@oracle.com 		ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags);
1902*12683SJimmy.Vetayases@oracle.com }
1903