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