xref: /onnv-gate/usr/src/uts/i86pc/io/apix/apix_utils.c (revision 12822:0bbdeb5a954e)
112683SJimmy.Vetayases@oracle.com /*
212683SJimmy.Vetayases@oracle.com  * CDDL HEADER START
312683SJimmy.Vetayases@oracle.com  *
412683SJimmy.Vetayases@oracle.com  * The contents of this file are subject to the terms of the
512683SJimmy.Vetayases@oracle.com  * Common Development and Distribution License (the "License").
612683SJimmy.Vetayases@oracle.com  * You may not use this file except in compliance with the License.
712683SJimmy.Vetayases@oracle.com  *
812683SJimmy.Vetayases@oracle.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912683SJimmy.Vetayases@oracle.com  * or http://www.opensolaris.org/os/licensing.
1012683SJimmy.Vetayases@oracle.com  * See the License for the specific language governing permissions
1112683SJimmy.Vetayases@oracle.com  * and limitations under the License.
1212683SJimmy.Vetayases@oracle.com  *
1312683SJimmy.Vetayases@oracle.com  * When distributing Covered Code, include this CDDL HEADER in each
1412683SJimmy.Vetayases@oracle.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512683SJimmy.Vetayases@oracle.com  * If applicable, add the following below this CDDL HEADER, with the
1612683SJimmy.Vetayases@oracle.com  * fields enclosed by brackets "[]" replaced with your own identifying
1712683SJimmy.Vetayases@oracle.com  * information: Portions Copyright [yyyy] [name of copyright owner]
1812683SJimmy.Vetayases@oracle.com  *
1912683SJimmy.Vetayases@oracle.com  * CDDL HEADER END
2012683SJimmy.Vetayases@oracle.com  */
2112683SJimmy.Vetayases@oracle.com 
2212683SJimmy.Vetayases@oracle.com /*
2312683SJimmy.Vetayases@oracle.com  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2412683SJimmy.Vetayases@oracle.com  */
2512683SJimmy.Vetayases@oracle.com /*
2612683SJimmy.Vetayases@oracle.com  * Copyright (c) 2010, Intel Corporation.
2712683SJimmy.Vetayases@oracle.com  * All rights reserved.
2812683SJimmy.Vetayases@oracle.com  */
2912683SJimmy.Vetayases@oracle.com 
3012683SJimmy.Vetayases@oracle.com #include <sys/processor.h>
3112683SJimmy.Vetayases@oracle.com #include <sys/time.h>
3212683SJimmy.Vetayases@oracle.com #include <sys/psm.h>
3312683SJimmy.Vetayases@oracle.com #include <sys/smp_impldefs.h>
3412683SJimmy.Vetayases@oracle.com #include <sys/cram.h>
3512683SJimmy.Vetayases@oracle.com #include <sys/acpi/acpi.h>
3612683SJimmy.Vetayases@oracle.com #include <sys/acpica.h>
3712683SJimmy.Vetayases@oracle.com #include <sys/psm_common.h>
3812683SJimmy.Vetayases@oracle.com #include <sys/pit.h>
3912683SJimmy.Vetayases@oracle.com #include <sys/ddi.h>
4012683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h>
4112683SJimmy.Vetayases@oracle.com #include <sys/ddi_impldefs.h>
4212683SJimmy.Vetayases@oracle.com #include <sys/pci.h>
4312683SJimmy.Vetayases@oracle.com #include <sys/promif.h>
4412683SJimmy.Vetayases@oracle.com #include <sys/x86_archext.h>
4512683SJimmy.Vetayases@oracle.com #include <sys/cpc_impl.h>
4612683SJimmy.Vetayases@oracle.com #include <sys/uadmin.h>
4712683SJimmy.Vetayases@oracle.com #include <sys/panic.h>
4812683SJimmy.Vetayases@oracle.com #include <sys/debug.h>
4912683SJimmy.Vetayases@oracle.com #include <sys/archsystm.h>
5012683SJimmy.Vetayases@oracle.com #include <sys/trap.h>
5112683SJimmy.Vetayases@oracle.com #include <sys/machsystm.h>
5212683SJimmy.Vetayases@oracle.com #include <sys/sysmacros.h>
5312683SJimmy.Vetayases@oracle.com #include <sys/cpuvar.h>
5412683SJimmy.Vetayases@oracle.com #include <sys/rm_platter.h>
5512683SJimmy.Vetayases@oracle.com #include <sys/privregs.h>
5612683SJimmy.Vetayases@oracle.com #include <sys/note.h>
5712683SJimmy.Vetayases@oracle.com #include <sys/pci_intr_lib.h>
5812683SJimmy.Vetayases@oracle.com #include <sys/spl.h>
5912683SJimmy.Vetayases@oracle.com #include <sys/clock.h>
6012683SJimmy.Vetayases@oracle.com #include <sys/dditypes.h>
6112683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h>
6212683SJimmy.Vetayases@oracle.com #include <sys/x_call.h>
6312683SJimmy.Vetayases@oracle.com #include <sys/reboot.h>
6412683SJimmy.Vetayases@oracle.com #include <sys/apix.h>
6512683SJimmy.Vetayases@oracle.com 
6612683SJimmy.Vetayases@oracle.com static int apix_get_avail_vector_oncpu(uint32_t, int, int);
6712683SJimmy.Vetayases@oracle.com static apix_vector_t *apix_init_vector(processorid_t, uchar_t);
6812683SJimmy.Vetayases@oracle.com static void apix_cleanup_vector(apix_vector_t *);
6912683SJimmy.Vetayases@oracle.com static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t,
7012683SJimmy.Vetayases@oracle.com     uint64_t *, int, dev_info_t *);
7112683SJimmy.Vetayases@oracle.com static void apix_remove_av(apix_vector_t *, struct autovec *);
7212683SJimmy.Vetayases@oracle.com static void apix_clear_dev_map(dev_info_t *, int, int);
7312683SJimmy.Vetayases@oracle.com static boolean_t apix_is_cpu_enabled(processorid_t);
7412683SJimmy.Vetayases@oracle.com static void apix_wait_till_seen(processorid_t, int);
7512683SJimmy.Vetayases@oracle.com 
7612683SJimmy.Vetayases@oracle.com #define	GET_INTR_INUM(ihdlp)		\
7712683SJimmy.Vetayases@oracle.com 	(((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0)
7812683SJimmy.Vetayases@oracle.com 
7912683SJimmy.Vetayases@oracle.com apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL};
8012683SJimmy.Vetayases@oracle.com 
8112683SJimmy.Vetayases@oracle.com /*
8212683SJimmy.Vetayases@oracle.com  * Allocate IPI
8312683SJimmy.Vetayases@oracle.com  *
8412683SJimmy.Vetayases@oracle.com  * Return vector number or 0 on error
8512683SJimmy.Vetayases@oracle.com  */
8612683SJimmy.Vetayases@oracle.com uchar_t
apix_alloc_ipi(int ipl)8712683SJimmy.Vetayases@oracle.com apix_alloc_ipi(int ipl)
8812683SJimmy.Vetayases@oracle.com {
8912683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
9012683SJimmy.Vetayases@oracle.com 	uchar_t vector;
9112683SJimmy.Vetayases@oracle.com 	int cpun;
9212683SJimmy.Vetayases@oracle.com 	int nproc;
9312683SJimmy.Vetayases@oracle.com 
9412683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(0);
9512683SJimmy.Vetayases@oracle.com 
9612683SJimmy.Vetayases@oracle.com 	vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX);
9712683SJimmy.Vetayases@oracle.com 	if (vector == 0) {
9812683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(0);
9912683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "apix: no available IPI\n");
10012683SJimmy.Vetayases@oracle.com 		apic_error |= APIC_ERR_GET_IPIVECT_FAIL;
10112683SJimmy.Vetayases@oracle.com 		return (0);
10212683SJimmy.Vetayases@oracle.com 	}
10312683SJimmy.Vetayases@oracle.com 
10412683SJimmy.Vetayases@oracle.com 	nproc = max(apic_nproc, apic_max_nproc);
10512683SJimmy.Vetayases@oracle.com 	for (cpun = 0; cpun < nproc; cpun++) {
10612683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpun, vector);
10712683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
10812683SJimmy.Vetayases@oracle.com 			vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
10912683SJimmy.Vetayases@oracle.com 			if (vecp == NULL) {
11012683SJimmy.Vetayases@oracle.com 				cmn_err(CE_WARN, "apix: No memory for ipi");
11112683SJimmy.Vetayases@oracle.com 				goto fail;
11212683SJimmy.Vetayases@oracle.com 			}
11312683SJimmy.Vetayases@oracle.com 			xv_vector(cpun, vector) = vecp;
11412683SJimmy.Vetayases@oracle.com 		}
11512683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_ALLOCED;
11612683SJimmy.Vetayases@oracle.com 		vecp->v_type = APIX_TYPE_IPI;
11712683SJimmy.Vetayases@oracle.com 		vecp->v_cpuid = vecp->v_bound_cpuid = cpun;
11812683SJimmy.Vetayases@oracle.com 		vecp->v_vector = vector;
11912683SJimmy.Vetayases@oracle.com 		vecp->v_pri = ipl;
12012683SJimmy.Vetayases@oracle.com 	}
12112683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(0);
12212683SJimmy.Vetayases@oracle.com 	return (vector);
12312683SJimmy.Vetayases@oracle.com 
12412683SJimmy.Vetayases@oracle.com fail:
12512683SJimmy.Vetayases@oracle.com 	while (--cpun >= 0)
12612683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(xv_vector(cpun, vector));
12712683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(0);
12812683SJimmy.Vetayases@oracle.com 	return (0);
12912683SJimmy.Vetayases@oracle.com }
13012683SJimmy.Vetayases@oracle.com 
13112683SJimmy.Vetayases@oracle.com /*
13212683SJimmy.Vetayases@oracle.com  * Add IPI service routine
13312683SJimmy.Vetayases@oracle.com  */
13412683SJimmy.Vetayases@oracle.com static int
apix_add_ipi(int ipl,avfunc xxintr,char * name,int vector,caddr_t arg1,caddr_t arg2)13512683SJimmy.Vetayases@oracle.com apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector,
13612683SJimmy.Vetayases@oracle.com     caddr_t arg1, caddr_t arg2)
13712683SJimmy.Vetayases@oracle.com {
13812683SJimmy.Vetayases@oracle.com 	int cpun;
13912683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
14012683SJimmy.Vetayases@oracle.com 	int nproc;
14112683SJimmy.Vetayases@oracle.com 
14212683SJimmy.Vetayases@oracle.com 	ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX);
14312683SJimmy.Vetayases@oracle.com 
14412683SJimmy.Vetayases@oracle.com 	nproc = max(apic_nproc, apic_max_nproc);
14512683SJimmy.Vetayases@oracle.com 	for (cpun = 0; cpun < nproc; cpun++) {
14612683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpun);
14712683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpun, vector);
14812683SJimmy.Vetayases@oracle.com 		apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL);
14912683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_ENABLED;
15012683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpun);
15112683SJimmy.Vetayases@oracle.com 	}
15212683SJimmy.Vetayases@oracle.com 
15312683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x "
15412683SJimmy.Vetayases@oracle.com 	    "ipl %x\n", name, vector, ipl));
15512683SJimmy.Vetayases@oracle.com 
15612683SJimmy.Vetayases@oracle.com 	return (1);
15712683SJimmy.Vetayases@oracle.com }
15812683SJimmy.Vetayases@oracle.com 
15912683SJimmy.Vetayases@oracle.com /*
16012683SJimmy.Vetayases@oracle.com  * Find and return first free vector in range (start, end)
16112683SJimmy.Vetayases@oracle.com  */
16212683SJimmy.Vetayases@oracle.com static int
apix_get_avail_vector_oncpu(uint32_t cpuid,int start,int end)16312683SJimmy.Vetayases@oracle.com apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end)
16412683SJimmy.Vetayases@oracle.com {
16512683SJimmy.Vetayases@oracle.com 	int i;
16612683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
16712683SJimmy.Vetayases@oracle.com 
16812683SJimmy.Vetayases@oracle.com 	for (i = start; i <= end; i++) {
16912683SJimmy.Vetayases@oracle.com 		if (APIC_CHECK_RESERVE_VECTORS(i))
17012683SJimmy.Vetayases@oracle.com 			continue;
17112683SJimmy.Vetayases@oracle.com 		if (IS_VECT_FREE(apixp->x_vectbl[i]))
17212683SJimmy.Vetayases@oracle.com 			return (i);
17312683SJimmy.Vetayases@oracle.com 	}
17412683SJimmy.Vetayases@oracle.com 
17512683SJimmy.Vetayases@oracle.com 	return (0);
17612683SJimmy.Vetayases@oracle.com }
17712683SJimmy.Vetayases@oracle.com 
17812683SJimmy.Vetayases@oracle.com /*
17912683SJimmy.Vetayases@oracle.com  * Allocate a vector on specified cpu
18012683SJimmy.Vetayases@oracle.com  *
18112683SJimmy.Vetayases@oracle.com  * Return NULL on error
18212683SJimmy.Vetayases@oracle.com  */
18312683SJimmy.Vetayases@oracle.com static apix_vector_t *
apix_alloc_vector_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int type)18412683SJimmy.Vetayases@oracle.com apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type)
18512683SJimmy.Vetayases@oracle.com {
18612683SJimmy.Vetayases@oracle.com 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
18712683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
18812683SJimmy.Vetayases@oracle.com 	int vector;
18912683SJimmy.Vetayases@oracle.com 
19012683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
19112683SJimmy.Vetayases@oracle.com 
19212683SJimmy.Vetayases@oracle.com 	/* find free vector */
19312683SJimmy.Vetayases@oracle.com 	vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN,
19412683SJimmy.Vetayases@oracle.com 	    APIX_AVINTR_MAX);
19512683SJimmy.Vetayases@oracle.com 	if (vector == 0)
19612683SJimmy.Vetayases@oracle.com 		return (NULL);
19712683SJimmy.Vetayases@oracle.com 
19812683SJimmy.Vetayases@oracle.com 	vecp = apix_init_vector(tocpu, vector);
19912683SJimmy.Vetayases@oracle.com 	vecp->v_type = (ushort_t)type;
20012683SJimmy.Vetayases@oracle.com 	vecp->v_inum = inum;
20112683SJimmy.Vetayases@oracle.com 	vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
20212683SJimmy.Vetayases@oracle.com 
20312683SJimmy.Vetayases@oracle.com 	if (dip != NULL)
20412683SJimmy.Vetayases@oracle.com 		apix_set_dev_map(vecp, dip, inum);
20512683SJimmy.Vetayases@oracle.com 
20612683SJimmy.Vetayases@oracle.com 	return (vecp);
20712683SJimmy.Vetayases@oracle.com }
20812683SJimmy.Vetayases@oracle.com 
20912683SJimmy.Vetayases@oracle.com /*
21012683SJimmy.Vetayases@oracle.com  * Allocates "count" contiguous MSI vectors starting at the proper alignment.
21112683SJimmy.Vetayases@oracle.com  * Caller needs to make sure that count has to be power of 2 and should not
21212683SJimmy.Vetayases@oracle.com  * be < 1.
21312683SJimmy.Vetayases@oracle.com  *
21412683SJimmy.Vetayases@oracle.com  * Return first vector number
21512683SJimmy.Vetayases@oracle.com  */
21612683SJimmy.Vetayases@oracle.com apix_vector_t *
apix_alloc_nvectors_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int count,int type)21712683SJimmy.Vetayases@oracle.com apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum,
21812683SJimmy.Vetayases@oracle.com     int count, int type)
21912683SJimmy.Vetayases@oracle.com {
22012683SJimmy.Vetayases@oracle.com 	int i, msibits, start = 0, navail = 0;
22112683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp, *startp = NULL;
22212683SJimmy.Vetayases@oracle.com 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
22312683SJimmy.Vetayases@oracle.com 	uint_t flags;
22412683SJimmy.Vetayases@oracle.com 
22512683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
22612683SJimmy.Vetayases@oracle.com 
22712683SJimmy.Vetayases@oracle.com 	/*
22812683SJimmy.Vetayases@oracle.com 	 * msibits is the no. of lower order message data bits for the
22912683SJimmy.Vetayases@oracle.com 	 * allocated MSI vectors and is used to calculate the aligned
23012683SJimmy.Vetayases@oracle.com 	 * starting vector
23112683SJimmy.Vetayases@oracle.com 	 */
23212683SJimmy.Vetayases@oracle.com 	msibits = count - 1;
23312683SJimmy.Vetayases@oracle.com 
23412683SJimmy.Vetayases@oracle.com 	/* It has to be contiguous */
23512683SJimmy.Vetayases@oracle.com 	for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) {
23612683SJimmy.Vetayases@oracle.com 		if (!IS_VECT_FREE(xv_vector(tocpu, i)))
23712683SJimmy.Vetayases@oracle.com 			continue;
23812683SJimmy.Vetayases@oracle.com 
23912683SJimmy.Vetayases@oracle.com 		/*
24012683SJimmy.Vetayases@oracle.com 		 * starting vector has to be aligned accordingly for
24112683SJimmy.Vetayases@oracle.com 		 * multiple MSIs
24212683SJimmy.Vetayases@oracle.com 		 */
24312683SJimmy.Vetayases@oracle.com 		if (msibits)
24412683SJimmy.Vetayases@oracle.com 			i = (i + msibits) & ~msibits;
24512683SJimmy.Vetayases@oracle.com 
24612683SJimmy.Vetayases@oracle.com 		for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) {
24712683SJimmy.Vetayases@oracle.com 			if (!IS_VECT_FREE(xv_vector(tocpu, i)))
24812683SJimmy.Vetayases@oracle.com 				break;
24912683SJimmy.Vetayases@oracle.com 			if (APIC_CHECK_RESERVE_VECTORS(i))
25012683SJimmy.Vetayases@oracle.com 				break;
25112683SJimmy.Vetayases@oracle.com 			if (++navail == count)
25212683SJimmy.Vetayases@oracle.com 				goto done;
25312683SJimmy.Vetayases@oracle.com 		}
25412683SJimmy.Vetayases@oracle.com 	}
25512683SJimmy.Vetayases@oracle.com 
25612683SJimmy.Vetayases@oracle.com 	return (NULL);
25712683SJimmy.Vetayases@oracle.com 
25812683SJimmy.Vetayases@oracle.com done:
25912683SJimmy.Vetayases@oracle.com 	flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
26012683SJimmy.Vetayases@oracle.com 
26112683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
26212683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_init_vector(tocpu, start + i)) == NULL)
26312683SJimmy.Vetayases@oracle.com 			goto fail;
26412683SJimmy.Vetayases@oracle.com 
26512683SJimmy.Vetayases@oracle.com 		vecp->v_type = (ushort_t)type;
26612683SJimmy.Vetayases@oracle.com 		vecp->v_inum = inum + i;
26712683SJimmy.Vetayases@oracle.com 		vecp->v_flags = flags;
26812683SJimmy.Vetayases@oracle.com 
26912683SJimmy.Vetayases@oracle.com 		if (dip != NULL)
27012683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(vecp, dip, inum + i);
27112683SJimmy.Vetayases@oracle.com 
27212683SJimmy.Vetayases@oracle.com 		if (i == 0)
27312683SJimmy.Vetayases@oracle.com 			startp = vecp;
27412683SJimmy.Vetayases@oracle.com 	}
27512683SJimmy.Vetayases@oracle.com 
27612683SJimmy.Vetayases@oracle.com 	return (startp);
27712683SJimmy.Vetayases@oracle.com 
27812683SJimmy.Vetayases@oracle.com fail:
27912683SJimmy.Vetayases@oracle.com 	while (i-- > 0) {	/* Free allocated vectors */
28012683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(tocpu, start + i);
28112683SJimmy.Vetayases@oracle.com 		apix_clear_dev_map(dip, inum + i, type);
28212683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(vecp);
28312683SJimmy.Vetayases@oracle.com 	}
28412683SJimmy.Vetayases@oracle.com 	return (NULL);
28512683SJimmy.Vetayases@oracle.com }
28612683SJimmy.Vetayases@oracle.com 
28712683SJimmy.Vetayases@oracle.com #define	APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\
28812683SJimmy.Vetayases@oracle.com do {\
28912683SJimmy.Vetayases@oracle.com 	if ((_ctrl) & PCI_MSI_64BIT_MASK)\
29012683SJimmy.Vetayases@oracle.com 		pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\
29112683SJimmy.Vetayases@oracle.com 	else\
29212683SJimmy.Vetayases@oracle.com 		pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\
29312683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0)
29412683SJimmy.Vetayases@oracle.com 
29512683SJimmy.Vetayases@oracle.com static void
apix_pci_msi_enable_vector(apix_vector_t * vecp,dev_info_t * dip,int type,int inum,int count,uchar_t vector,int target_apic_id)29612683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type,
29712683SJimmy.Vetayases@oracle.com     int inum, int count, uchar_t vector, int target_apic_id)
29812683SJimmy.Vetayases@oracle.com {
29912683SJimmy.Vetayases@oracle.com 	uint64_t		msi_addr, msi_data;
30012683SJimmy.Vetayases@oracle.com 	ushort_t		msi_ctrl;
30112683SJimmy.Vetayases@oracle.com 	int			i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
30212683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
30312683SJimmy.Vetayases@oracle.com 	msi_regs_t		msi_regs;
30412683SJimmy.Vetayases@oracle.com 	void			*intrmap_tbl[PCI_MSI_MAX_INTRS];
30512683SJimmy.Vetayases@oracle.com 
30612683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n"
30712683SJimmy.Vetayases@oracle.com 	    "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip,
30812683SJimmy.Vetayases@oracle.com 	    ddi_driver_name(dip), inum, vector, target_apic_id));
30912683SJimmy.Vetayases@oracle.com 
31012683SJimmy.Vetayases@oracle.com 	ASSERT((handle != NULL) && (cap_ptr != 0));
31112683SJimmy.Vetayases@oracle.com 
31212683SJimmy.Vetayases@oracle.com 	msi_regs.mr_data = vector;
31312683SJimmy.Vetayases@oracle.com 	msi_regs.mr_addr = target_apic_id;
31412683SJimmy.Vetayases@oracle.com 
315*12822SJudy.Chen@Sun.COM 	for (i = 0; i < count; i++)
316*12822SJudy.Chen@Sun.COM 		intrmap_tbl[i] = xv_intrmap_private(vecp->v_cpuid, vector + i);
31712683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type,
31812683SJimmy.Vetayases@oracle.com 	    count, 0xff);
31912683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++)
32012683SJimmy.Vetayases@oracle.com 		xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i];
32112683SJimmy.Vetayases@oracle.com 
32212683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private,
32312683SJimmy.Vetayases@oracle.com 	    (void *)&msi_regs, type, count);
32412683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private,
32512683SJimmy.Vetayases@oracle.com 	    &msi_regs);
32612683SJimmy.Vetayases@oracle.com 
32712683SJimmy.Vetayases@oracle.com 	/* MSI Address */
32812683SJimmy.Vetayases@oracle.com 	msi_addr = msi_regs.mr_addr;
32912683SJimmy.Vetayases@oracle.com 
33012683SJimmy.Vetayases@oracle.com 	/* MSI Data: MSI is edge triggered according to spec */
33112683SJimmy.Vetayases@oracle.com 	msi_data = msi_regs.mr_data;
33212683SJimmy.Vetayases@oracle.com 
33312683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx "
33412683SJimmy.Vetayases@oracle.com 	    "data=0x%lx\n", (long)msi_addr, (long)msi_data));
33512683SJimmy.Vetayases@oracle.com 
33612683SJimmy.Vetayases@oracle.com 	if (type == APIX_TYPE_MSI) {
33712683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
33812683SJimmy.Vetayases@oracle.com 
33912683SJimmy.Vetayases@oracle.com 		/* Set the bits to inform how many MSIs are enabled */
34012683SJimmy.Vetayases@oracle.com 		msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT);
34112683SJimmy.Vetayases@oracle.com 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
34212683SJimmy.Vetayases@oracle.com 
34312683SJimmy.Vetayases@oracle.com 		if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0)
34412683SJimmy.Vetayases@oracle.com 			APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl,
34512683SJimmy.Vetayases@oracle.com 			    APIX_RESV_VECTOR);
34612683SJimmy.Vetayases@oracle.com 
34712683SJimmy.Vetayases@oracle.com 		pci_config_put32(handle,
34812683SJimmy.Vetayases@oracle.com 		    cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr);
34912683SJimmy.Vetayases@oracle.com 		if (msi_ctrl &  PCI_MSI_64BIT_MASK)
35012683SJimmy.Vetayases@oracle.com 			pci_config_put32(handle,
35112683SJimmy.Vetayases@oracle.com 			    cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32);
35212683SJimmy.Vetayases@oracle.com 
35312683SJimmy.Vetayases@oracle.com 		APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data);
35412683SJimmy.Vetayases@oracle.com 	} else if (type == APIX_TYPE_MSIX) {
35512683SJimmy.Vetayases@oracle.com 		uintptr_t	off;
35612683SJimmy.Vetayases@oracle.com 		ddi_intr_msix_t	*msix_p = i_ddi_get_msix(dip);
35712683SJimmy.Vetayases@oracle.com 
35812683SJimmy.Vetayases@oracle.com 		/* Offset into the "inum"th entry in the MSI-X table */
35912683SJimmy.Vetayases@oracle.com 		off = (uintptr_t)msix_p->msix_tbl_addr +
36012683SJimmy.Vetayases@oracle.com 		    (inum * PCI_MSIX_VECTOR_SIZE);
36112683SJimmy.Vetayases@oracle.com 
36212683SJimmy.Vetayases@oracle.com 		ddi_put32(msix_p->msix_tbl_hdl,
36312683SJimmy.Vetayases@oracle.com 		    (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data);
36412683SJimmy.Vetayases@oracle.com 		ddi_put64(msix_p->msix_tbl_hdl,
36512683SJimmy.Vetayases@oracle.com 		    (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr);
36612683SJimmy.Vetayases@oracle.com 	}
36712683SJimmy.Vetayases@oracle.com }
36812683SJimmy.Vetayases@oracle.com 
36912683SJimmy.Vetayases@oracle.com static void
apix_pci_msi_enable_mode(dev_info_t * dip,int type,int inum)37012683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum)
37112683SJimmy.Vetayases@oracle.com {
37212683SJimmy.Vetayases@oracle.com 	ushort_t		msi_ctrl;
37312683SJimmy.Vetayases@oracle.com 	int			cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
37412683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
37512683SJimmy.Vetayases@oracle.com 
37612683SJimmy.Vetayases@oracle.com 	ASSERT((handle != NULL) && (cap_ptr != 0));
37712683SJimmy.Vetayases@oracle.com 
37812683SJimmy.Vetayases@oracle.com 	if (type == APIX_TYPE_MSI) {
37912683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
38012683SJimmy.Vetayases@oracle.com 		if ((msi_ctrl & PCI_MSI_ENABLE_BIT))
38112683SJimmy.Vetayases@oracle.com 			return;
38212683SJimmy.Vetayases@oracle.com 
38312683SJimmy.Vetayases@oracle.com 		msi_ctrl |= PCI_MSI_ENABLE_BIT;
38412683SJimmy.Vetayases@oracle.com 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
38512683SJimmy.Vetayases@oracle.com 
38612683SJimmy.Vetayases@oracle.com 	} else if (type == DDI_INTR_TYPE_MSIX) {
38712683SJimmy.Vetayases@oracle.com 		uintptr_t	off;
38812683SJimmy.Vetayases@oracle.com 		uint32_t	mask;
38912683SJimmy.Vetayases@oracle.com 		ddi_intr_msix_t	*msix_p;
39012683SJimmy.Vetayases@oracle.com 
39112683SJimmy.Vetayases@oracle.com 		msix_p = i_ddi_get_msix(dip);
39212683SJimmy.Vetayases@oracle.com 
39312683SJimmy.Vetayases@oracle.com 		/* Offset into "inum"th entry in the MSI-X table & clear mask */
39412683SJimmy.Vetayases@oracle.com 		off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
39512683SJimmy.Vetayases@oracle.com 		    PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
39612683SJimmy.Vetayases@oracle.com 
39712683SJimmy.Vetayases@oracle.com 		mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
39812683SJimmy.Vetayases@oracle.com 
39912683SJimmy.Vetayases@oracle.com 		ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1));
40012683SJimmy.Vetayases@oracle.com 
40112683SJimmy.Vetayases@oracle.com 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
40212683SJimmy.Vetayases@oracle.com 
40312683SJimmy.Vetayases@oracle.com 		if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) {
40412683SJimmy.Vetayases@oracle.com 			msi_ctrl |= PCI_MSIX_ENABLE_BIT;
40512683SJimmy.Vetayases@oracle.com 			pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,
40612683SJimmy.Vetayases@oracle.com 			    msi_ctrl);
40712683SJimmy.Vetayases@oracle.com 		}
40812683SJimmy.Vetayases@oracle.com 	}
40912683SJimmy.Vetayases@oracle.com }
41012683SJimmy.Vetayases@oracle.com 
41112683SJimmy.Vetayases@oracle.com /*
41212683SJimmy.Vetayases@oracle.com  * Setup interrupt, pogramming IO-APIC or MSI/X address/data.
41312683SJimmy.Vetayases@oracle.com  */
41412683SJimmy.Vetayases@oracle.com void
apix_enable_vector(apix_vector_t * vecp)41512683SJimmy.Vetayases@oracle.com apix_enable_vector(apix_vector_t *vecp)
41612683SJimmy.Vetayases@oracle.com {
41712683SJimmy.Vetayases@oracle.com 	int tocpu = vecp->v_cpuid, type = vecp->v_type;
41812683SJimmy.Vetayases@oracle.com 	apic_cpus_info_t *cpu_infop;
41912683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
42012683SJimmy.Vetayases@oracle.com 
42112683SJimmy.Vetayases@oracle.com 	ASSERT(tocpu < apic_nproc);
42212683SJimmy.Vetayases@oracle.com 
42312683SJimmy.Vetayases@oracle.com 	cpu_infop = &apic_cpus[tocpu];
42412683SJimmy.Vetayases@oracle.com 	if (vecp->v_flags & APIX_VECT_USER_BOUND)
42512683SJimmy.Vetayases@oracle.com 		cpu_infop->aci_bound++;
42612683SJimmy.Vetayases@oracle.com 	else
42712683SJimmy.Vetayases@oracle.com 		cpu_infop->aci_temp_bound++;
42812683SJimmy.Vetayases@oracle.com 
42912683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
43012683SJimmy.Vetayases@oracle.com 	lock_set(&apic_ioapic_lock);
43112683SJimmy.Vetayases@oracle.com 
43212683SJimmy.Vetayases@oracle.com 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {	/* fixed */
43312683SJimmy.Vetayases@oracle.com 		apix_intx_enable(vecp->v_inum);
43412683SJimmy.Vetayases@oracle.com 	} else {
43512683SJimmy.Vetayases@oracle.com 		int inum = vecp->v_inum;
43612683SJimmy.Vetayases@oracle.com 		dev_info_t *dip = APIX_GET_DIP(vecp);
43712683SJimmy.Vetayases@oracle.com 		int count = i_ddi_intr_get_current_nintrs(dip);
43812683SJimmy.Vetayases@oracle.com 
43912683SJimmy.Vetayases@oracle.com 		if (type == APIX_TYPE_MSI) {	/* MSI */
44012683SJimmy.Vetayases@oracle.com 			if (inum == apix_get_max_dev_inum(dip, type)) {
44112683SJimmy.Vetayases@oracle.com 				/* last one */
44212683SJimmy.Vetayases@oracle.com 				uchar_t start_inum = inum + 1 - count;
44312683SJimmy.Vetayases@oracle.com 				uchar_t start_vect = vecp->v_vector + 1 - count;
44412683SJimmy.Vetayases@oracle.com 				apix_vector_t *start_vecp =
44512683SJimmy.Vetayases@oracle.com 				    xv_vector(vecp->v_cpuid, start_vect);
44612683SJimmy.Vetayases@oracle.com 
44712683SJimmy.Vetayases@oracle.com 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
44812683SJimmy.Vetayases@oracle.com 				    "apix_pci_msi_enable_vector\n"));
44912683SJimmy.Vetayases@oracle.com 				apix_pci_msi_enable_vector(start_vecp, dip,
45012683SJimmy.Vetayases@oracle.com 				    type, start_inum, count, start_vect,
45112683SJimmy.Vetayases@oracle.com 				    cpu_infop->aci_local_id);
45212683SJimmy.Vetayases@oracle.com 
45312683SJimmy.Vetayases@oracle.com 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
45412683SJimmy.Vetayases@oracle.com 				    "apix_pci_msi_enable_mode\n"));
45512683SJimmy.Vetayases@oracle.com 				apix_pci_msi_enable_mode(dip, type, inum);
45612683SJimmy.Vetayases@oracle.com 			}
45712683SJimmy.Vetayases@oracle.com 		} else {				/* MSI-X */
45812683SJimmy.Vetayases@oracle.com 			apix_pci_msi_enable_vector(vecp, dip,
45912683SJimmy.Vetayases@oracle.com 			    type, inum, 1, vecp->v_vector,
46012683SJimmy.Vetayases@oracle.com 			    cpu_infop->aci_local_id);
46112683SJimmy.Vetayases@oracle.com 			apix_pci_msi_enable_mode(dip, type, inum);
46212683SJimmy.Vetayases@oracle.com 		}
46312683SJimmy.Vetayases@oracle.com 	}
46412683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_ENABLED;
46512683SJimmy.Vetayases@oracle.com 	apic_redist_cpu_skip &= ~(1 << tocpu);
46612683SJimmy.Vetayases@oracle.com 
46712683SJimmy.Vetayases@oracle.com 	lock_clear(&apic_ioapic_lock);
46812683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
46912683SJimmy.Vetayases@oracle.com }
47012683SJimmy.Vetayases@oracle.com 
47112683SJimmy.Vetayases@oracle.com /*
47212683SJimmy.Vetayases@oracle.com  * Disable the interrupt
47312683SJimmy.Vetayases@oracle.com  */
47412683SJimmy.Vetayases@oracle.com void
apix_disable_vector(apix_vector_t * vecp)47512683SJimmy.Vetayases@oracle.com apix_disable_vector(apix_vector_t *vecp)
47612683SJimmy.Vetayases@oracle.com {
47712683SJimmy.Vetayases@oracle.com 	struct autovec *avp = vecp->v_autovect;
47812683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
47912683SJimmy.Vetayases@oracle.com 
48012683SJimmy.Vetayases@oracle.com 	ASSERT(avp != NULL);
48112683SJimmy.Vetayases@oracle.com 
48212683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
48312683SJimmy.Vetayases@oracle.com 	lock_set(&apic_ioapic_lock);
48412683SJimmy.Vetayases@oracle.com 
48512683SJimmy.Vetayases@oracle.com 	switch (vecp->v_type) {
48612683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSI:
48712683SJimmy.Vetayases@oracle.com 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
48812683SJimmy.Vetayases@oracle.com 		/*
48912683SJimmy.Vetayases@oracle.com 		 * Disable the MSI vector
49012683SJimmy.Vetayases@oracle.com 		 * Make sure we only disable on the last
49112683SJimmy.Vetayases@oracle.com 		 * of the multi-MSI support
49212683SJimmy.Vetayases@oracle.com 		 */
49312683SJimmy.Vetayases@oracle.com 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
49412683SJimmy.Vetayases@oracle.com 			apic_pci_msi_disable_mode(avp->av_dip,
49512683SJimmy.Vetayases@oracle.com 			    DDI_INTR_TYPE_MSI);
49612683SJimmy.Vetayases@oracle.com 		}
49712683SJimmy.Vetayases@oracle.com 		break;
49812683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSIX:
49912683SJimmy.Vetayases@oracle.com 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
50012683SJimmy.Vetayases@oracle.com 		/*
50112683SJimmy.Vetayases@oracle.com 		 * Disable the MSI-X vector
50212683SJimmy.Vetayases@oracle.com 		 * needs to clear its mask and addr/data for each MSI-X
50312683SJimmy.Vetayases@oracle.com 		 */
50412683SJimmy.Vetayases@oracle.com 		apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX,
50512683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
50612683SJimmy.Vetayases@oracle.com 		/*
50712683SJimmy.Vetayases@oracle.com 		 * Make sure we only disable on the last MSI-X
50812683SJimmy.Vetayases@oracle.com 		 */
50912683SJimmy.Vetayases@oracle.com 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
51012683SJimmy.Vetayases@oracle.com 			apic_pci_msi_disable_mode(avp->av_dip,
51112683SJimmy.Vetayases@oracle.com 			    DDI_INTR_TYPE_MSIX);
51212683SJimmy.Vetayases@oracle.com 		}
51312683SJimmy.Vetayases@oracle.com 		break;
51412683SJimmy.Vetayases@oracle.com 	default:
51512683SJimmy.Vetayases@oracle.com 		apix_intx_disable(vecp->v_inum);
51612683SJimmy.Vetayases@oracle.com 		break;
51712683SJimmy.Vetayases@oracle.com 	}
51812683SJimmy.Vetayases@oracle.com 
51912683SJimmy.Vetayases@oracle.com 	if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND))
52012683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_DISABLED;
52112683SJimmy.Vetayases@oracle.com 	apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private);
52212683SJimmy.Vetayases@oracle.com 	vecp->v_intrmap_private = NULL;
52312683SJimmy.Vetayases@oracle.com 
52412683SJimmy.Vetayases@oracle.com 	lock_clear(&apic_ioapic_lock);
52512683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
52612683SJimmy.Vetayases@oracle.com }
52712683SJimmy.Vetayases@oracle.com 
52812683SJimmy.Vetayases@oracle.com /*
52912683SJimmy.Vetayases@oracle.com  * Mark vector as obsoleted or freed. The vector is marked
53012683SJimmy.Vetayases@oracle.com  * obsoleted if there are pending requests on it. Otherwise,
53112683SJimmy.Vetayases@oracle.com  * free the vector. The obsoleted vectors get freed after
53212683SJimmy.Vetayases@oracle.com  * being serviced.
53312683SJimmy.Vetayases@oracle.com  *
53412683SJimmy.Vetayases@oracle.com  * Return 1 on being obosoleted and 0 on being freed.
53512683SJimmy.Vetayases@oracle.com  */
53612683SJimmy.Vetayases@oracle.com #define	INTR_BUSY(_avp)\
53712683SJimmy.Vetayases@oracle.com 	((((volatile ushort_t)(_avp)->av_flags) &\
53812683SJimmy.Vetayases@oracle.com 	(AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0)
53912683SJimmy.Vetayases@oracle.com #define	LOCAL_WITH_INTR_DISABLED(_cpuid)\
54012683SJimmy.Vetayases@oracle.com 	((_cpuid) == psm_get_cpu_id() && !interrupts_enabled())
54112683SJimmy.Vetayases@oracle.com static uint64_t dummy_tick;
54212683SJimmy.Vetayases@oracle.com 
54312683SJimmy.Vetayases@oracle.com int
apix_obsolete_vector(apix_vector_t * vecp)54412683SJimmy.Vetayases@oracle.com apix_obsolete_vector(apix_vector_t *vecp)
54512683SJimmy.Vetayases@oracle.com {
54612683SJimmy.Vetayases@oracle.com 	struct autovec *avp = vecp->v_autovect;
54712683SJimmy.Vetayases@oracle.com 	int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid;
54812683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
54912683SJimmy.Vetayases@oracle.com 
55012683SJimmy.Vetayases@oracle.com 	ASSERT(APIX_CPU_LOCK_HELD(cpuid));
55112683SJimmy.Vetayases@oracle.com 
55212683SJimmy.Vetayases@oracle.com 	for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) {
55312683SJimmy.Vetayases@oracle.com 		if (avp->av_vector == NULL)
55412683SJimmy.Vetayases@oracle.com 			continue;
55512683SJimmy.Vetayases@oracle.com 
55612683SJimmy.Vetayases@oracle.com 		if (LOCAL_WITH_INTR_DISABLED(cpuid)) {
55712683SJimmy.Vetayases@oracle.com 			int bit, index, irr;
55812683SJimmy.Vetayases@oracle.com 
55912683SJimmy.Vetayases@oracle.com 			if (INTR_BUSY(avp)) {
56012683SJimmy.Vetayases@oracle.com 				busy++;
56112683SJimmy.Vetayases@oracle.com 				continue;
56212683SJimmy.Vetayases@oracle.com 			}
56312683SJimmy.Vetayases@oracle.com 
56412683SJimmy.Vetayases@oracle.com 			/* check IRR for pending interrupts */
56512683SJimmy.Vetayases@oracle.com 			index = vecp->v_vector / 32;
56612683SJimmy.Vetayases@oracle.com 			bit = vecp->v_vector % 32;
56712683SJimmy.Vetayases@oracle.com 			irr = apic_reg_ops->apic_read(APIC_IRR_REG + index);
56812683SJimmy.Vetayases@oracle.com 			if ((irr & (1 << bit)) != 0)
56912683SJimmy.Vetayases@oracle.com 				busy++;
57012683SJimmy.Vetayases@oracle.com 
57112683SJimmy.Vetayases@oracle.com 			if (!busy)
57212683SJimmy.Vetayases@oracle.com 				apix_remove_av(vecp, avp);
57312683SJimmy.Vetayases@oracle.com 
57412683SJimmy.Vetayases@oracle.com 			continue;
57512683SJimmy.Vetayases@oracle.com 		}
57612683SJimmy.Vetayases@oracle.com 
57712683SJimmy.Vetayases@oracle.com 		repeats = 0;
57812683SJimmy.Vetayases@oracle.com 		do {
57912683SJimmy.Vetayases@oracle.com 			repeats++;
58012683SJimmy.Vetayases@oracle.com 			for (tries = 0; tries < apic_max_reps_clear_pending;
58112683SJimmy.Vetayases@oracle.com 			    tries++)
58212683SJimmy.Vetayases@oracle.com 				if (!INTR_BUSY(avp))
58312683SJimmy.Vetayases@oracle.com 					break;
58412683SJimmy.Vetayases@oracle.com 		} while (INTR_BUSY(avp) &&
58512683SJimmy.Vetayases@oracle.com 		    (repeats < apic_max_reps_clear_pending));
58612683SJimmy.Vetayases@oracle.com 
58712683SJimmy.Vetayases@oracle.com 		if (INTR_BUSY(avp))
58812683SJimmy.Vetayases@oracle.com 			busy++;
58912683SJimmy.Vetayases@oracle.com 		else {
59012683SJimmy.Vetayases@oracle.com 			/*
59112683SJimmy.Vetayases@oracle.com 			 * Interrupt is not in pending list or being serviced.
59212683SJimmy.Vetayases@oracle.com 			 * However it might be cached in Local APIC's IRR
59312683SJimmy.Vetayases@oracle.com 			 * register. It's impossible to check another CPU's
59412683SJimmy.Vetayases@oracle.com 			 * IRR register. Then wait till lower levels finish
59512683SJimmy.Vetayases@oracle.com 			 * running.
59612683SJimmy.Vetayases@oracle.com 			 */
59712683SJimmy.Vetayases@oracle.com 			for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++)
59812683SJimmy.Vetayases@oracle.com 				apix_wait_till_seen(cpuid, ipl);
59912683SJimmy.Vetayases@oracle.com 			if (INTR_BUSY(avp))
60012683SJimmy.Vetayases@oracle.com 				busy++;
60112683SJimmy.Vetayases@oracle.com 		}
60212683SJimmy.Vetayases@oracle.com 
60312683SJimmy.Vetayases@oracle.com 		if (!busy)
60412683SJimmy.Vetayases@oracle.com 			apix_remove_av(vecp, avp);
60512683SJimmy.Vetayases@oracle.com 	}
60612683SJimmy.Vetayases@oracle.com 
60712683SJimmy.Vetayases@oracle.com 	if (busy) {
60812683SJimmy.Vetayases@oracle.com 		apix_vector_t *tp = apixp->x_obsoletes;
60912683SJimmy.Vetayases@oracle.com 
61012683SJimmy.Vetayases@oracle.com 		if (vecp->v_state == APIX_STATE_OBSOLETED)
61112683SJimmy.Vetayases@oracle.com 			return (1);
61212683SJimmy.Vetayases@oracle.com 
61312683SJimmy.Vetayases@oracle.com 		vecp->v_state = APIX_STATE_OBSOLETED;
61412683SJimmy.Vetayases@oracle.com 		vecp->v_next = NULL;
61512683SJimmy.Vetayases@oracle.com 		if (tp == NULL)
61612683SJimmy.Vetayases@oracle.com 			apixp->x_obsoletes = vecp;
61712683SJimmy.Vetayases@oracle.com 		else {
61812683SJimmy.Vetayases@oracle.com 			while (tp->v_next != NULL)
61912683SJimmy.Vetayases@oracle.com 				tp = tp->v_next;
62012683SJimmy.Vetayases@oracle.com 			tp->v_next = vecp;
62112683SJimmy.Vetayases@oracle.com 		}
62212683SJimmy.Vetayases@oracle.com 		return (1);
62312683SJimmy.Vetayases@oracle.com 	}
62412683SJimmy.Vetayases@oracle.com 
62512683SJimmy.Vetayases@oracle.com 	/* interrupt is not busy */
62612683SJimmy.Vetayases@oracle.com 	if (vecp->v_state == APIX_STATE_OBSOLETED) {
62712683SJimmy.Vetayases@oracle.com 		/* remove from obsoleted list */
62812683SJimmy.Vetayases@oracle.com 		apixp->x_obsoletes = vecp->v_next;
62912683SJimmy.Vetayases@oracle.com 		vecp->v_next = NULL;
63012683SJimmy.Vetayases@oracle.com 	}
63112683SJimmy.Vetayases@oracle.com 	apix_cleanup_vector(vecp);
63212683SJimmy.Vetayases@oracle.com 	return (0);
63312683SJimmy.Vetayases@oracle.com }
63412683SJimmy.Vetayases@oracle.com 
63512683SJimmy.Vetayases@oracle.com /*
63612683SJimmy.Vetayases@oracle.com  * Duplicate number of continuous vectors to specified target vectors.
63712683SJimmy.Vetayases@oracle.com  */
63812683SJimmy.Vetayases@oracle.com static void
apix_dup_vectors(apix_vector_t * oldp,apix_vector_t * newp,int count)63912683SJimmy.Vetayases@oracle.com apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count)
64012683SJimmy.Vetayases@oracle.com {
64112683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
64212683SJimmy.Vetayases@oracle.com 	apix_vector_t *fromp, *top;
64312683SJimmy.Vetayases@oracle.com 	processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid;
64412683SJimmy.Vetayases@oracle.com 	uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector;
64512683SJimmy.Vetayases@oracle.com 	int i, inum;
64612683SJimmy.Vetayases@oracle.com 
64712683SJimmy.Vetayases@oracle.com 	ASSERT(oldp->v_type != APIX_TYPE_IPI);
64812683SJimmy.Vetayases@oracle.com 
64912683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
65012683SJimmy.Vetayases@oracle.com 		fromp = xv_vector(oldcpu, oldvec + i);
65112683SJimmy.Vetayases@oracle.com 		top = xv_vector(newcpu, newvec + i);
65212683SJimmy.Vetayases@oracle.com 		ASSERT(fromp != NULL && top != NULL);
65312683SJimmy.Vetayases@oracle.com 
65412683SJimmy.Vetayases@oracle.com 		/* copy over original one */
65512683SJimmy.Vetayases@oracle.com 		top->v_state = fromp->v_state;
65612683SJimmy.Vetayases@oracle.com 		top->v_type = fromp->v_type;
65712683SJimmy.Vetayases@oracle.com 		top->v_bound_cpuid = fromp->v_bound_cpuid;
65812683SJimmy.Vetayases@oracle.com 		top->v_inum = fromp->v_inum;
65912683SJimmy.Vetayases@oracle.com 		top->v_flags = fromp->v_flags;
66012683SJimmy.Vetayases@oracle.com 		top->v_intrmap_private = fromp->v_intrmap_private;
66112683SJimmy.Vetayases@oracle.com 
66212683SJimmy.Vetayases@oracle.com 		for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) {
66312683SJimmy.Vetayases@oracle.com 			if (avp->av_vector == NULL)
66412683SJimmy.Vetayases@oracle.com 				continue;
66512683SJimmy.Vetayases@oracle.com 
66612683SJimmy.Vetayases@oracle.com 			apix_insert_av(top, avp->av_intr_id, avp->av_vector,
66712683SJimmy.Vetayases@oracle.com 			    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
66812683SJimmy.Vetayases@oracle.com 			    avp->av_prilevel, avp->av_dip);
66912683SJimmy.Vetayases@oracle.com 
67012683SJimmy.Vetayases@oracle.com 			if (fromp->v_type == APIX_TYPE_FIXED &&
67112683SJimmy.Vetayases@oracle.com 			    avp->av_dip != NULL) {
67212683SJimmy.Vetayases@oracle.com 				inum = GET_INTR_INUM(avp->av_intr_id);
67312683SJimmy.Vetayases@oracle.com 				apix_set_dev_map(top, avp->av_dip, inum);
67412683SJimmy.Vetayases@oracle.com 			}
67512683SJimmy.Vetayases@oracle.com 		}
67612683SJimmy.Vetayases@oracle.com 
67712683SJimmy.Vetayases@oracle.com 		if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) &&
67812683SJimmy.Vetayases@oracle.com 		    fromp->v_devp != NULL)
67912683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(top, fromp->v_devp->dv_dip,
68012683SJimmy.Vetayases@oracle.com 			    fromp->v_devp->dv_inum);
68112683SJimmy.Vetayases@oracle.com 	}
68212683SJimmy.Vetayases@oracle.com }
68312683SJimmy.Vetayases@oracle.com 
68412683SJimmy.Vetayases@oracle.com static apix_vector_t *
apix_init_vector(processorid_t cpuid,uchar_t vector)68512683SJimmy.Vetayases@oracle.com apix_init_vector(processorid_t cpuid, uchar_t vector)
68612683SJimmy.Vetayases@oracle.com {
68712683SJimmy.Vetayases@oracle.com 	apix_impl_t *apixp = apixs[cpuid];
68812683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp = apixp->x_vectbl[vector];
68912683SJimmy.Vetayases@oracle.com 
69012683SJimmy.Vetayases@oracle.com 	ASSERT(IS_VECT_FREE(vecp));
69112683SJimmy.Vetayases@oracle.com 
69212683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
69312683SJimmy.Vetayases@oracle.com 		vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
69412683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
69512683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "apix: no memory to allocate vector");
69612683SJimmy.Vetayases@oracle.com 			return (NULL);
69712683SJimmy.Vetayases@oracle.com 		}
69812683SJimmy.Vetayases@oracle.com 		apixp->x_vectbl[vector] = vecp;
69912683SJimmy.Vetayases@oracle.com 	}
70012683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_ALLOCED;
70112683SJimmy.Vetayases@oracle.com 	vecp->v_cpuid = vecp->v_bound_cpuid = cpuid;
70212683SJimmy.Vetayases@oracle.com 	vecp->v_vector = vector;
70312683SJimmy.Vetayases@oracle.com 
70412683SJimmy.Vetayases@oracle.com 	return (vecp);
70512683SJimmy.Vetayases@oracle.com }
70612683SJimmy.Vetayases@oracle.com 
70712683SJimmy.Vetayases@oracle.com static void
apix_cleanup_vector(apix_vector_t * vecp)70812683SJimmy.Vetayases@oracle.com apix_cleanup_vector(apix_vector_t *vecp)
70912683SJimmy.Vetayases@oracle.com {
71012683SJimmy.Vetayases@oracle.com 	ASSERT(vecp->v_share == 0);
71112683SJimmy.Vetayases@oracle.com 	vecp->v_bound_cpuid = IRQ_UNINIT;
71212683SJimmy.Vetayases@oracle.com 	vecp->v_state = APIX_STATE_FREED;
71312683SJimmy.Vetayases@oracle.com 	vecp->v_type = 0;
71412683SJimmy.Vetayases@oracle.com 	vecp->v_flags = 0;
71512683SJimmy.Vetayases@oracle.com 	vecp->v_busy = 0;
71612752SPrasad.Singamsetty@Sun.COM 	vecp->v_intrmap_private = NULL;
71712683SJimmy.Vetayases@oracle.com }
71812683SJimmy.Vetayases@oracle.com 
71912683SJimmy.Vetayases@oracle.com static void
apix_dprint_vector(apix_vector_t * vecp,dev_info_t * dip,int count)72012683SJimmy.Vetayases@oracle.com apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count)
72112683SJimmy.Vetayases@oracle.com {
72212683SJimmy.Vetayases@oracle.com #ifdef DEBUG
72312683SJimmy.Vetayases@oracle.com 	major_t major;
72412683SJimmy.Vetayases@oracle.com 	char *name, *drv_name;
72512683SJimmy.Vetayases@oracle.com 	int instance, len, t_len;
72612683SJimmy.Vetayases@oracle.com 	char mesg[1024] = "apix: ";
72712683SJimmy.Vetayases@oracle.com 
72812683SJimmy.Vetayases@oracle.com 	t_len = sizeof (mesg);
72912683SJimmy.Vetayases@oracle.com 	len = strlen(mesg);
73012683SJimmy.Vetayases@oracle.com 	if (dip != NULL) {
73112683SJimmy.Vetayases@oracle.com 		name = ddi_get_name(dip);
73212683SJimmy.Vetayases@oracle.com 		major = ddi_name_to_major(name);
73312683SJimmy.Vetayases@oracle.com 		drv_name = ddi_major_to_name(major);
73412683SJimmy.Vetayases@oracle.com 		instance = ddi_get_instance(dip);
73512683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ",
73612683SJimmy.Vetayases@oracle.com 		    name, drv_name, instance);
73712683SJimmy.Vetayases@oracle.com 	}
73812683SJimmy.Vetayases@oracle.com 	len = strlen(mesg);
73912683SJimmy.Vetayases@oracle.com 
74012683SJimmy.Vetayases@oracle.com 	switch (vecp->v_type) {
74112683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_FIXED:
74212683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "irqno %d",
74312683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
74412683SJimmy.Vetayases@oracle.com 		break;
74512683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSI:
74612683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len,
74712683SJimmy.Vetayases@oracle.com 		    "msi inum %d (count %d)", vecp->v_inum, count);
74812683SJimmy.Vetayases@oracle.com 		break;
74912683SJimmy.Vetayases@oracle.com 	case APIX_TYPE_MSIX:
75012683SJimmy.Vetayases@oracle.com 		(void) snprintf(mesg + len, t_len - len, "msi-x inum %d",
75112683SJimmy.Vetayases@oracle.com 		    vecp->v_inum);
75212683SJimmy.Vetayases@oracle.com 		break;
75312683SJimmy.Vetayases@oracle.com 	default:
75412683SJimmy.Vetayases@oracle.com 		break;
75512683SJimmy.Vetayases@oracle.com 
75612683SJimmy.Vetayases@oracle.com 	}
75712683SJimmy.Vetayases@oracle.com 
75812683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on "
75912683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid));
76012683SJimmy.Vetayases@oracle.com #endif	/* DEBUG */
76112683SJimmy.Vetayases@oracle.com }
76212683SJimmy.Vetayases@oracle.com 
76312683SJimmy.Vetayases@oracle.com /*
76412683SJimmy.Vetayases@oracle.com  * Operations on avintr
76512683SJimmy.Vetayases@oracle.com  */
76612683SJimmy.Vetayases@oracle.com 
76712683SJimmy.Vetayases@oracle.com #define	INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip)	\
76812683SJimmy.Vetayases@oracle.com do { \
76912683SJimmy.Vetayases@oracle.com 	(p)->av_intr_id = intr_id;	\
77012683SJimmy.Vetayases@oracle.com 	(p)->av_vector = f;		\
77112683SJimmy.Vetayases@oracle.com 	(p)->av_intarg1 = arg1;		\
77212683SJimmy.Vetayases@oracle.com 	(p)->av_intarg2 = arg2;		\
77312683SJimmy.Vetayases@oracle.com 	(p)->av_ticksp = ticksp;	\
77412683SJimmy.Vetayases@oracle.com 	(p)->av_prilevel = ipl;		\
77512683SJimmy.Vetayases@oracle.com 	(p)->av_dip = dip;		\
77612683SJimmy.Vetayases@oracle.com 	(p)->av_flags = 0;		\
77712683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0)
77812683SJimmy.Vetayases@oracle.com 
77912683SJimmy.Vetayases@oracle.com /*
78012683SJimmy.Vetayases@oracle.com  * Insert an interrupt service routine into chain by its priority from
78112683SJimmy.Vetayases@oracle.com  * high to low
78212683SJimmy.Vetayases@oracle.com  */
78312683SJimmy.Vetayases@oracle.com static void
apix_insert_av(apix_vector_t * vecp,void * intr_id,avfunc f,caddr_t arg1,caddr_t arg2,uint64_t * ticksp,int ipl,dev_info_t * dip)78412683SJimmy.Vetayases@oracle.com apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1,
78512683SJimmy.Vetayases@oracle.com     caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip)
78612683SJimmy.Vetayases@oracle.com {
78712683SJimmy.Vetayases@oracle.com 	struct autovec *p, *prep, *mem;
78812683SJimmy.Vetayases@oracle.com 
78912683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, "
79012683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid));
79112683SJimmy.Vetayases@oracle.com 
79212683SJimmy.Vetayases@oracle.com 	mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP);
79312683SJimmy.Vetayases@oracle.com 	INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip);
79412683SJimmy.Vetayases@oracle.com 	if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum])
79512683SJimmy.Vetayases@oracle.com 		mem->av_flags |= AV_PENTRY_LEVEL;
79612683SJimmy.Vetayases@oracle.com 
79712683SJimmy.Vetayases@oracle.com 	vecp->v_share++;
79812683SJimmy.Vetayases@oracle.com 	vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri;
79912683SJimmy.Vetayases@oracle.com 	if (vecp->v_autovect == NULL) {	/* Nothing on list - put it at head */
80012683SJimmy.Vetayases@oracle.com 		vecp->v_autovect = mem;
80112683SJimmy.Vetayases@oracle.com 		return;
80212683SJimmy.Vetayases@oracle.com 	}
80312683SJimmy.Vetayases@oracle.com 
80412683SJimmy.Vetayases@oracle.com 	if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {	/* MSI/X */
80512683SJimmy.Vetayases@oracle.com 		ASSERT(vecp->v_share == 1);	/* No sharing for MSI/X */
80612683SJimmy.Vetayases@oracle.com 
80712683SJimmy.Vetayases@oracle.com 		INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp,
80812683SJimmy.Vetayases@oracle.com 		    ipl, dip);
80912683SJimmy.Vetayases@oracle.com 		prep = vecp->v_autovect->av_link;
81012683SJimmy.Vetayases@oracle.com 		vecp->v_autovect->av_link = NULL;
81112683SJimmy.Vetayases@oracle.com 
81212683SJimmy.Vetayases@oracle.com 		/* Free the following autovect chain */
81312683SJimmy.Vetayases@oracle.com 		while (prep != NULL) {
81412683SJimmy.Vetayases@oracle.com 			ASSERT(prep->av_vector == NULL);
81512683SJimmy.Vetayases@oracle.com 
81612683SJimmy.Vetayases@oracle.com 			p = prep;
81712683SJimmy.Vetayases@oracle.com 			prep = prep->av_link;
81812683SJimmy.Vetayases@oracle.com 			kmem_free(p, sizeof (struct autovec));
81912683SJimmy.Vetayases@oracle.com 		}
82012683SJimmy.Vetayases@oracle.com 
82112683SJimmy.Vetayases@oracle.com 		kmem_free(mem, sizeof (struct autovec));
82212683SJimmy.Vetayases@oracle.com 		return;
82312683SJimmy.Vetayases@oracle.com 	}
82412683SJimmy.Vetayases@oracle.com 
82512683SJimmy.Vetayases@oracle.com 	/* find where it goes in list */
82612683SJimmy.Vetayases@oracle.com 	prep = NULL;
82712683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p != NULL; p = p->av_link) {
82812683SJimmy.Vetayases@oracle.com 		if (p->av_vector && p->av_prilevel <= ipl)
82912683SJimmy.Vetayases@oracle.com 			break;
83012683SJimmy.Vetayases@oracle.com 		prep = p;
83112683SJimmy.Vetayases@oracle.com 	}
83212683SJimmy.Vetayases@oracle.com 	if (prep != NULL) {
83312683SJimmy.Vetayases@oracle.com 		if (prep->av_vector == NULL) {	/* freed struct available */
83412683SJimmy.Vetayases@oracle.com 			INIT_AUTOVEC(prep, intr_id, f, arg1, arg2,
83512683SJimmy.Vetayases@oracle.com 			    ticksp, ipl, dip);
83612683SJimmy.Vetayases@oracle.com 			prep->av_flags = mem->av_flags;
83712683SJimmy.Vetayases@oracle.com 			kmem_free(mem, sizeof (struct autovec));
83812683SJimmy.Vetayases@oracle.com 			return;
83912683SJimmy.Vetayases@oracle.com 		}
84012683SJimmy.Vetayases@oracle.com 
84112683SJimmy.Vetayases@oracle.com 		mem->av_link = prep->av_link;
84212683SJimmy.Vetayases@oracle.com 		prep->av_link = mem;
84312683SJimmy.Vetayases@oracle.com 	} else {
84412683SJimmy.Vetayases@oracle.com 		/* insert new intpt at beginning of chain */
84512683SJimmy.Vetayases@oracle.com 		mem->av_link = vecp->v_autovect;
84612683SJimmy.Vetayases@oracle.com 		vecp->v_autovect = mem;
84712683SJimmy.Vetayases@oracle.com 	}
84812683SJimmy.Vetayases@oracle.com }
84912683SJimmy.Vetayases@oracle.com 
85012683SJimmy.Vetayases@oracle.com /*
85112683SJimmy.Vetayases@oracle.com  * After having made a change to an autovector list, wait until we have
85212683SJimmy.Vetayases@oracle.com  * seen specified cpu not executing an interrupt at that level--so we
85312683SJimmy.Vetayases@oracle.com  * know our change has taken effect completely (no old state in registers,
85412683SJimmy.Vetayases@oracle.com  * etc).
85512683SJimmy.Vetayases@oracle.com  */
85612683SJimmy.Vetayases@oracle.com #define	APIX_CPU_ENABLED(_cp) \
85712683SJimmy.Vetayases@oracle.com 	(quiesce_active == 0 && \
85812683SJimmy.Vetayases@oracle.com 	(((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0))
85912683SJimmy.Vetayases@oracle.com 
86012683SJimmy.Vetayases@oracle.com static void
apix_wait_till_seen(processorid_t cpuid,int ipl)86112683SJimmy.Vetayases@oracle.com apix_wait_till_seen(processorid_t cpuid, int ipl)
86212683SJimmy.Vetayases@oracle.com {
86312683SJimmy.Vetayases@oracle.com 	struct cpu *cp = cpu[cpuid];
86412683SJimmy.Vetayases@oracle.com 
86512683SJimmy.Vetayases@oracle.com 	if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid))
86612683SJimmy.Vetayases@oracle.com 		return;
86712683SJimmy.Vetayases@oracle.com 
86812683SJimmy.Vetayases@oracle.com 	/*
86912683SJimmy.Vetayases@oracle.com 	 * Don't wait if the CPU is quiesced or offlined. This can happen
87012683SJimmy.Vetayases@oracle.com 	 * when a CPU is running pause thread but hardware triggered an
87112683SJimmy.Vetayases@oracle.com 	 * interrupt and the interrupt gets queued.
87212683SJimmy.Vetayases@oracle.com 	 */
87312683SJimmy.Vetayases@oracle.com 	for (;;) {
87412683SJimmy.Vetayases@oracle.com 		if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) &&
87512683SJimmy.Vetayases@oracle.com 		    (!APIX_CPU_ENABLED(cp) ||
87612683SJimmy.Vetayases@oracle.com 		    !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl)))
87712683SJimmy.Vetayases@oracle.com 			return;
87812683SJimmy.Vetayases@oracle.com 	}
87912683SJimmy.Vetayases@oracle.com }
88012683SJimmy.Vetayases@oracle.com 
88112683SJimmy.Vetayases@oracle.com static void
apix_remove_av(apix_vector_t * vecp,struct autovec * target)88212683SJimmy.Vetayases@oracle.com apix_remove_av(apix_vector_t *vecp, struct autovec *target)
88312683SJimmy.Vetayases@oracle.com {
88412683SJimmy.Vetayases@oracle.com 	int hi_pri = 0;
88512683SJimmy.Vetayases@oracle.com 	struct autovec *p;
88612683SJimmy.Vetayases@oracle.com 
88712683SJimmy.Vetayases@oracle.com 	if (target == NULL)
88812683SJimmy.Vetayases@oracle.com 		return;
88912683SJimmy.Vetayases@oracle.com 
89012683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, "
89112683SJimmy.Vetayases@oracle.com 	    "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid));
89212683SJimmy.Vetayases@oracle.com 
89312683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p; p = p->av_link) {
89412683SJimmy.Vetayases@oracle.com 		if (p == target || p->av_vector == NULL)
89512683SJimmy.Vetayases@oracle.com 			continue;
89612683SJimmy.Vetayases@oracle.com 		hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri;
89712683SJimmy.Vetayases@oracle.com 	}
89812683SJimmy.Vetayases@oracle.com 
89912683SJimmy.Vetayases@oracle.com 	vecp->v_share--;
90012683SJimmy.Vetayases@oracle.com 	vecp->v_pri = hi_pri;
90112683SJimmy.Vetayases@oracle.com 
90212683SJimmy.Vetayases@oracle.com 	/*
90312683SJimmy.Vetayases@oracle.com 	 * This drops the handler from the chain, it can no longer be called.
90412683SJimmy.Vetayases@oracle.com 	 * However, there is no guarantee that the handler is not currently
90512683SJimmy.Vetayases@oracle.com 	 * still executing.
90612683SJimmy.Vetayases@oracle.com 	 */
90712683SJimmy.Vetayases@oracle.com 	target->av_vector = NULL;
90812683SJimmy.Vetayases@oracle.com 	/*
90912683SJimmy.Vetayases@oracle.com 	 * There is a race where we could be just about to pick up the ticksp
91012683SJimmy.Vetayases@oracle.com 	 * pointer to increment it after returning from the service routine
91112683SJimmy.Vetayases@oracle.com 	 * in av_dispatch_autovect.  Rather than NULL it out let's just point
91212683SJimmy.Vetayases@oracle.com 	 * it off to something safe so that any final tick update attempt
91312683SJimmy.Vetayases@oracle.com 	 * won't fault.
91412683SJimmy.Vetayases@oracle.com 	 */
91512683SJimmy.Vetayases@oracle.com 	target->av_ticksp = &dummy_tick;
91612683SJimmy.Vetayases@oracle.com 	apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel);
91712683SJimmy.Vetayases@oracle.com }
91812683SJimmy.Vetayases@oracle.com 
91912683SJimmy.Vetayases@oracle.com static struct autovec *
apix_find_av(apix_vector_t * vecp,void * intr_id,avfunc f)92012683SJimmy.Vetayases@oracle.com apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f)
92112683SJimmy.Vetayases@oracle.com {
92212683SJimmy.Vetayases@oracle.com 	struct autovec *p;
92312683SJimmy.Vetayases@oracle.com 
92412683SJimmy.Vetayases@oracle.com 	for (p = vecp->v_autovect; p; p = p->av_link) {
92512683SJimmy.Vetayases@oracle.com 		if ((p->av_vector == f) && (p->av_intr_id == intr_id)) {
92612683SJimmy.Vetayases@oracle.com 			/* found the handler */
92712683SJimmy.Vetayases@oracle.com 			return (p);
92812683SJimmy.Vetayases@oracle.com 		}
92912683SJimmy.Vetayases@oracle.com 	}
93012683SJimmy.Vetayases@oracle.com 
93112683SJimmy.Vetayases@oracle.com 	return (NULL);
93212683SJimmy.Vetayases@oracle.com }
93312683SJimmy.Vetayases@oracle.com 
93412683SJimmy.Vetayases@oracle.com static apix_vector_t *
apix_find_vector_by_avintr(void * intr_id,avfunc f)93512683SJimmy.Vetayases@oracle.com apix_find_vector_by_avintr(void *intr_id, avfunc f)
93612683SJimmy.Vetayases@oracle.com {
93712683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
93812683SJimmy.Vetayases@oracle.com 	processorid_t n;
93912683SJimmy.Vetayases@oracle.com 	uchar_t v;
94012683SJimmy.Vetayases@oracle.com 
94112683SJimmy.Vetayases@oracle.com 	for (n = 0; n < apic_nproc; n++) {
94212683SJimmy.Vetayases@oracle.com 		if (!apix_is_cpu_enabled(n))
94312683SJimmy.Vetayases@oracle.com 			continue;
94412683SJimmy.Vetayases@oracle.com 
94512683SJimmy.Vetayases@oracle.com 		for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) {
94612683SJimmy.Vetayases@oracle.com 			vecp = xv_vector(n, v);
94712683SJimmy.Vetayases@oracle.com 			if (vecp == NULL ||
94812683SJimmy.Vetayases@oracle.com 			    vecp->v_state <= APIX_STATE_OBSOLETED)
94912683SJimmy.Vetayases@oracle.com 				continue;
95012683SJimmy.Vetayases@oracle.com 
95112683SJimmy.Vetayases@oracle.com 			if (apix_find_av(vecp, intr_id, f) != NULL)
95212683SJimmy.Vetayases@oracle.com 				return (vecp);
95312683SJimmy.Vetayases@oracle.com 		}
95412683SJimmy.Vetayases@oracle.com 	}
95512683SJimmy.Vetayases@oracle.com 
95612683SJimmy.Vetayases@oracle.com 	return (NULL);
95712683SJimmy.Vetayases@oracle.com }
95812683SJimmy.Vetayases@oracle.com 
95912683SJimmy.Vetayases@oracle.com /*
96012683SJimmy.Vetayases@oracle.com  * Add interrupt service routine.
96112683SJimmy.Vetayases@oracle.com  *
96212683SJimmy.Vetayases@oracle.com  * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually
96312683SJimmy.Vetayases@oracle.com  * IRQ no. A vector is then allocated. Otherwise, the vector is already
96412683SJimmy.Vetayases@oracle.com  * allocated. The input argument virt_vect is virtual vector of format
96512683SJimmy.Vetayases@oracle.com  * APIX_VIRTVEC_VECTOR(cpuid, vector).
96612683SJimmy.Vetayases@oracle.com  *
96712683SJimmy.Vetayases@oracle.com  * Return 1 on success, 0 on failure.
96812683SJimmy.Vetayases@oracle.com  */
96912683SJimmy.Vetayases@oracle.com int
apix_add_avintr(void * intr_id,int ipl,avfunc xxintr,char * name,int virt_vect,caddr_t arg1,caddr_t arg2,uint64_t * ticksp,dev_info_t * dip)97012683SJimmy.Vetayases@oracle.com apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name,
97112683SJimmy.Vetayases@oracle.com     int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp,
97212683SJimmy.Vetayases@oracle.com     dev_info_t *dip)
97312683SJimmy.Vetayases@oracle.com {
97412683SJimmy.Vetayases@oracle.com 	int cpuid;
97512683SJimmy.Vetayases@oracle.com 	uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect);
97612683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
97712683SJimmy.Vetayases@oracle.com 
97812683SJimmy.Vetayases@oracle.com 	if (xxintr == NULL) {
97912683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "Attempt to add null for %s "
98012683SJimmy.Vetayases@oracle.com 		    "on vector 0x%x,0x%x", name,
98112683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_CPU(virt_vect),
98212683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
98312683SJimmy.Vetayases@oracle.com 		return (0);
98412683SJimmy.Vetayases@oracle.com 	}
98512683SJimmy.Vetayases@oracle.com 
98612683SJimmy.Vetayases@oracle.com 	if (v >= APIX_IPI_MIN)	/* IPIs */
98712683SJimmy.Vetayases@oracle.com 		return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2));
98812683SJimmy.Vetayases@oracle.com 
98912683SJimmy.Vetayases@oracle.com 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
99012683SJimmy.Vetayases@oracle.com 		int irqno = virt_vect;
99112683SJimmy.Vetayases@oracle.com 		int inum = GET_INTR_INUM(intr_id);
99212683SJimmy.Vetayases@oracle.com 
99312683SJimmy.Vetayases@oracle.com 		/*
99412683SJimmy.Vetayases@oracle.com 		 * Senarios include:
99512683SJimmy.Vetayases@oracle.com 		 * a. add_avintr() is called before irqp initialized (legacy)
99612683SJimmy.Vetayases@oracle.com 		 * b. irqp is initialized, vector is not allocated (fixed)
99712683SJimmy.Vetayases@oracle.com 		 * c. irqp is initialized, vector is allocated (fixed & shared)
99812683SJimmy.Vetayases@oracle.com 		 */
99912683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL)
100012683SJimmy.Vetayases@oracle.com 			return (0);
100112683SJimmy.Vetayases@oracle.com 
100212683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
100312683SJimmy.Vetayases@oracle.com 		v = vecp->v_vector;
100412683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(cpuid, v);
100512683SJimmy.Vetayases@oracle.com 	} else {	/* got virtual vector */
100612683SJimmy.Vetayases@oracle.com 		cpuid = APIX_VIRTVEC_CPU(virt_vect);
100712683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(cpuid, v);
100812683SJimmy.Vetayases@oracle.com 		ASSERT(vecp != NULL);
100912683SJimmy.Vetayases@oracle.com 	}
101012683SJimmy.Vetayases@oracle.com 
101112683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
101212683SJimmy.Vetayases@oracle.com 	if (vecp->v_state <= APIX_STATE_OBSOLETED) {
101312683SJimmy.Vetayases@oracle.com 		vecp = NULL;
101412683SJimmy.Vetayases@oracle.com 
101512683SJimmy.Vetayases@oracle.com 		/*
101612683SJimmy.Vetayases@oracle.com 		 * Basically the allocated but not enabled interrupts
101712683SJimmy.Vetayases@oracle.com 		 * will not get re-targeted. But MSIs in allocated state
101812683SJimmy.Vetayases@oracle.com 		 * could be re-targeted due to group re-targeting.
101912683SJimmy.Vetayases@oracle.com 		 */
102012683SJimmy.Vetayases@oracle.com 		if (intr_id != NULL && dip != NULL) {
102112683SJimmy.Vetayases@oracle.com 			ddi_intr_handle_impl_t *hdlp = intr_id;
102212683SJimmy.Vetayases@oracle.com 			vecp = apix_get_dev_map(dip, hdlp->ih_inum,
102312683SJimmy.Vetayases@oracle.com 			    hdlp->ih_type);
102412683SJimmy.Vetayases@oracle.com 			ASSERT(vecp->v_state == APIX_STATE_ALLOCED);
102512683SJimmy.Vetayases@oracle.com 		}
102612683SJimmy.Vetayases@oracle.com 		if (vecp == NULL) {
102712683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
102812683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x "
102912683SJimmy.Vetayases@oracle.com 			    " for %p to add", cpuid, v, intr_id);
103012683SJimmy.Vetayases@oracle.com 			return (0);
103112683SJimmy.Vetayases@oracle.com 		}
103212683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
103312683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector);
103412683SJimmy.Vetayases@oracle.com 	}
103512683SJimmy.Vetayases@oracle.com 
103612683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
103712683SJimmy.Vetayases@oracle.com 	apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip);
103812683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
103912683SJimmy.Vetayases@oracle.com 
104012683SJimmy.Vetayases@oracle.com 	(void) apix_addspl(virt_vect, ipl, 0, 0);
104112683SJimmy.Vetayases@oracle.com 
104212683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
104312683SJimmy.Vetayases@oracle.com 
104412683SJimmy.Vetayases@oracle.com 	return (1);
104512683SJimmy.Vetayases@oracle.com }
104612683SJimmy.Vetayases@oracle.com 
104712683SJimmy.Vetayases@oracle.com /*
104812683SJimmy.Vetayases@oracle.com  * Remove avintr
104912683SJimmy.Vetayases@oracle.com  *
105012683SJimmy.Vetayases@oracle.com  * For fixed, if it's the last one of shared interrupts, free the vector.
105112683SJimmy.Vetayases@oracle.com  * For msi/x, only disable the interrupt but not free the vector, which
105212683SJimmy.Vetayases@oracle.com  * is freed by PSM_XXX_FREE_XXX.
105312683SJimmy.Vetayases@oracle.com  */
105412683SJimmy.Vetayases@oracle.com void
apix_rem_avintr(void * intr_id,int ipl,avfunc xxintr,int virt_vect)105512683SJimmy.Vetayases@oracle.com apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect)
105612683SJimmy.Vetayases@oracle.com {
105712683SJimmy.Vetayases@oracle.com 	avfunc f;
105812683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
105912683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
106012683SJimmy.Vetayases@oracle.com 	processorid_t cpuid;
106112683SJimmy.Vetayases@oracle.com 
106212683SJimmy.Vetayases@oracle.com 	if ((f = xxintr) == NULL)
106312683SJimmy.Vetayases@oracle.com 		return;
106412683SJimmy.Vetayases@oracle.com 
106512683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
106612683SJimmy.Vetayases@oracle.com 
106712683SJimmy.Vetayases@oracle.com 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
106812683SJimmy.Vetayases@oracle.com 		vecp = apix_intx_get_vector(virt_vect);
106912683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
107012683SJimmy.Vetayases@oracle.com 	} else	/* got virtual vector */
107112683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect),
107212683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
107312683SJimmy.Vetayases@oracle.com 
107412683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
107512683SJimmy.Vetayases@oracle.com 		lock_clear(&apix_lock);
107612683SJimmy.Vetayases@oracle.com 		cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove",
107712683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_CPU(virt_vect),
107812683SJimmy.Vetayases@oracle.com 		    APIX_VIRTVEC_VECTOR(virt_vect));
107912683SJimmy.Vetayases@oracle.com 		return;
108012683SJimmy.Vetayases@oracle.com 	}
108112683SJimmy.Vetayases@oracle.com 
108212683SJimmy.Vetayases@oracle.com 	if (vecp->v_state <= APIX_STATE_OBSOLETED ||
108312683SJimmy.Vetayases@oracle.com 	    ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) {
108412683SJimmy.Vetayases@oracle.com 		/*
108512683SJimmy.Vetayases@oracle.com 		 * It's possible that the interrupt is rebound to a
108612683SJimmy.Vetayases@oracle.com 		 * different cpu before rem_avintr() is called. Search
108712683SJimmy.Vetayases@oracle.com 		 * through all vectors once it happens.
108812683SJimmy.Vetayases@oracle.com 		 */
108912683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_find_vector_by_avintr(intr_id, f))
109012683SJimmy.Vetayases@oracle.com 		    == NULL) {
109112683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
109212683SJimmy.Vetayases@oracle.com 			cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x "
109312683SJimmy.Vetayases@oracle.com 			    "for %p to remove", APIX_VIRTVEC_CPU(virt_vect),
109412683SJimmy.Vetayases@oracle.com 			    APIX_VIRTVEC_VECTOR(virt_vect), intr_id);
109512683SJimmy.Vetayases@oracle.com 			return;
109612683SJimmy.Vetayases@oracle.com 		}
109712683SJimmy.Vetayases@oracle.com 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
109812683SJimmy.Vetayases@oracle.com 		avp = apix_find_av(vecp, intr_id, f);
109912683SJimmy.Vetayases@oracle.com 	}
110012683SJimmy.Vetayases@oracle.com 	cpuid = vecp->v_cpuid;
110112683SJimmy.Vetayases@oracle.com 
110212683SJimmy.Vetayases@oracle.com 	/* disable interrupt */
110312683SJimmy.Vetayases@oracle.com 	(void) apix_delspl(virt_vect, ipl, 0, 0);
110412683SJimmy.Vetayases@oracle.com 
110512683SJimmy.Vetayases@oracle.com 	/* remove ISR entry */
110612683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
110712683SJimmy.Vetayases@oracle.com 	apix_remove_av(vecp, avp);
110812683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
110912683SJimmy.Vetayases@oracle.com 
111012683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
111112683SJimmy.Vetayases@oracle.com }
111212683SJimmy.Vetayases@oracle.com 
111312683SJimmy.Vetayases@oracle.com /*
111412683SJimmy.Vetayases@oracle.com  * Device to vector mapping table
111512683SJimmy.Vetayases@oracle.com  */
111612683SJimmy.Vetayases@oracle.com 
111712683SJimmy.Vetayases@oracle.com static void
apix_clear_dev_map(dev_info_t * dip,int inum,int type)111812683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dev_info_t *dip, int inum, int type)
111912683SJimmy.Vetayases@oracle.com {
112012683SJimmy.Vetayases@oracle.com 	char *name;
112112683SJimmy.Vetayases@oracle.com 	major_t major;
112212683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp, *prev = NULL;
112312683SJimmy.Vetayases@oracle.com 	int found = 0;
112412683SJimmy.Vetayases@oracle.com 
112512683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
112612683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
112712683SJimmy.Vetayases@oracle.com 
112812683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
112912683SJimmy.Vetayases@oracle.com 
113012683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
113112683SJimmy.Vetayases@oracle.com 	    prev = dvp, dvp = dvp->dv_next) {
113212683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
113312683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == type) {
113412683SJimmy.Vetayases@oracle.com 			found++;
113512683SJimmy.Vetayases@oracle.com 			break;
113612683SJimmy.Vetayases@oracle.com 		}
113712683SJimmy.Vetayases@oracle.com 	}
113812683SJimmy.Vetayases@oracle.com 
113912683SJimmy.Vetayases@oracle.com 	if (!found) {
114012683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
114112683SJimmy.Vetayases@oracle.com 		return;
114212683SJimmy.Vetayases@oracle.com 	}
114312683SJimmy.Vetayases@oracle.com 
114412683SJimmy.Vetayases@oracle.com 	if (prev != NULL)
114512683SJimmy.Vetayases@oracle.com 		prev->dv_next = dvp->dv_next;
114612683SJimmy.Vetayases@oracle.com 
114712683SJimmy.Vetayases@oracle.com 	if (apix_dev_vector[major] == dvp)
114812683SJimmy.Vetayases@oracle.com 		apix_dev_vector[major] = dvp->dv_next;
114912683SJimmy.Vetayases@oracle.com 
115012683SJimmy.Vetayases@oracle.com 	dvp->dv_vector->v_devp = NULL;
115112683SJimmy.Vetayases@oracle.com 
115212683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
115312683SJimmy.Vetayases@oracle.com 
115412683SJimmy.Vetayases@oracle.com 	kmem_free(dvp, sizeof (apix_dev_vector_t));
115512683SJimmy.Vetayases@oracle.com }
115612683SJimmy.Vetayases@oracle.com 
115712683SJimmy.Vetayases@oracle.com void
apix_set_dev_map(apix_vector_t * vecp,dev_info_t * dip,int inum)115812683SJimmy.Vetayases@oracle.com apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum)
115912683SJimmy.Vetayases@oracle.com {
116012683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
116112683SJimmy.Vetayases@oracle.com 	char *name;
116212683SJimmy.Vetayases@oracle.com 	major_t major;
116312683SJimmy.Vetayases@oracle.com 	uint32_t found = 0;
116412683SJimmy.Vetayases@oracle.com 
116512683SJimmy.Vetayases@oracle.com 	ASSERT(dip != NULL);
116612683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
116712683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
116812683SJimmy.Vetayases@oracle.com 
116912683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
117012683SJimmy.Vetayases@oracle.com 
117112683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
117212683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
117312683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
117412683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == vecp->v_type) {
117512683SJimmy.Vetayases@oracle.com 			found++;
117612683SJimmy.Vetayases@oracle.com 			break;
117712683SJimmy.Vetayases@oracle.com 		}
117812683SJimmy.Vetayases@oracle.com 	}
117912683SJimmy.Vetayases@oracle.com 
118012683SJimmy.Vetayases@oracle.com 	if (found == 0) {	/* not found */
118112683SJimmy.Vetayases@oracle.com 		dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP);
118212683SJimmy.Vetayases@oracle.com 		dvp->dv_dip = dip;
118312683SJimmy.Vetayases@oracle.com 		dvp->dv_inum = inum;
118412683SJimmy.Vetayases@oracle.com 		dvp->dv_type = vecp->v_type;
118512683SJimmy.Vetayases@oracle.com 
118612683SJimmy.Vetayases@oracle.com 		dvp->dv_next = apix_dev_vector[major];
118712683SJimmy.Vetayases@oracle.com 		apix_dev_vector[major] = dvp;
118812683SJimmy.Vetayases@oracle.com 	}
118912683SJimmy.Vetayases@oracle.com 	dvp->dv_vector = vecp;
119012683SJimmy.Vetayases@oracle.com 	vecp->v_devp = dvp;
119112683SJimmy.Vetayases@oracle.com 
119212683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
119312683SJimmy.Vetayases@oracle.com 
119412683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p "
119512683SJimmy.Vetayases@oracle.com 	    "inum=0x%x  vector=0x%x/0x%x\n",
119612683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, vecp->v_cpuid, vecp->v_vector));
119712683SJimmy.Vetayases@oracle.com }
119812683SJimmy.Vetayases@oracle.com 
119912683SJimmy.Vetayases@oracle.com apix_vector_t *
apix_get_dev_map(dev_info_t * dip,int inum,int type)120012683SJimmy.Vetayases@oracle.com apix_get_dev_map(dev_info_t *dip, int inum, int type)
120112683SJimmy.Vetayases@oracle.com {
120212683SJimmy.Vetayases@oracle.com 	char *name;
120312683SJimmy.Vetayases@oracle.com 	major_t major;
120412683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
120512683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
120612683SJimmy.Vetayases@oracle.com 
120712683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
120812683SJimmy.Vetayases@oracle.com 	if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE)
120912683SJimmy.Vetayases@oracle.com 		return (NULL);
121012683SJimmy.Vetayases@oracle.com 
121112683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
121212683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
121312683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
121412683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
121512683SJimmy.Vetayases@oracle.com 		    dvp->dv_type == type) {
121612683SJimmy.Vetayases@oracle.com 			vecp = dvp->dv_vector;
121712683SJimmy.Vetayases@oracle.com 			mutex_exit(&apix_mutex);
121812683SJimmy.Vetayases@oracle.com 			return (vecp);
121912683SJimmy.Vetayases@oracle.com 		}
122012683SJimmy.Vetayases@oracle.com 	}
122112683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
122212683SJimmy.Vetayases@oracle.com 
122312683SJimmy.Vetayases@oracle.com 	return (NULL);
122412683SJimmy.Vetayases@oracle.com }
122512683SJimmy.Vetayases@oracle.com 
122612683SJimmy.Vetayases@oracle.com /*
122712683SJimmy.Vetayases@oracle.com  * Get minimum inum for specified device, used for MSI
122812683SJimmy.Vetayases@oracle.com  */
122912683SJimmy.Vetayases@oracle.com int
apix_get_min_dev_inum(dev_info_t * dip,int type)123012683SJimmy.Vetayases@oracle.com apix_get_min_dev_inum(dev_info_t *dip, int type)
123112683SJimmy.Vetayases@oracle.com {
123212683SJimmy.Vetayases@oracle.com 	char *name;
123312683SJimmy.Vetayases@oracle.com 	major_t major;
123412683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
123512683SJimmy.Vetayases@oracle.com 	int inum = -1;
123612683SJimmy.Vetayases@oracle.com 
123712683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
123812683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
123912683SJimmy.Vetayases@oracle.com 
124012683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
124112683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
124212683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
124312683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
124412683SJimmy.Vetayases@oracle.com 			if (inum == -1)
124512683SJimmy.Vetayases@oracle.com 				inum = dvp->dv_inum;
124612683SJimmy.Vetayases@oracle.com 			else
124712683SJimmy.Vetayases@oracle.com 				inum = (dvp->dv_inum < inum) ?
124812683SJimmy.Vetayases@oracle.com 				    dvp->dv_inum : inum;
124912683SJimmy.Vetayases@oracle.com 		}
125012683SJimmy.Vetayases@oracle.com 	}
125112683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
125212683SJimmy.Vetayases@oracle.com 
125312683SJimmy.Vetayases@oracle.com 	return (inum);
125412683SJimmy.Vetayases@oracle.com }
125512683SJimmy.Vetayases@oracle.com 
125612683SJimmy.Vetayases@oracle.com int
apix_get_max_dev_inum(dev_info_t * dip,int type)125712683SJimmy.Vetayases@oracle.com apix_get_max_dev_inum(dev_info_t *dip, int type)
125812683SJimmy.Vetayases@oracle.com {
125912683SJimmy.Vetayases@oracle.com 	char *name;
126012683SJimmy.Vetayases@oracle.com 	major_t major;
126112683SJimmy.Vetayases@oracle.com 	apix_dev_vector_t *dvp;
126212683SJimmy.Vetayases@oracle.com 	int inum = -1;
126312683SJimmy.Vetayases@oracle.com 
126412683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
126512683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
126612683SJimmy.Vetayases@oracle.com 
126712683SJimmy.Vetayases@oracle.com 	mutex_enter(&apix_mutex);
126812683SJimmy.Vetayases@oracle.com 	for (dvp = apix_dev_vector[major]; dvp != NULL;
126912683SJimmy.Vetayases@oracle.com 	    dvp = dvp->dv_next) {
127012683SJimmy.Vetayases@oracle.com 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
127112683SJimmy.Vetayases@oracle.com 			if (inum == -1)
127212683SJimmy.Vetayases@oracle.com 				inum = dvp->dv_inum;
127312683SJimmy.Vetayases@oracle.com 			else
127412683SJimmy.Vetayases@oracle.com 				inum = (dvp->dv_inum > inum) ?
127512683SJimmy.Vetayases@oracle.com 				    dvp->dv_inum : inum;
127612683SJimmy.Vetayases@oracle.com 		}
127712683SJimmy.Vetayases@oracle.com 	}
127812683SJimmy.Vetayases@oracle.com 	mutex_exit(&apix_mutex);
127912683SJimmy.Vetayases@oracle.com 
128012683SJimmy.Vetayases@oracle.com 	return (inum);
128112683SJimmy.Vetayases@oracle.com }
128212683SJimmy.Vetayases@oracle.com 
128312683SJimmy.Vetayases@oracle.com /*
128412683SJimmy.Vetayases@oracle.com  * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu
128512683SJimmy.Vetayases@oracle.com  * binding policy
128612683SJimmy.Vetayases@oracle.com  */
128712683SJimmy.Vetayases@oracle.com 
128812683SJimmy.Vetayases@oracle.com static uint32_t
apix_get_dev_binding(dev_info_t * dip)128912683SJimmy.Vetayases@oracle.com apix_get_dev_binding(dev_info_t *dip)
129012683SJimmy.Vetayases@oracle.com {
129112683SJimmy.Vetayases@oracle.com 	major_t major;
129212683SJimmy.Vetayases@oracle.com 	char *name;
129312683SJimmy.Vetayases@oracle.com 	uint32_t cpu = IRQ_UNINIT;
129412683SJimmy.Vetayases@oracle.com 
129512683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
129612683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
129712683SJimmy.Vetayases@oracle.com 	if (major < devcnt) {
129812683SJimmy.Vetayases@oracle.com 		mutex_enter(&apix_mutex);
129912683SJimmy.Vetayases@oracle.com 		cpu = apix_major_to_cpu[major];
130012683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
130112683SJimmy.Vetayases@oracle.com 	}
130212683SJimmy.Vetayases@oracle.com 
130312683SJimmy.Vetayases@oracle.com 	return (cpu);
130412683SJimmy.Vetayases@oracle.com }
130512683SJimmy.Vetayases@oracle.com 
130612683SJimmy.Vetayases@oracle.com static void
apix_set_dev_binding(dev_info_t * dip,uint32_t cpu)130712683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dev_info_t *dip, uint32_t cpu)
130812683SJimmy.Vetayases@oracle.com {
130912683SJimmy.Vetayases@oracle.com 	major_t major;
131012683SJimmy.Vetayases@oracle.com 	char *name;
131112683SJimmy.Vetayases@oracle.com 
131212683SJimmy.Vetayases@oracle.com 	/* setup major to cpu mapping */
131312683SJimmy.Vetayases@oracle.com 	name = ddi_get_name(dip);
131412683SJimmy.Vetayases@oracle.com 	major = ddi_name_to_major(name);
131512683SJimmy.Vetayases@oracle.com 	if (apix_major_to_cpu[major] == IRQ_UNINIT) {
131612683SJimmy.Vetayases@oracle.com 		mutex_enter(&apix_mutex);
131712683SJimmy.Vetayases@oracle.com 		apix_major_to_cpu[major] = cpu;
131812683SJimmy.Vetayases@oracle.com 		mutex_exit(&apix_mutex);
131912683SJimmy.Vetayases@oracle.com 	}
132012683SJimmy.Vetayases@oracle.com }
132112683SJimmy.Vetayases@oracle.com 
132212683SJimmy.Vetayases@oracle.com /*
132312683SJimmy.Vetayases@oracle.com  * return the cpu to which this intr should be bound.
132412683SJimmy.Vetayases@oracle.com  * Check properties or any other mechanism to see if user wants it
132512683SJimmy.Vetayases@oracle.com  * bound to a specific CPU. If so, return the cpu id with high bit set.
132612683SJimmy.Vetayases@oracle.com  * If not, use the policy to choose a cpu and return the id.
132712683SJimmy.Vetayases@oracle.com  */
132812683SJimmy.Vetayases@oracle.com uint32_t
apix_bind_cpu(dev_info_t * dip)132912683SJimmy.Vetayases@oracle.com apix_bind_cpu(dev_info_t *dip)
133012683SJimmy.Vetayases@oracle.com {
133112683SJimmy.Vetayases@oracle.com 	int	instance, instno, prop_len, bind_cpu, count;
133212683SJimmy.Vetayases@oracle.com 	uint_t	i, rc;
133312683SJimmy.Vetayases@oracle.com 	major_t	major;
133412683SJimmy.Vetayases@oracle.com 	char	*name, *drv_name, *prop_val, *cptr;
133512683SJimmy.Vetayases@oracle.com 	char	prop_name[32];
133612683SJimmy.Vetayases@oracle.com 
133712683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
133812683SJimmy.Vetayases@oracle.com 
133912683SJimmy.Vetayases@oracle.com 	if (apic_intr_policy == INTR_LOWEST_PRIORITY) {
134012683SJimmy.Vetayases@oracle.com 		cmn_err(CE_WARN, "apix: unsupported interrupt binding policy "
134112683SJimmy.Vetayases@oracle.com 		    "LOWEST PRIORITY, use ROUND ROBIN instead");
134212683SJimmy.Vetayases@oracle.com 		apic_intr_policy = INTR_ROUND_ROBIN;
134312683SJimmy.Vetayases@oracle.com 	}
134412683SJimmy.Vetayases@oracle.com 
134512683SJimmy.Vetayases@oracle.com 	if (apic_nproc == 1) {
134612683SJimmy.Vetayases@oracle.com 		lock_clear(&apix_lock);
134712683SJimmy.Vetayases@oracle.com 		return (0);
134812683SJimmy.Vetayases@oracle.com 	}
134912683SJimmy.Vetayases@oracle.com 
135012683SJimmy.Vetayases@oracle.com 	drv_name = NULL;
135112683SJimmy.Vetayases@oracle.com 	rc = DDI_PROP_NOT_FOUND;
135212683SJimmy.Vetayases@oracle.com 	major = (major_t)-1;
135312683SJimmy.Vetayases@oracle.com 	if (dip != NULL) {
135412683SJimmy.Vetayases@oracle.com 		name = ddi_get_name(dip);
135512683SJimmy.Vetayases@oracle.com 		major = ddi_name_to_major(name);
135612683SJimmy.Vetayases@oracle.com 		drv_name = ddi_major_to_name(major);
135712683SJimmy.Vetayases@oracle.com 		instance = ddi_get_instance(dip);
135812683SJimmy.Vetayases@oracle.com 		if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
135912683SJimmy.Vetayases@oracle.com 			bind_cpu = apix_get_dev_binding(dip);
136012683SJimmy.Vetayases@oracle.com 			if (bind_cpu != IRQ_UNINIT) {
136112683SJimmy.Vetayases@oracle.com 				lock_clear(&apix_lock);
136212683SJimmy.Vetayases@oracle.com 				return (bind_cpu);
136312683SJimmy.Vetayases@oracle.com 			}
136412683SJimmy.Vetayases@oracle.com 		}
136512683SJimmy.Vetayases@oracle.com 		/*
136612683SJimmy.Vetayases@oracle.com 		 * search for "drvname"_intpt_bind_cpus property first, the
136712683SJimmy.Vetayases@oracle.com 		 * syntax of the property should be "a[,b,c,...]" where
136812683SJimmy.Vetayases@oracle.com 		 * instance 0 binds to cpu a, instance 1 binds to cpu b,
136912683SJimmy.Vetayases@oracle.com 		 * instance 3 binds to cpu c...
137012683SJimmy.Vetayases@oracle.com 		 * ddi_getlongprop() will search /option first, then /
137112683SJimmy.Vetayases@oracle.com 		 * if "drvname"_intpt_bind_cpus doesn't exist, then find
137212683SJimmy.Vetayases@oracle.com 		 * intpt_bind_cpus property.  The syntax is the same, and
137312683SJimmy.Vetayases@oracle.com 		 * it applies to all the devices if its "drvname" specific
137412683SJimmy.Vetayases@oracle.com 		 * property doesn't exist
137512683SJimmy.Vetayases@oracle.com 		 */
137612683SJimmy.Vetayases@oracle.com 		(void) strcpy(prop_name, drv_name);
137712683SJimmy.Vetayases@oracle.com 		(void) strcat(prop_name, "_intpt_bind_cpus");
137812683SJimmy.Vetayases@oracle.com 		rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
137912683SJimmy.Vetayases@oracle.com 		    (caddr_t)&prop_val, &prop_len);
138012683SJimmy.Vetayases@oracle.com 		if (rc != DDI_PROP_SUCCESS) {
138112683SJimmy.Vetayases@oracle.com 			rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
138212683SJimmy.Vetayases@oracle.com 			    "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
138312683SJimmy.Vetayases@oracle.com 		}
138412683SJimmy.Vetayases@oracle.com 	}
138512683SJimmy.Vetayases@oracle.com 	if (rc == DDI_PROP_SUCCESS) {
138612683SJimmy.Vetayases@oracle.com 		for (i = count = 0; i < (prop_len - 1); i++)
138712683SJimmy.Vetayases@oracle.com 			if (prop_val[i] == ',')
138812683SJimmy.Vetayases@oracle.com 				count++;
138912683SJimmy.Vetayases@oracle.com 		if (prop_val[i-1] != ',')
139012683SJimmy.Vetayases@oracle.com 			count++;
139112683SJimmy.Vetayases@oracle.com 		/*
139212683SJimmy.Vetayases@oracle.com 		 * if somehow the binding instances defined in the
139312683SJimmy.Vetayases@oracle.com 		 * property are not enough for this instno., then
139412683SJimmy.Vetayases@oracle.com 		 * reuse the pattern for the next instance until
139512683SJimmy.Vetayases@oracle.com 		 * it reaches the requested instno
139612683SJimmy.Vetayases@oracle.com 		 */
139712683SJimmy.Vetayases@oracle.com 		instno = instance % count;
139812683SJimmy.Vetayases@oracle.com 		i = 0;
139912683SJimmy.Vetayases@oracle.com 		cptr = prop_val;
140012683SJimmy.Vetayases@oracle.com 		while (i < instno)
140112683SJimmy.Vetayases@oracle.com 			if (*cptr++ == ',')
140212683SJimmy.Vetayases@oracle.com 				i++;
140312683SJimmy.Vetayases@oracle.com 		bind_cpu = stoi(&cptr);
140412683SJimmy.Vetayases@oracle.com 		kmem_free(prop_val, prop_len);
140512683SJimmy.Vetayases@oracle.com 		/* if specific cpu is bogus, then default to cpu 0 */
140612683SJimmy.Vetayases@oracle.com 		if (bind_cpu >= apic_nproc) {
140712683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present",
140812683SJimmy.Vetayases@oracle.com 			    prop_name, prop_val, bind_cpu);
140912683SJimmy.Vetayases@oracle.com 			bind_cpu = 0;
141012683SJimmy.Vetayases@oracle.com 		} else {
141112683SJimmy.Vetayases@oracle.com 			/* indicate that we are bound at user request */
141212683SJimmy.Vetayases@oracle.com 			bind_cpu |= IRQ_USER_BOUND;
141312683SJimmy.Vetayases@oracle.com 		}
141412683SJimmy.Vetayases@oracle.com 		/*
141512683SJimmy.Vetayases@oracle.com 		 * no need to check apic_cpus[].aci_status, if specific cpu is
141612683SJimmy.Vetayases@oracle.com 		 * not up, then post_cpu_start will handle it.
141712683SJimmy.Vetayases@oracle.com 		 */
141812683SJimmy.Vetayases@oracle.com 	} else {
141912683SJimmy.Vetayases@oracle.com 		bind_cpu = apic_get_next_bind_cpu();
142012683SJimmy.Vetayases@oracle.com 	}
142112683SJimmy.Vetayases@oracle.com 
142212683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
142312683SJimmy.Vetayases@oracle.com 
142412683SJimmy.Vetayases@oracle.com 	return ((uint32_t)bind_cpu);
142512683SJimmy.Vetayases@oracle.com }
142612683SJimmy.Vetayases@oracle.com 
142712683SJimmy.Vetayases@oracle.com static boolean_t
apix_is_cpu_enabled(processorid_t cpuid)142812683SJimmy.Vetayases@oracle.com apix_is_cpu_enabled(processorid_t cpuid)
142912683SJimmy.Vetayases@oracle.com {
143012683SJimmy.Vetayases@oracle.com 	apic_cpus_info_t *cpu_infop;
143112683SJimmy.Vetayases@oracle.com 
143212683SJimmy.Vetayases@oracle.com 	cpu_infop = &apic_cpus[cpuid];
143312683SJimmy.Vetayases@oracle.com 
143412683SJimmy.Vetayases@oracle.com 	if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0)
143512683SJimmy.Vetayases@oracle.com 		return (B_FALSE);
143612683SJimmy.Vetayases@oracle.com 
143712683SJimmy.Vetayases@oracle.com 	return (B_TRUE);
143812683SJimmy.Vetayases@oracle.com }
143912683SJimmy.Vetayases@oracle.com 
144012683SJimmy.Vetayases@oracle.com /*
144112683SJimmy.Vetayases@oracle.com  * Must be called with apix_lock held. This function can be
144212683SJimmy.Vetayases@oracle.com  * called from above lock level by apix_intr_redistribute().
144312683SJimmy.Vetayases@oracle.com  *
144412683SJimmy.Vetayases@oracle.com  * Arguments:
144512683SJimmy.Vetayases@oracle.com  *    vecp  : Vector to be rebound
144612683SJimmy.Vetayases@oracle.com  *    tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid.
144712683SJimmy.Vetayases@oracle.com  *    count : Number of continuous vectors
144812683SJimmy.Vetayases@oracle.com  *
144912683SJimmy.Vetayases@oracle.com  * Return new vector being bound to
145012683SJimmy.Vetayases@oracle.com  */
145112683SJimmy.Vetayases@oracle.com apix_vector_t *
apix_rebind(apix_vector_t * vecp,processorid_t newcpu,int count)145212683SJimmy.Vetayases@oracle.com apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count)
145312683SJimmy.Vetayases@oracle.com {
145412683SJimmy.Vetayases@oracle.com 	apix_vector_t *newp, *oldp;
145512683SJimmy.Vetayases@oracle.com 	processorid_t oldcpu = vecp->v_cpuid;
145612683SJimmy.Vetayases@oracle.com 	uchar_t newvec, oldvec = vecp->v_vector;
145712683SJimmy.Vetayases@oracle.com 	int i;
145812683SJimmy.Vetayases@oracle.com 
145912683SJimmy.Vetayases@oracle.com 	ASSERT(LOCK_HELD(&apix_lock) && count > 0);
146012683SJimmy.Vetayases@oracle.com 
146112683SJimmy.Vetayases@oracle.com 	if (!apix_is_cpu_enabled(newcpu))
146212683SJimmy.Vetayases@oracle.com 		return (NULL);
146312683SJimmy.Vetayases@oracle.com 
146412683SJimmy.Vetayases@oracle.com 	if (vecp->v_cpuid == newcpu) 	/* rebind to the same cpu */
146512683SJimmy.Vetayases@oracle.com 		return (vecp);
146612683SJimmy.Vetayases@oracle.com 
146712683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(oldcpu);
146812683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(newcpu);
146912683SJimmy.Vetayases@oracle.com 
147012683SJimmy.Vetayases@oracle.com 	/* allocate vector */
147112683SJimmy.Vetayases@oracle.com 	if (count == 1)
147212683SJimmy.Vetayases@oracle.com 		newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type);
147312683SJimmy.Vetayases@oracle.com 	else {
147412683SJimmy.Vetayases@oracle.com 		ASSERT(vecp->v_type == APIX_TYPE_MSI);
147512683SJimmy.Vetayases@oracle.com 		newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count,
147612683SJimmy.Vetayases@oracle.com 		    vecp->v_type);
147712683SJimmy.Vetayases@oracle.com 	}
147812683SJimmy.Vetayases@oracle.com 	if (newp == NULL) {
147912683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(newcpu);
148012683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
148112683SJimmy.Vetayases@oracle.com 		return (NULL);
148212683SJimmy.Vetayases@oracle.com 	}
148312683SJimmy.Vetayases@oracle.com 
148412683SJimmy.Vetayases@oracle.com 	newvec = newp->v_vector;
148512683SJimmy.Vetayases@oracle.com 	apix_dup_vectors(vecp, newp, count);
148612683SJimmy.Vetayases@oracle.com 
148712683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(newcpu);
148812683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(oldcpu);
148912683SJimmy.Vetayases@oracle.com 
149012683SJimmy.Vetayases@oracle.com 	if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {
149112683SJimmy.Vetayases@oracle.com 		ASSERT(count == 1);
149212683SJimmy.Vetayases@oracle.com 		if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) {
149312683SJimmy.Vetayases@oracle.com 			struct autovec *avp;
149412683SJimmy.Vetayases@oracle.com 			int inum;
149512683SJimmy.Vetayases@oracle.com 
149612683SJimmy.Vetayases@oracle.com 			/* undo duplication */
149712683SJimmy.Vetayases@oracle.com 			APIX_ENTER_CPU_LOCK(oldcpu);
149812683SJimmy.Vetayases@oracle.com 			APIX_ENTER_CPU_LOCK(newcpu);
149912683SJimmy.Vetayases@oracle.com 			for (avp = newp->v_autovect; avp != NULL;
150012683SJimmy.Vetayases@oracle.com 			    avp = avp->av_link) {
150112683SJimmy.Vetayases@oracle.com 				if (avp->av_dip != NULL) {
150212683SJimmy.Vetayases@oracle.com 					inum = GET_INTR_INUM(avp->av_intr_id);
150312683SJimmy.Vetayases@oracle.com 					apix_set_dev_map(vecp, avp->av_dip,
150412683SJimmy.Vetayases@oracle.com 					    inum);
150512683SJimmy.Vetayases@oracle.com 				}
150612683SJimmy.Vetayases@oracle.com 				apix_remove_av(newp, avp);
150712683SJimmy.Vetayases@oracle.com 			}
150812683SJimmy.Vetayases@oracle.com 			apix_cleanup_vector(newp);
150912683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(newcpu);
151012683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(oldcpu);
151112683SJimmy.Vetayases@oracle.com 			APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed "
151212683SJimmy.Vetayases@oracle.com 			    "interrupt 0x%x to cpu %d failed\n",
151312683SJimmy.Vetayases@oracle.com 			    vecp->v_inum, newcpu));
151412683SJimmy.Vetayases@oracle.com 			return (NULL);
151512683SJimmy.Vetayases@oracle.com 		}
151612683SJimmy.Vetayases@oracle.com 
151712683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(oldcpu);
151812683SJimmy.Vetayases@oracle.com 		(void) apix_obsolete_vector(vecp);
151912683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
152012683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt"
152112683SJimmy.Vetayases@oracle.com 		    " 0x%x/0x%x to 0x%x/0x%x\n",
152212683SJimmy.Vetayases@oracle.com 		    oldcpu, oldvec, newcpu, newvec));
152312683SJimmy.Vetayases@oracle.com 		return (newp);
152412683SJimmy.Vetayases@oracle.com 	}
152512683SJimmy.Vetayases@oracle.com 
152612683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
152712683SJimmy.Vetayases@oracle.com 		oldp = xv_vector(oldcpu, oldvec + i);
152812683SJimmy.Vetayases@oracle.com 		newp = xv_vector(newcpu, newvec + i);
152912683SJimmy.Vetayases@oracle.com 
153012683SJimmy.Vetayases@oracle.com 		if (newp->v_share > 0) {
153112683SJimmy.Vetayases@oracle.com 			APIX_SET_REBIND_INFO(oldp, newp);
153212683SJimmy.Vetayases@oracle.com 
153312683SJimmy.Vetayases@oracle.com 			apix_enable_vector(newp);
153412683SJimmy.Vetayases@oracle.com 
153512683SJimmy.Vetayases@oracle.com 			APIX_CLR_REBIND_INFO();
153612683SJimmy.Vetayases@oracle.com 		}
153712683SJimmy.Vetayases@oracle.com 
153812683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(oldcpu);
153912683SJimmy.Vetayases@oracle.com 		(void) apix_obsolete_vector(oldp);
154012683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(oldcpu);
154112683SJimmy.Vetayases@oracle.com 	}
154212683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x "
154312683SJimmy.Vetayases@oracle.com 	    "to 0x%x/0x%x, count=%d\n",
154412683SJimmy.Vetayases@oracle.com 	    oldcpu, oldvec, newcpu, newvec, count));
154512683SJimmy.Vetayases@oracle.com 
154612683SJimmy.Vetayases@oracle.com 	return (xv_vector(newcpu, newvec));
154712683SJimmy.Vetayases@oracle.com }
154812683SJimmy.Vetayases@oracle.com 
154912683SJimmy.Vetayases@oracle.com /*
155012683SJimmy.Vetayases@oracle.com  * Senarios include:
155112683SJimmy.Vetayases@oracle.com  * a. add_avintr() is called before irqp initialized (legacy)
155212683SJimmy.Vetayases@oracle.com  * b. irqp is initialized, vector is not allocated (fixed interrupts)
155312683SJimmy.Vetayases@oracle.com  * c. irqp is initialized, vector is allocated (shared interrupts)
155412683SJimmy.Vetayases@oracle.com  */
155512683SJimmy.Vetayases@oracle.com apix_vector_t *
apix_alloc_intx(dev_info_t * dip,int inum,int irqno)155612683SJimmy.Vetayases@oracle.com apix_alloc_intx(dev_info_t *dip, int inum, int irqno)
155712683SJimmy.Vetayases@oracle.com {
155812683SJimmy.Vetayases@oracle.com 	apic_irq_t *irqp;
155912683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
156012683SJimmy.Vetayases@oracle.com 
156112683SJimmy.Vetayases@oracle.com 	/*
156212683SJimmy.Vetayases@oracle.com 	 * Allocate IRQ. Caller is later responsible for the
156312683SJimmy.Vetayases@oracle.com 	 * initialization
156412683SJimmy.Vetayases@oracle.com 	 */
156512683SJimmy.Vetayases@oracle.com 	mutex_enter(&airq_mutex);
156612683SJimmy.Vetayases@oracle.com 	if ((irqp = apic_irq_table[irqno]) == NULL) {
156712683SJimmy.Vetayases@oracle.com 		/* allocate irq */
156812683SJimmy.Vetayases@oracle.com 		irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
156912683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = FREE_INDEX;
157012683SJimmy.Vetayases@oracle.com 		apic_irq_table[irqno] = irqp;
157112683SJimmy.Vetayases@oracle.com 	}
157212683SJimmy.Vetayases@oracle.com 	if (irqp->airq_mps_intr_index == FREE_INDEX) {
157312683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = DEFAULT_INDEX;
157412683SJimmy.Vetayases@oracle.com 		irqp->airq_cpu = IRQ_UNINIT;
157512683SJimmy.Vetayases@oracle.com 		irqp->airq_origirq = (uchar_t)irqno;
157612683SJimmy.Vetayases@oracle.com 	}
157712683SJimmy.Vetayases@oracle.com 
157812683SJimmy.Vetayases@oracle.com 	mutex_exit(&airq_mutex);
157912683SJimmy.Vetayases@oracle.com 
158012683SJimmy.Vetayases@oracle.com 	/*
158112683SJimmy.Vetayases@oracle.com 	 * allocate vector
158212683SJimmy.Vetayases@oracle.com 	 */
158312683SJimmy.Vetayases@oracle.com 	if (irqp->airq_cpu == IRQ_UNINIT) {
158412683SJimmy.Vetayases@oracle.com 		uint32_t bindcpu, cpuid;
158512683SJimmy.Vetayases@oracle.com 
158612683SJimmy.Vetayases@oracle.com 		/* select cpu by system policy */
158712683SJimmy.Vetayases@oracle.com 		bindcpu = apix_bind_cpu(dip);
158812683SJimmy.Vetayases@oracle.com 		cpuid = bindcpu & ~IRQ_USER_BOUND;
158912683SJimmy.Vetayases@oracle.com 
159012683SJimmy.Vetayases@oracle.com 		/* allocate vector */
159112683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpuid);
159212683SJimmy.Vetayases@oracle.com 
159312683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum,
159412683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_FIXED)) == NULL) {
159512683SJimmy.Vetayases@oracle.com 			cmn_err(CE_WARN, "No interrupt vector for irq %x",
159612683SJimmy.Vetayases@oracle.com 			    irqno);
159712683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(cpuid);
159812683SJimmy.Vetayases@oracle.com 			return (NULL);
159912683SJimmy.Vetayases@oracle.com 		}
160012683SJimmy.Vetayases@oracle.com 		vecp->v_inum = irqno;
160112683SJimmy.Vetayases@oracle.com 		vecp->v_flags |= APIX_VECT_MASKABLE;
160212683SJimmy.Vetayases@oracle.com 
160312683SJimmy.Vetayases@oracle.com 		apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector);
160412683SJimmy.Vetayases@oracle.com 
160512683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
160612683SJimmy.Vetayases@oracle.com 	} else {
160712683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
160812683SJimmy.Vetayases@oracle.com 		ASSERT(!IS_VECT_FREE(vecp));
160912683SJimmy.Vetayases@oracle.com 
161012683SJimmy.Vetayases@oracle.com 		if (dip != NULL)
161112683SJimmy.Vetayases@oracle.com 			apix_set_dev_map(vecp, dip, inum);
161212683SJimmy.Vetayases@oracle.com 	}
161312683SJimmy.Vetayases@oracle.com 
161412683SJimmy.Vetayases@oracle.com 	if ((dip != NULL) &&
161512683SJimmy.Vetayases@oracle.com 	    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
161612683SJimmy.Vetayases@oracle.com 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
161712683SJimmy.Vetayases@oracle.com 		apix_set_dev_binding(dip, vecp->v_cpuid);
161812683SJimmy.Vetayases@oracle.com 
161912683SJimmy.Vetayases@oracle.com 	apix_dprint_vector(vecp, dip, 1);
162012683SJimmy.Vetayases@oracle.com 
162112683SJimmy.Vetayases@oracle.com 	return (vecp);
162212683SJimmy.Vetayases@oracle.com }
162312683SJimmy.Vetayases@oracle.com 
162412683SJimmy.Vetayases@oracle.com int
apix_alloc_msi(dev_info_t * dip,int inum,int count,int behavior)162512683SJimmy.Vetayases@oracle.com apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior)
162612683SJimmy.Vetayases@oracle.com {
162712683SJimmy.Vetayases@oracle.com 	int i, cap_ptr, rcount = count;
162812683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
162912683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu, cpuid;
163012683SJimmy.Vetayases@oracle.com 	ushort_t msi_ctrl;
163112683SJimmy.Vetayases@oracle.com 	ddi_acc_handle_t handle;
163212683SJimmy.Vetayases@oracle.com 
163312683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p "
163412683SJimmy.Vetayases@oracle.com 	    "inum=0x%x  count=0x%x behavior=%d\n",
163512683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, count, behavior));
163612683SJimmy.Vetayases@oracle.com 
163712683SJimmy.Vetayases@oracle.com 	if (count > 1) {
163812683SJimmy.Vetayases@oracle.com 		if (behavior == DDI_INTR_ALLOC_STRICT &&
163912683SJimmy.Vetayases@oracle.com 		    apic_multi_msi_enable == 0)
164012683SJimmy.Vetayases@oracle.com 			return (0);
164112683SJimmy.Vetayases@oracle.com 		if (apic_multi_msi_enable == 0)
164212683SJimmy.Vetayases@oracle.com 			count = 1;
164312683SJimmy.Vetayases@oracle.com 	}
164412683SJimmy.Vetayases@oracle.com 
164512683SJimmy.Vetayases@oracle.com 	/* Check whether it supports per-vector masking */
164612683SJimmy.Vetayases@oracle.com 	cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
164712683SJimmy.Vetayases@oracle.com 	handle = i_ddi_get_pci_config_handle(dip);
164812683SJimmy.Vetayases@oracle.com 	msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
164912683SJimmy.Vetayases@oracle.com 
165012683SJimmy.Vetayases@oracle.com 	/* bind to cpu */
165112683SJimmy.Vetayases@oracle.com 	bindcpu = apix_bind_cpu(dip);
165212683SJimmy.Vetayases@oracle.com 	cpuid = bindcpu & ~IRQ_USER_BOUND;
165312683SJimmy.Vetayases@oracle.com 
165412683SJimmy.Vetayases@oracle.com 	/* if not ISP2, then round it down */
165512683SJimmy.Vetayases@oracle.com 	if (!ISP2(rcount))
165612683SJimmy.Vetayases@oracle.com 		rcount = 1 << (highbit(rcount) - 1);
165712683SJimmy.Vetayases@oracle.com 
165812683SJimmy.Vetayases@oracle.com 	APIX_ENTER_CPU_LOCK(cpuid);
165912683SJimmy.Vetayases@oracle.com 	for (vecp = NULL; rcount > 0; rcount >>= 1) {
166012683SJimmy.Vetayases@oracle.com 		vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount,
166112683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_MSI);
166212683SJimmy.Vetayases@oracle.com 		if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT)
166312683SJimmy.Vetayases@oracle.com 			break;
166412683SJimmy.Vetayases@oracle.com 	}
166512683SJimmy.Vetayases@oracle.com 	for (i = 0; vecp && i < rcount; i++)
166612683SJimmy.Vetayases@oracle.com 		xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |=
166712683SJimmy.Vetayases@oracle.com 		    (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0;
166812683SJimmy.Vetayases@oracle.com 	APIX_LEAVE_CPU_LOCK(cpuid);
166912683SJimmy.Vetayases@oracle.com 	if (vecp == NULL) {
167012683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(INTR, (CE_CONT,
167112683SJimmy.Vetayases@oracle.com 		    "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n",
167212683SJimmy.Vetayases@oracle.com 		    count, bindcpu));
167312683SJimmy.Vetayases@oracle.com 		return (0);
167412683SJimmy.Vetayases@oracle.com 	}
167512683SJimmy.Vetayases@oracle.com 
167612683SJimmy.Vetayases@oracle.com 	/* major to cpu binding */
167712683SJimmy.Vetayases@oracle.com 	if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
167812683SJimmy.Vetayases@oracle.com 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
167912683SJimmy.Vetayases@oracle.com 		apix_set_dev_binding(dip, vecp->v_cpuid);
168012683SJimmy.Vetayases@oracle.com 
168112683SJimmy.Vetayases@oracle.com 	apix_dprint_vector(vecp, dip, rcount);
168212683SJimmy.Vetayases@oracle.com 
168312683SJimmy.Vetayases@oracle.com 	return (rcount);
168412683SJimmy.Vetayases@oracle.com }
168512683SJimmy.Vetayases@oracle.com 
168612683SJimmy.Vetayases@oracle.com int
apix_alloc_msix(dev_info_t * dip,int inum,int count,int behavior)168712683SJimmy.Vetayases@oracle.com apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior)
168812683SJimmy.Vetayases@oracle.com {
168912683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
169012683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu, cpuid;
169112683SJimmy.Vetayases@oracle.com 	int i;
169212683SJimmy.Vetayases@oracle.com 
169312683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++) {
169412683SJimmy.Vetayases@oracle.com 		/* select cpu by system policy */
169512683SJimmy.Vetayases@oracle.com 		bindcpu = apix_bind_cpu(dip);
169612683SJimmy.Vetayases@oracle.com 		cpuid = bindcpu & ~IRQ_USER_BOUND;
169712683SJimmy.Vetayases@oracle.com 
169812683SJimmy.Vetayases@oracle.com 		/* allocate vector */
169912683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(cpuid);
170012683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i,
170112683SJimmy.Vetayases@oracle.com 		    APIX_TYPE_MSIX)) == NULL) {
170212683SJimmy.Vetayases@oracle.com 			APIX_LEAVE_CPU_LOCK(cpuid);
170312683SJimmy.Vetayases@oracle.com 			APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: "
170412683SJimmy.Vetayases@oracle.com 			    "allocate msix for device dip=%p, inum=%d on"
170512683SJimmy.Vetayases@oracle.com 			    " cpu %d failed", (void *)dip, inum + i, bindcpu));
170612683SJimmy.Vetayases@oracle.com 			break;
170712683SJimmy.Vetayases@oracle.com 		}
170812683SJimmy.Vetayases@oracle.com 		vecp->v_flags |= APIX_VECT_MASKABLE;
170912683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
171012683SJimmy.Vetayases@oracle.com 
171112683SJimmy.Vetayases@oracle.com 		/* major to cpu mapping */
171212683SJimmy.Vetayases@oracle.com 		if ((i == 0) &&
171312683SJimmy.Vetayases@oracle.com 		    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
171412683SJimmy.Vetayases@oracle.com 		    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
171512683SJimmy.Vetayases@oracle.com 			apix_set_dev_binding(dip, vecp->v_cpuid);
171612683SJimmy.Vetayases@oracle.com 
171712683SJimmy.Vetayases@oracle.com 		apix_dprint_vector(vecp, dip, 1);
171812683SJimmy.Vetayases@oracle.com 	}
171912683SJimmy.Vetayases@oracle.com 
172012683SJimmy.Vetayases@oracle.com 	if (i < count && behavior == DDI_INTR_ALLOC_STRICT) {
172112683SJimmy.Vetayases@oracle.com 		APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: "
172212683SJimmy.Vetayases@oracle.com 		    "strictly allocate %d vectors failed, got %d\n",
172312683SJimmy.Vetayases@oracle.com 		    count, i));
172412683SJimmy.Vetayases@oracle.com 		apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX);
172512683SJimmy.Vetayases@oracle.com 		i = 0;
172612683SJimmy.Vetayases@oracle.com 	}
172712683SJimmy.Vetayases@oracle.com 
172812683SJimmy.Vetayases@oracle.com 	return (i);
172912683SJimmy.Vetayases@oracle.com }
173012683SJimmy.Vetayases@oracle.com 
173112683SJimmy.Vetayases@oracle.com /*
173212683SJimmy.Vetayases@oracle.com  * A rollback free for vectors allocated by apix_alloc_xxx().
173312683SJimmy.Vetayases@oracle.com  */
173412683SJimmy.Vetayases@oracle.com void
apix_free_vectors(dev_info_t * dip,int inum,int count,int type)173512683SJimmy.Vetayases@oracle.com apix_free_vectors(dev_info_t *dip, int inum, int count, int type)
173612683SJimmy.Vetayases@oracle.com {
173712683SJimmy.Vetayases@oracle.com 	int i, cpuid;
173812683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
173912683SJimmy.Vetayases@oracle.com 
174012683SJimmy.Vetayases@oracle.com 	DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x "
174112683SJimmy.Vetayases@oracle.com 	    "count: %x type: %x\n",
174212683SJimmy.Vetayases@oracle.com 	    (void *)dip, inum, count, type));
174312683SJimmy.Vetayases@oracle.com 
174412683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
174512683SJimmy.Vetayases@oracle.com 
174612683SJimmy.Vetayases@oracle.com 	for (i = 0; i < count; i++, inum++) {
174712683SJimmy.Vetayases@oracle.com 		if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) {
174812683SJimmy.Vetayases@oracle.com 			lock_clear(&apix_lock);
174912683SJimmy.Vetayases@oracle.com 			DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
175012683SJimmy.Vetayases@oracle.com 			    "dip=0x%p inum=0x%x type=0x%x apix_find_intr() "
175112683SJimmy.Vetayases@oracle.com 			    "failed\n", (void *)dip, inum, type));
175212683SJimmy.Vetayases@oracle.com 			continue;
175312683SJimmy.Vetayases@oracle.com 		}
175412683SJimmy.Vetayases@oracle.com 
175512683SJimmy.Vetayases@oracle.com 		APIX_ENTER_CPU_LOCK(vecp->v_cpuid);
175612683SJimmy.Vetayases@oracle.com 		cpuid = vecp->v_cpuid;
175712683SJimmy.Vetayases@oracle.com 
175812683SJimmy.Vetayases@oracle.com 		DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
175912683SJimmy.Vetayases@oracle.com 		    "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n",
176012683SJimmy.Vetayases@oracle.com 		    (void *)dip, inum, type, vecp->v_vector, vecp->v_share));
176112683SJimmy.Vetayases@oracle.com 
176212683SJimmy.Vetayases@oracle.com 		/* tear down device interrupt to vector mapping */
176312683SJimmy.Vetayases@oracle.com 		apix_clear_dev_map(dip, inum, type);
176412683SJimmy.Vetayases@oracle.com 
176512683SJimmy.Vetayases@oracle.com 		if (vecp->v_type == APIX_TYPE_FIXED) {
176612683SJimmy.Vetayases@oracle.com 			if (vecp->v_share > 0) {	/* share IRQ line */
176712683SJimmy.Vetayases@oracle.com 				APIX_LEAVE_CPU_LOCK(cpuid);
176812683SJimmy.Vetayases@oracle.com 				continue;
176912683SJimmy.Vetayases@oracle.com 			}
177012683SJimmy.Vetayases@oracle.com 
177112683SJimmy.Vetayases@oracle.com 			/* Free apic_irq_table entry */
177212683SJimmy.Vetayases@oracle.com 			apix_intx_free(vecp->v_inum);
177312683SJimmy.Vetayases@oracle.com 		}
177412683SJimmy.Vetayases@oracle.com 
177512683SJimmy.Vetayases@oracle.com 		/* free vector */
177612683SJimmy.Vetayases@oracle.com 		apix_cleanup_vector(vecp);
177712683SJimmy.Vetayases@oracle.com 
177812683SJimmy.Vetayases@oracle.com 		APIX_LEAVE_CPU_LOCK(cpuid);
177912683SJimmy.Vetayases@oracle.com 	}
178012683SJimmy.Vetayases@oracle.com 
178112683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
178212683SJimmy.Vetayases@oracle.com }
178312683SJimmy.Vetayases@oracle.com 
178412683SJimmy.Vetayases@oracle.com /*
178512683SJimmy.Vetayases@oracle.com  * Must be called with apix_lock held
178612683SJimmy.Vetayases@oracle.com  */
178712683SJimmy.Vetayases@oracle.com apix_vector_t *
apix_setup_io_intr(apix_vector_t * vecp)178812683SJimmy.Vetayases@oracle.com apix_setup_io_intr(apix_vector_t *vecp)
178912683SJimmy.Vetayases@oracle.com {
179012683SJimmy.Vetayases@oracle.com 	processorid_t bindcpu;
179112683SJimmy.Vetayases@oracle.com 	int ret;
179212683SJimmy.Vetayases@oracle.com 
179312683SJimmy.Vetayases@oracle.com 	ASSERT(LOCK_HELD(&apix_lock));
179412683SJimmy.Vetayases@oracle.com 
179512683SJimmy.Vetayases@oracle.com 	/*
179612683SJimmy.Vetayases@oracle.com 	 * Interrupts are enabled on the CPU, programme IOAPIC RDT
179712683SJimmy.Vetayases@oracle.com 	 * entry or MSI/X address/data to enable the interrupt.
179812683SJimmy.Vetayases@oracle.com 	 */
179912683SJimmy.Vetayases@oracle.com 	if (apix_is_cpu_enabled(vecp->v_cpuid)) {
180012683SJimmy.Vetayases@oracle.com 		apix_enable_vector(vecp);
180112683SJimmy.Vetayases@oracle.com 		return (vecp);
180212683SJimmy.Vetayases@oracle.com 	}
180312683SJimmy.Vetayases@oracle.com 
180412683SJimmy.Vetayases@oracle.com 	/*
180512683SJimmy.Vetayases@oracle.com 	 * CPU is not up or interrupts are disabled. Fall back to the
180612683SJimmy.Vetayases@oracle.com 	 * first avialable CPU.
180712683SJimmy.Vetayases@oracle.com 	 */
180812683SJimmy.Vetayases@oracle.com 	bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE);
180912683SJimmy.Vetayases@oracle.com 
181012683SJimmy.Vetayases@oracle.com 	if (vecp->v_type == APIX_TYPE_MSI)
181112683SJimmy.Vetayases@oracle.com 		return (apix_grp_set_cpu(vecp, bindcpu, &ret));
181212683SJimmy.Vetayases@oracle.com 
181312683SJimmy.Vetayases@oracle.com 	return (apix_set_cpu(vecp, bindcpu, &ret));
181412683SJimmy.Vetayases@oracle.com }
181512683SJimmy.Vetayases@oracle.com 
181612683SJimmy.Vetayases@oracle.com /*
181712683SJimmy.Vetayases@oracle.com  * For interrupts which call add_avintr() before apic is initialized.
181812683SJimmy.Vetayases@oracle.com  * ioapix_setup_intr() will
181912683SJimmy.Vetayases@oracle.com  *   - allocate vector
182012683SJimmy.Vetayases@oracle.com  *   - copy over ISR
182112683SJimmy.Vetayases@oracle.com  */
182212683SJimmy.Vetayases@oracle.com static void
ioapix_setup_intr(int irqno,iflag_t * flagp)182312683SJimmy.Vetayases@oracle.com ioapix_setup_intr(int irqno, iflag_t *flagp)
182412683SJimmy.Vetayases@oracle.com {
182512683SJimmy.Vetayases@oracle.com 	extern struct av_head autovect[];
182612683SJimmy.Vetayases@oracle.com 	apix_vector_t *vecp;
182712683SJimmy.Vetayases@oracle.com 	apic_irq_t *irqp;
182812683SJimmy.Vetayases@oracle.com 	uchar_t ioapicindex, ipin;
182912683SJimmy.Vetayases@oracle.com 	ulong_t iflag;
183012683SJimmy.Vetayases@oracle.com 	struct autovec *avp;
183112683SJimmy.Vetayases@oracle.com 
183212683SJimmy.Vetayases@oracle.com 	irqp = apic_irq_table[irqno];
183312683SJimmy.Vetayases@oracle.com 	ioapicindex = acpi_find_ioapic(irqno);
183412683SJimmy.Vetayases@oracle.com 	ASSERT(ioapicindex != 0xFF);
183512683SJimmy.Vetayases@oracle.com 	ipin = irqno - apic_io_vectbase[ioapicindex];
183612683SJimmy.Vetayases@oracle.com 
183712683SJimmy.Vetayases@oracle.com 	if ((irqp != NULL) && (irqp->airq_mps_intr_index == ACPI_INDEX)) {
183812683SJimmy.Vetayases@oracle.com 		ASSERT(irqp->airq_intin_no == ipin &&
183912683SJimmy.Vetayases@oracle.com 		    irqp->airq_ioapicindex == ioapicindex);
184012683SJimmy.Vetayases@oracle.com 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
184112683SJimmy.Vetayases@oracle.com 		ASSERT(!IS_VECT_FREE(vecp));
184212683SJimmy.Vetayases@oracle.com 	} else {
184312683SJimmy.Vetayases@oracle.com 		vecp = apix_alloc_intx(NULL, 0, irqno);
184412683SJimmy.Vetayases@oracle.com 
184512683SJimmy.Vetayases@oracle.com 		irqp = apic_irq_table[irqno];
184612683SJimmy.Vetayases@oracle.com 		irqp->airq_mps_intr_index = ACPI_INDEX;
184712683SJimmy.Vetayases@oracle.com 		irqp->airq_ioapicindex = ioapicindex;
184812683SJimmy.Vetayases@oracle.com 		irqp->airq_intin_no = ipin;
184912683SJimmy.Vetayases@oracle.com 		irqp->airq_iflag = *flagp;
185012683SJimmy.Vetayases@oracle.com 		irqp->airq_share++;
185112683SJimmy.Vetayases@oracle.com 		apic_record_rdt_entry(irqp, irqno);
185212683SJimmy.Vetayases@oracle.com 	}
185312683SJimmy.Vetayases@oracle.com 
185412683SJimmy.Vetayases@oracle.com 	/* copy over autovect */
185512683SJimmy.Vetayases@oracle.com 	for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link)
185612683SJimmy.Vetayases@oracle.com 		apix_insert_av(vecp, avp->av_intr_id, avp->av_vector,
185712683SJimmy.Vetayases@oracle.com 		    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
185812683SJimmy.Vetayases@oracle.com 		    avp->av_prilevel, avp->av_dip);
185912683SJimmy.Vetayases@oracle.com 
186012683SJimmy.Vetayases@oracle.com 	/* Program I/O APIC */
186112683SJimmy.Vetayases@oracle.com 	iflag = intr_clear();
186212683SJimmy.Vetayases@oracle.com 	lock_set(&apix_lock);
186312683SJimmy.Vetayases@oracle.com 
186412683SJimmy.Vetayases@oracle.com 	(void) apix_setup_io_intr(vecp);
186512683SJimmy.Vetayases@oracle.com 
186612683SJimmy.Vetayases@oracle.com 	lock_clear(&apix_lock);
186712683SJimmy.Vetayases@oracle.com 	intr_restore(iflag);
186812683SJimmy.Vetayases@oracle.com 
186912683SJimmy.Vetayases@oracle.com 	APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x "
187012683SJimmy.Vetayases@oracle.com 	    "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n",
187112683SJimmy.Vetayases@oracle.com 	    irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector));
187212683SJimmy.Vetayases@oracle.com }
187312683SJimmy.Vetayases@oracle.com 
187412683SJimmy.Vetayases@oracle.com void
ioapix_init_intr(int mask_apic)187512683SJimmy.Vetayases@oracle.com ioapix_init_intr(int mask_apic)
187612683SJimmy.Vetayases@oracle.com {
187712683SJimmy.Vetayases@oracle.com 	int ioapicindex;
187812683SJimmy.Vetayases@oracle.com 	int i, j;
187912683SJimmy.Vetayases@oracle.com 
188012683SJimmy.Vetayases@oracle.com 	/* mask interrupt vectors */
188112683SJimmy.Vetayases@oracle.com 	for (j = 0; j < apic_io_max && mask_apic; j++) {
188212683SJimmy.Vetayases@oracle.com 		int intin_max;
188312683SJimmy.Vetayases@oracle.com 
188412683SJimmy.Vetayases@oracle.com 		ioapicindex = j;
188512683SJimmy.Vetayases@oracle.com 		/* Bits 23-16 define the maximum redirection entries */
188612683SJimmy.Vetayases@oracle.com 		intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16)
188712683SJimmy.Vetayases@oracle.com 		    & 0xff;
188812683SJimmy.Vetayases@oracle.com 		for (i = 0; i <= intin_max; i++)
188912683SJimmy.Vetayases@oracle.com 			ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i,
189012683SJimmy.Vetayases@oracle.com 			    AV_MASK);
189112683SJimmy.Vetayases@oracle.com 	}
189212683SJimmy.Vetayases@oracle.com 
189312683SJimmy.Vetayases@oracle.com 	/*
189412683SJimmy.Vetayases@oracle.com 	 * Hack alert: deal with ACPI SCI interrupt chicken/egg here
189512683SJimmy.Vetayases@oracle.com 	 */
189612683SJimmy.Vetayases@oracle.com 	if (apic_sci_vect > 0)
189712683SJimmy.Vetayases@oracle.com 		ioapix_setup_intr(apic_sci_vect, &apic_sci_flags);
189812683SJimmy.Vetayases@oracle.com 
189912683SJimmy.Vetayases@oracle.com 	/*
190012683SJimmy.Vetayases@oracle.com 	 * Hack alert: deal with ACPI HPET interrupt chicken/egg here.
190112683SJimmy.Vetayases@oracle.com 	 */
190212683SJimmy.Vetayases@oracle.com 	if (apic_hpet_vect > 0)
190312683SJimmy.Vetayases@oracle.com 		ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags);
190412683SJimmy.Vetayases@oracle.com }
1905