xref: /illumos-gate/usr/src/uts/i86pc/io/apix/apix_utils.c (revision d5026a94)
17ff178cdSJimmy Vetayases /*
27ff178cdSJimmy Vetayases  * CDDL HEADER START
37ff178cdSJimmy Vetayases  *
47ff178cdSJimmy Vetayases  * The contents of this file are subject to the terms of the
57ff178cdSJimmy Vetayases  * Common Development and Distribution License (the "License").
67ff178cdSJimmy Vetayases  * You may not use this file except in compliance with the License.
77ff178cdSJimmy Vetayases  *
87ff178cdSJimmy Vetayases  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97ff178cdSJimmy Vetayases  * or http://www.opensolaris.org/os/licensing.
107ff178cdSJimmy Vetayases  * See the License for the specific language governing permissions
117ff178cdSJimmy Vetayases  * and limitations under the License.
127ff178cdSJimmy Vetayases  *
137ff178cdSJimmy Vetayases  * When distributing Covered Code, include this CDDL HEADER in each
147ff178cdSJimmy Vetayases  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157ff178cdSJimmy Vetayases  * If applicable, add the following below this CDDL HEADER, with the
167ff178cdSJimmy Vetayases  * fields enclosed by brackets "[]" replaced with your own identifying
177ff178cdSJimmy Vetayases  * information: Portions Copyright [yyyy] [name of copyright owner]
187ff178cdSJimmy Vetayases  *
197ff178cdSJimmy Vetayases  * CDDL HEADER END
207ff178cdSJimmy Vetayases  */
217ff178cdSJimmy Vetayases 
227ff178cdSJimmy Vetayases /*
237ff178cdSJimmy Vetayases  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
247ff178cdSJimmy Vetayases  */
257ff178cdSJimmy Vetayases /*
267ff178cdSJimmy Vetayases  * Copyright (c) 2010, Intel Corporation.
277ff178cdSJimmy Vetayases  * All rights reserved.
287ff178cdSJimmy Vetayases  */
29584d084aSHans Rosenfeld /*
30584d084aSHans Rosenfeld  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
318181b438SGarrett D'Amore  * Copyright 2013 Pluribus Networks, Inc.
32c3377ee9SJohn Levon  * Copyright 2019 Joyent, Inc.
33584d084aSHans Rosenfeld  */
347ff178cdSJimmy Vetayases 
357ff178cdSJimmy Vetayases #include <sys/processor.h>
367ff178cdSJimmy Vetayases #include <sys/time.h>
377ff178cdSJimmy Vetayases #include <sys/psm.h>
387ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h>
397ff178cdSJimmy Vetayases #include <sys/cram.h>
407ff178cdSJimmy Vetayases #include <sys/acpi/acpi.h>
417ff178cdSJimmy Vetayases #include <sys/acpica.h>
427ff178cdSJimmy Vetayases #include <sys/psm_common.h>
437ff178cdSJimmy Vetayases #include <sys/pit.h>
447ff178cdSJimmy Vetayases #include <sys/ddi.h>
457ff178cdSJimmy Vetayases #include <sys/sunddi.h>
467ff178cdSJimmy Vetayases #include <sys/ddi_impldefs.h>
477ff178cdSJimmy Vetayases #include <sys/pci.h>
487ff178cdSJimmy Vetayases #include <sys/promif.h>
497ff178cdSJimmy Vetayases #include <sys/x86_archext.h>
507ff178cdSJimmy Vetayases #include <sys/cpc_impl.h>
517ff178cdSJimmy Vetayases #include <sys/uadmin.h>
527ff178cdSJimmy Vetayases #include <sys/panic.h>
537ff178cdSJimmy Vetayases #include <sys/debug.h>
547ff178cdSJimmy Vetayases #include <sys/archsystm.h>
557ff178cdSJimmy Vetayases #include <sys/trap.h>
567ff178cdSJimmy Vetayases #include <sys/machsystm.h>
577ff178cdSJimmy Vetayases #include <sys/sysmacros.h>
587ff178cdSJimmy Vetayases #include <sys/cpuvar.h>
597ff178cdSJimmy Vetayases #include <sys/rm_platter.h>
607ff178cdSJimmy Vetayases #include <sys/privregs.h>
617ff178cdSJimmy Vetayases #include <sys/note.h>
627ff178cdSJimmy Vetayases #include <sys/pci_intr_lib.h>
637ff178cdSJimmy Vetayases #include <sys/spl.h>
647ff178cdSJimmy Vetayases #include <sys/clock.h>
657ff178cdSJimmy Vetayases #include <sys/dditypes.h>
667ff178cdSJimmy Vetayases #include <sys/sunddi.h>
677ff178cdSJimmy Vetayases #include <sys/x_call.h>
687ff178cdSJimmy Vetayases #include <sys/reboot.h>
697ff178cdSJimmy Vetayases #include <sys/apix.h>
70c3377ee9SJohn Levon #include <sys/smt.h>
717ff178cdSJimmy Vetayases 
727ff178cdSJimmy Vetayases static int apix_get_avail_vector_oncpu(uint32_t, int, int);
737ff178cdSJimmy Vetayases static apix_vector_t *apix_init_vector(processorid_t, uchar_t);
747ff178cdSJimmy Vetayases static void apix_cleanup_vector(apix_vector_t *);
757ff178cdSJimmy Vetayases static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t,
767ff178cdSJimmy Vetayases     uint64_t *, int, dev_info_t *);
777ff178cdSJimmy Vetayases static void apix_remove_av(apix_vector_t *, struct autovec *);
787ff178cdSJimmy Vetayases static void apix_clear_dev_map(dev_info_t *, int, int);
797ff178cdSJimmy Vetayases static boolean_t apix_is_cpu_enabled(processorid_t);
807ff178cdSJimmy Vetayases static void apix_wait_till_seen(processorid_t, int);
817ff178cdSJimmy Vetayases 
827ff178cdSJimmy Vetayases #define	GET_INTR_INUM(ihdlp)		\
837ff178cdSJimmy Vetayases 	(((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0)
847ff178cdSJimmy Vetayases 
857ff178cdSJimmy Vetayases apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL};
867ff178cdSJimmy Vetayases 
877ff178cdSJimmy Vetayases /*
887ff178cdSJimmy Vetayases  * Allocate IPI
897ff178cdSJimmy Vetayases  *
907ff178cdSJimmy Vetayases  * Return vector number or 0 on error
917ff178cdSJimmy Vetayases  */
927ff178cdSJimmy Vetayases uchar_t
apix_alloc_ipi(int ipl)937ff178cdSJimmy Vetayases apix_alloc_ipi(int ipl)
947ff178cdSJimmy Vetayases {
957ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
967ff178cdSJimmy Vetayases 	uchar_t vector;
977ff178cdSJimmy Vetayases 	int cpun;
987ff178cdSJimmy Vetayases 	int nproc;
997ff178cdSJimmy Vetayases 
1007ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(0);
1017ff178cdSJimmy Vetayases 
1027ff178cdSJimmy Vetayases 	vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX);
1037ff178cdSJimmy Vetayases 	if (vector == 0) {
1047ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(0);
1057ff178cdSJimmy Vetayases 		cmn_err(CE_WARN, "apix: no available IPI\n");
1067ff178cdSJimmy Vetayases 		apic_error |= APIC_ERR_GET_IPIVECT_FAIL;
1077ff178cdSJimmy Vetayases 		return (0);
1087ff178cdSJimmy Vetayases 	}
1097ff178cdSJimmy Vetayases 
1107ff178cdSJimmy Vetayases 	nproc = max(apic_nproc, apic_max_nproc);
1117ff178cdSJimmy Vetayases 	for (cpun = 0; cpun < nproc; cpun++) {
1127ff178cdSJimmy Vetayases 		vecp = xv_vector(cpun, vector);
1137ff178cdSJimmy Vetayases 		if (vecp == NULL) {
1147ff178cdSJimmy Vetayases 			vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
1157ff178cdSJimmy Vetayases 			if (vecp == NULL) {
1167ff178cdSJimmy Vetayases 				cmn_err(CE_WARN, "apix: No memory for ipi");
1177ff178cdSJimmy Vetayases 				goto fail;
1187ff178cdSJimmy Vetayases 			}
1197ff178cdSJimmy Vetayases 			xv_vector(cpun, vector) = vecp;
1207ff178cdSJimmy Vetayases 		}
1217ff178cdSJimmy Vetayases 		vecp->v_state = APIX_STATE_ALLOCED;
1227ff178cdSJimmy Vetayases 		vecp->v_type = APIX_TYPE_IPI;
1237ff178cdSJimmy Vetayases 		vecp->v_cpuid = vecp->v_bound_cpuid = cpun;
1247ff178cdSJimmy Vetayases 		vecp->v_vector = vector;
1257ff178cdSJimmy Vetayases 		vecp->v_pri = ipl;
1267ff178cdSJimmy Vetayases 	}
1277ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(0);
1287ff178cdSJimmy Vetayases 	return (vector);
1297ff178cdSJimmy Vetayases 
1307ff178cdSJimmy Vetayases fail:
1317ff178cdSJimmy Vetayases 	while (--cpun >= 0)
1327ff178cdSJimmy Vetayases 		apix_cleanup_vector(xv_vector(cpun, vector));
1337ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(0);
1347ff178cdSJimmy Vetayases 	return (0);
1357ff178cdSJimmy Vetayases }
1367ff178cdSJimmy Vetayases 
1377ff178cdSJimmy Vetayases /*
1387ff178cdSJimmy Vetayases  * Add IPI service routine
1397ff178cdSJimmy Vetayases  */
1407ff178cdSJimmy Vetayases static int
apix_add_ipi(int ipl,avfunc xxintr,char * name,int vector,caddr_t arg1,caddr_t arg2)1417ff178cdSJimmy Vetayases apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector,
1427ff178cdSJimmy Vetayases     caddr_t arg1, caddr_t arg2)
1437ff178cdSJimmy Vetayases {
1447ff178cdSJimmy Vetayases 	int cpun;
1457ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
1467ff178cdSJimmy Vetayases 	int nproc;
1477ff178cdSJimmy Vetayases 
1487ff178cdSJimmy Vetayases 	ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX);
1497ff178cdSJimmy Vetayases 
1507ff178cdSJimmy Vetayases 	nproc = max(apic_nproc, apic_max_nproc);
1517ff178cdSJimmy Vetayases 	for (cpun = 0; cpun < nproc; cpun++) {
1527ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(cpun);
1537ff178cdSJimmy Vetayases 		vecp = xv_vector(cpun, vector);
1547ff178cdSJimmy Vetayases 		apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL);
1557ff178cdSJimmy Vetayases 		vecp->v_state = APIX_STATE_ENABLED;
1567ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(cpun);
1577ff178cdSJimmy Vetayases 	}
1587ff178cdSJimmy Vetayases 
1597ff178cdSJimmy Vetayases 	APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x "
1607ff178cdSJimmy Vetayases 	    "ipl %x\n", name, vector, ipl));
1617ff178cdSJimmy Vetayases 
1627ff178cdSJimmy Vetayases 	return (1);
1637ff178cdSJimmy Vetayases }
1647ff178cdSJimmy Vetayases 
1657ff178cdSJimmy Vetayases /*
1667ff178cdSJimmy Vetayases  * Find and return first free vector in range (start, end)
1677ff178cdSJimmy Vetayases  */
1687ff178cdSJimmy Vetayases static int
apix_get_avail_vector_oncpu(uint32_t cpuid,int start,int end)1697ff178cdSJimmy Vetayases apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end)
1707ff178cdSJimmy Vetayases {
1717ff178cdSJimmy Vetayases 	int i;
1727ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpuid];
1737ff178cdSJimmy Vetayases 
1747ff178cdSJimmy Vetayases 	for (i = start; i <= end; i++) {
1757ff178cdSJimmy Vetayases 		if (APIC_CHECK_RESERVE_VECTORS(i))
1767ff178cdSJimmy Vetayases 			continue;
1777ff178cdSJimmy Vetayases 		if (IS_VECT_FREE(apixp->x_vectbl[i]))
1787ff178cdSJimmy Vetayases 			return (i);
1797ff178cdSJimmy Vetayases 	}
1807ff178cdSJimmy Vetayases 
1817ff178cdSJimmy Vetayases 	return (0);
1827ff178cdSJimmy Vetayases }
1837ff178cdSJimmy Vetayases 
1847ff178cdSJimmy Vetayases /*
1857ff178cdSJimmy Vetayases  * Allocate a vector on specified cpu
1867ff178cdSJimmy Vetayases  *
1877ff178cdSJimmy Vetayases  * Return NULL on error
1887ff178cdSJimmy Vetayases  */
1897ff178cdSJimmy Vetayases static apix_vector_t *
apix_alloc_vector_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int type)1907ff178cdSJimmy Vetayases apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type)
1917ff178cdSJimmy Vetayases {
1927ff178cdSJimmy Vetayases 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
1937ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
1947ff178cdSJimmy Vetayases 	int vector;
1957ff178cdSJimmy Vetayases 
1967ff178cdSJimmy Vetayases 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
1977ff178cdSJimmy Vetayases 
1987ff178cdSJimmy Vetayases 	/* find free vector */
1997ff178cdSJimmy Vetayases 	vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN,
2007ff178cdSJimmy Vetayases 	    APIX_AVINTR_MAX);
2017ff178cdSJimmy Vetayases 	if (vector == 0)
2027ff178cdSJimmy Vetayases 		return (NULL);
2037ff178cdSJimmy Vetayases 
2047ff178cdSJimmy Vetayases 	vecp = apix_init_vector(tocpu, vector);
2057ff178cdSJimmy Vetayases 	vecp->v_type = (ushort_t)type;
2067ff178cdSJimmy Vetayases 	vecp->v_inum = inum;
2077ff178cdSJimmy Vetayases 	vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
2087ff178cdSJimmy Vetayases 
2097ff178cdSJimmy Vetayases 	if (dip != NULL)
2107ff178cdSJimmy Vetayases 		apix_set_dev_map(vecp, dip, inum);
2117ff178cdSJimmy Vetayases 
2127ff178cdSJimmy Vetayases 	return (vecp);
2137ff178cdSJimmy Vetayases }
2147ff178cdSJimmy Vetayases 
2157ff178cdSJimmy Vetayases /*
2167ff178cdSJimmy Vetayases  * Allocates "count" contiguous MSI vectors starting at the proper alignment.
2177ff178cdSJimmy Vetayases  * Caller needs to make sure that count has to be power of 2 and should not
2187ff178cdSJimmy Vetayases  * be < 1.
2197ff178cdSJimmy Vetayases  *
2207ff178cdSJimmy Vetayases  * Return first vector number
2217ff178cdSJimmy Vetayases  */
2227ff178cdSJimmy Vetayases apix_vector_t *
apix_alloc_nvectors_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int count,int type)2237ff178cdSJimmy Vetayases apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum,
2247ff178cdSJimmy Vetayases     int count, int type)
2257ff178cdSJimmy Vetayases {
2267ff178cdSJimmy Vetayases 	int i, msibits, start = 0, navail = 0;
2277ff178cdSJimmy Vetayases 	apix_vector_t *vecp, *startp = NULL;
2287ff178cdSJimmy Vetayases 	processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
2297ff178cdSJimmy Vetayases 	uint_t flags;
2307ff178cdSJimmy Vetayases 
2317ff178cdSJimmy Vetayases 	ASSERT(APIX_CPU_LOCK_HELD(tocpu));
2327ff178cdSJimmy Vetayases 
2337ff178cdSJimmy Vetayases 	/*
2347ff178cdSJimmy Vetayases 	 * msibits is the no. of lower order message data bits for the
2357ff178cdSJimmy Vetayases 	 * allocated MSI vectors and is used to calculate the aligned
2367ff178cdSJimmy Vetayases 	 * starting vector
2377ff178cdSJimmy Vetayases 	 */
2387ff178cdSJimmy Vetayases 	msibits = count - 1;
2397ff178cdSJimmy Vetayases 
2407ff178cdSJimmy Vetayases 	/* It has to be contiguous */
2417ff178cdSJimmy Vetayases 	for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) {
2427ff178cdSJimmy Vetayases 		if (!IS_VECT_FREE(xv_vector(tocpu, i)))
2437ff178cdSJimmy Vetayases 			continue;
2447ff178cdSJimmy Vetayases 
2457ff178cdSJimmy Vetayases 		/*
2467ff178cdSJimmy Vetayases 		 * starting vector has to be aligned accordingly for
2477ff178cdSJimmy Vetayases 		 * multiple MSIs
2487ff178cdSJimmy Vetayases 		 */
2497ff178cdSJimmy Vetayases 		if (msibits)
2507ff178cdSJimmy Vetayases 			i = (i + msibits) & ~msibits;
2517ff178cdSJimmy Vetayases 
2527ff178cdSJimmy Vetayases 		for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) {
2537ff178cdSJimmy Vetayases 			if (!IS_VECT_FREE(xv_vector(tocpu, i)))
2547ff178cdSJimmy Vetayases 				break;
2557ff178cdSJimmy Vetayases 			if (APIC_CHECK_RESERVE_VECTORS(i))
2567ff178cdSJimmy Vetayases 				break;
2577ff178cdSJimmy Vetayases 			if (++navail == count)
2587ff178cdSJimmy Vetayases 				goto done;
2597ff178cdSJimmy Vetayases 		}
2607ff178cdSJimmy Vetayases 	}
2617ff178cdSJimmy Vetayases 
2627ff178cdSJimmy Vetayases 	return (NULL);
2637ff178cdSJimmy Vetayases 
2647ff178cdSJimmy Vetayases done:
2657ff178cdSJimmy Vetayases 	flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
2667ff178cdSJimmy Vetayases 
2677ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++) {
2687ff178cdSJimmy Vetayases 		if ((vecp = apix_init_vector(tocpu, start + i)) == NULL)
2697ff178cdSJimmy Vetayases 			goto fail;
2707ff178cdSJimmy Vetayases 
2717ff178cdSJimmy Vetayases 		vecp->v_type = (ushort_t)type;
2727ff178cdSJimmy Vetayases 		vecp->v_inum = inum + i;
2737ff178cdSJimmy Vetayases 		vecp->v_flags = flags;
2747ff178cdSJimmy Vetayases 
2757ff178cdSJimmy Vetayases 		if (dip != NULL)
2767ff178cdSJimmy Vetayases 			apix_set_dev_map(vecp, dip, inum + i);
2777ff178cdSJimmy Vetayases 
2787ff178cdSJimmy Vetayases 		if (i == 0)
2797ff178cdSJimmy Vetayases 			startp = vecp;
2807ff178cdSJimmy Vetayases 	}
2817ff178cdSJimmy Vetayases 
2827ff178cdSJimmy Vetayases 	return (startp);
2837ff178cdSJimmy Vetayases 
2847ff178cdSJimmy Vetayases fail:
2857ff178cdSJimmy Vetayases 	while (i-- > 0) {	/* Free allocated vectors */
2867ff178cdSJimmy Vetayases 		vecp = xv_vector(tocpu, start + i);
2877ff178cdSJimmy Vetayases 		apix_clear_dev_map(dip, inum + i, type);
2887ff178cdSJimmy Vetayases 		apix_cleanup_vector(vecp);
2897ff178cdSJimmy Vetayases 	}
2907ff178cdSJimmy Vetayases 	return (NULL);
2917ff178cdSJimmy Vetayases }
2927ff178cdSJimmy Vetayases 
2937ff178cdSJimmy Vetayases #define	APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\
2947ff178cdSJimmy Vetayases do {\
2957ff178cdSJimmy Vetayases 	if ((_ctrl) & PCI_MSI_64BIT_MASK)\
2967ff178cdSJimmy Vetayases 		pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\
2977ff178cdSJimmy Vetayases 	else\
2987ff178cdSJimmy Vetayases 		pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\
2997ff178cdSJimmy Vetayases _NOTE(CONSTCOND)} while (0)
3007ff178cdSJimmy Vetayases 
3017ff178cdSJimmy Vetayases 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)3027ff178cdSJimmy Vetayases apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type,
3037ff178cdSJimmy Vetayases     int inum, int count, uchar_t vector, int target_apic_id)
3047ff178cdSJimmy Vetayases {
3057ff178cdSJimmy Vetayases 	uint64_t		msi_addr, msi_data;
3067ff178cdSJimmy Vetayases 	ushort_t		msi_ctrl;
3077ff178cdSJimmy Vetayases 	int			i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
3087ff178cdSJimmy Vetayases 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
3097ff178cdSJimmy Vetayases 	msi_regs_t		msi_regs;
3107ff178cdSJimmy Vetayases 	void			*intrmap_tbl[PCI_MSI_MAX_INTRS];
3117ff178cdSJimmy Vetayases 
3127ff178cdSJimmy Vetayases 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n"
3137ff178cdSJimmy Vetayases 	    "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip,
3147ff178cdSJimmy Vetayases 	    ddi_driver_name(dip), inum, vector, target_apic_id));
3157ff178cdSJimmy Vetayases 
3167ff178cdSJimmy Vetayases 	ASSERT((handle != NULL) && (cap_ptr != 0));
3177ff178cdSJimmy Vetayases 
3187ff178cdSJimmy Vetayases 	msi_regs.mr_data = vector;
3197ff178cdSJimmy Vetayases 	msi_regs.mr_addr = target_apic_id;
3207ff178cdSJimmy Vetayases 
3212edb3dccSJudy Chen 	for (i = 0; i < count; i++)
3222edb3dccSJudy Chen 		intrmap_tbl[i] = xv_intrmap_private(vecp->v_cpuid, vector + i);
3237ff178cdSJimmy Vetayases 	apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type,
3247ff178cdSJimmy Vetayases 	    count, 0xff);
3257ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++)
3267ff178cdSJimmy Vetayases 		xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i];
3277ff178cdSJimmy Vetayases 
3287ff178cdSJimmy Vetayases 	apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private,
3297ff178cdSJimmy Vetayases 	    (void *)&msi_regs, type, count);
3307ff178cdSJimmy Vetayases 	apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private,
3317ff178cdSJimmy Vetayases 	    &msi_regs);
3327ff178cdSJimmy Vetayases 
3337ff178cdSJimmy Vetayases 	/* MSI Address */
3347ff178cdSJimmy Vetayases 	msi_addr = msi_regs.mr_addr;
3357ff178cdSJimmy Vetayases 
3367ff178cdSJimmy Vetayases 	/* MSI Data: MSI is edge triggered according to spec */
3377ff178cdSJimmy Vetayases 	msi_data = msi_regs.mr_data;
3387ff178cdSJimmy Vetayases 
3397ff178cdSJimmy Vetayases 	DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx "
3407ff178cdSJimmy Vetayases 	    "data=0x%lx\n", (long)msi_addr, (long)msi_data));
3417ff178cdSJimmy Vetayases 
3427ff178cdSJimmy Vetayases 	if (type == APIX_TYPE_MSI) {
3437ff178cdSJimmy Vetayases 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
3447ff178cdSJimmy Vetayases 
3457ff178cdSJimmy Vetayases 		/* Set the bits to inform how many MSIs are enabled */
3467ff178cdSJimmy Vetayases 		msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT);
3477ff178cdSJimmy Vetayases 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
3487ff178cdSJimmy Vetayases 
3497ff178cdSJimmy Vetayases 		if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0)
3507ff178cdSJimmy Vetayases 			APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl,
3517ff178cdSJimmy Vetayases 			    APIX_RESV_VECTOR);
3527ff178cdSJimmy Vetayases 
3537ff178cdSJimmy Vetayases 		pci_config_put32(handle,
3547ff178cdSJimmy Vetayases 		    cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr);
3557ff178cdSJimmy Vetayases 		if (msi_ctrl &  PCI_MSI_64BIT_MASK)
3567ff178cdSJimmy Vetayases 			pci_config_put32(handle,
3577ff178cdSJimmy Vetayases 			    cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32);
3587ff178cdSJimmy Vetayases 
3597ff178cdSJimmy Vetayases 		APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data);
3607ff178cdSJimmy Vetayases 	} else if (type == APIX_TYPE_MSIX) {
3617ff178cdSJimmy Vetayases 		uintptr_t	off;
3627ff178cdSJimmy Vetayases 		ddi_intr_msix_t	*msix_p = i_ddi_get_msix(dip);
3637ff178cdSJimmy Vetayases 
3647ff178cdSJimmy Vetayases 		/* Offset into the "inum"th entry in the MSI-X table */
3657ff178cdSJimmy Vetayases 		off = (uintptr_t)msix_p->msix_tbl_addr +
3667ff178cdSJimmy Vetayases 		    (inum * PCI_MSIX_VECTOR_SIZE);
3677ff178cdSJimmy Vetayases 
3687ff178cdSJimmy Vetayases 		ddi_put32(msix_p->msix_tbl_hdl,
3697ff178cdSJimmy Vetayases 		    (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data);
3708181b438SGarrett D'Amore 		ddi_put32(msix_p->msix_tbl_hdl,
3718181b438SGarrett D'Amore 		    (uint32_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr);
3728181b438SGarrett D'Amore 		ddi_put32(msix_p->msix_tbl_hdl,
3738181b438SGarrett D'Amore 		    (uint32_t *)(off + PCI_MSIX_UPPER_ADDR_OFFSET),
3748181b438SGarrett D'Amore 		    msi_addr >> 32);
3757ff178cdSJimmy Vetayases 	}
3767ff178cdSJimmy Vetayases }
3777ff178cdSJimmy Vetayases 
3787ff178cdSJimmy Vetayases static void
apix_pci_msi_enable_mode(dev_info_t * dip,int type,int inum)3797ff178cdSJimmy Vetayases apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum)
3807ff178cdSJimmy Vetayases {
3817ff178cdSJimmy Vetayases 	ushort_t		msi_ctrl;
3827ff178cdSJimmy Vetayases 	int			cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
3837ff178cdSJimmy Vetayases 	ddi_acc_handle_t	handle = i_ddi_get_pci_config_handle(dip);
3847ff178cdSJimmy Vetayases 
3857ff178cdSJimmy Vetayases 	ASSERT((handle != NULL) && (cap_ptr != 0));
3867ff178cdSJimmy Vetayases 
3877ff178cdSJimmy Vetayases 	if (type == APIX_TYPE_MSI) {
3887ff178cdSJimmy Vetayases 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
3897ff178cdSJimmy Vetayases 		if ((msi_ctrl & PCI_MSI_ENABLE_BIT))
3907ff178cdSJimmy Vetayases 			return;
3917ff178cdSJimmy Vetayases 
3927ff178cdSJimmy Vetayases 		msi_ctrl |= PCI_MSI_ENABLE_BIT;
3937ff178cdSJimmy Vetayases 		pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
3947ff178cdSJimmy Vetayases 
3957ff178cdSJimmy Vetayases 	} else if (type == DDI_INTR_TYPE_MSIX) {
3967ff178cdSJimmy Vetayases 		uintptr_t	off;
3977ff178cdSJimmy Vetayases 		uint32_t	mask;
3987ff178cdSJimmy Vetayases 		ddi_intr_msix_t	*msix_p;
3997ff178cdSJimmy Vetayases 
4007ff178cdSJimmy Vetayases 		msix_p = i_ddi_get_msix(dip);
4017ff178cdSJimmy Vetayases 
4027ff178cdSJimmy Vetayases 		/* Offset into "inum"th entry in the MSI-X table & clear mask */
4037ff178cdSJimmy Vetayases 		off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
4047ff178cdSJimmy Vetayases 		    PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
4057ff178cdSJimmy Vetayases 
4067ff178cdSJimmy Vetayases 		mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
4077ff178cdSJimmy Vetayases 
4087ff178cdSJimmy Vetayases 		ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1));
4097ff178cdSJimmy Vetayases 
4107ff178cdSJimmy Vetayases 		msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
4117ff178cdSJimmy Vetayases 
4127ff178cdSJimmy Vetayases 		if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) {
4137ff178cdSJimmy Vetayases 			msi_ctrl |= PCI_MSIX_ENABLE_BIT;
4147ff178cdSJimmy Vetayases 			pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,
4157ff178cdSJimmy Vetayases 			    msi_ctrl);
4167ff178cdSJimmy Vetayases 		}
4177ff178cdSJimmy Vetayases 	}
4187ff178cdSJimmy Vetayases }
4197ff178cdSJimmy Vetayases 
4207ff178cdSJimmy Vetayases /*
4217ff178cdSJimmy Vetayases  * Setup interrupt, pogramming IO-APIC or MSI/X address/data.
4227ff178cdSJimmy Vetayases  */
4237ff178cdSJimmy Vetayases void
apix_enable_vector(apix_vector_t * vecp)4247ff178cdSJimmy Vetayases apix_enable_vector(apix_vector_t *vecp)
4257ff178cdSJimmy Vetayases {
4267ff178cdSJimmy Vetayases 	int tocpu = vecp->v_cpuid, type = vecp->v_type;
4277ff178cdSJimmy Vetayases 	apic_cpus_info_t *cpu_infop;
4287ff178cdSJimmy Vetayases 	ulong_t iflag;
4297ff178cdSJimmy Vetayases 
4307ff178cdSJimmy Vetayases 	ASSERT(tocpu < apic_nproc);
4317ff178cdSJimmy Vetayases 
4327ff178cdSJimmy Vetayases 	cpu_infop = &apic_cpus[tocpu];
4337ff178cdSJimmy Vetayases 	if (vecp->v_flags & APIX_VECT_USER_BOUND)
4347ff178cdSJimmy Vetayases 		cpu_infop->aci_bound++;
4357ff178cdSJimmy Vetayases 	else
4367ff178cdSJimmy Vetayases 		cpu_infop->aci_temp_bound++;
4377ff178cdSJimmy Vetayases 
4387ff178cdSJimmy Vetayases 	iflag = intr_clear();
4397ff178cdSJimmy Vetayases 	lock_set(&apic_ioapic_lock);
4407ff178cdSJimmy Vetayases 
4417ff178cdSJimmy Vetayases 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {	/* fixed */
4427ff178cdSJimmy Vetayases 		apix_intx_enable(vecp->v_inum);
4437ff178cdSJimmy Vetayases 	} else {
4447ff178cdSJimmy Vetayases 		int inum = vecp->v_inum;
4457ff178cdSJimmy Vetayases 		dev_info_t *dip = APIX_GET_DIP(vecp);
4467ff178cdSJimmy Vetayases 		int count = i_ddi_intr_get_current_nintrs(dip);
4477ff178cdSJimmy Vetayases 
4487ff178cdSJimmy Vetayases 		if (type == APIX_TYPE_MSI) {	/* MSI */
4497ff178cdSJimmy Vetayases 			if (inum == apix_get_max_dev_inum(dip, type)) {
4507ff178cdSJimmy Vetayases 				/* last one */
4517ff178cdSJimmy Vetayases 				uchar_t start_inum = inum + 1 - count;
4527ff178cdSJimmy Vetayases 				uchar_t start_vect = vecp->v_vector + 1 - count;
4537ff178cdSJimmy Vetayases 				apix_vector_t *start_vecp =
4547ff178cdSJimmy Vetayases 				    xv_vector(vecp->v_cpuid, start_vect);
4557ff178cdSJimmy Vetayases 
4567ff178cdSJimmy Vetayases 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
4577ff178cdSJimmy Vetayases 				    "apix_pci_msi_enable_vector\n"));
4587ff178cdSJimmy Vetayases 				apix_pci_msi_enable_vector(start_vecp, dip,
4597ff178cdSJimmy Vetayases 				    type, start_inum, count, start_vect,
4607ff178cdSJimmy Vetayases 				    cpu_infop->aci_local_id);
4617ff178cdSJimmy Vetayases 
4627ff178cdSJimmy Vetayases 				APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
4637ff178cdSJimmy Vetayases 				    "apix_pci_msi_enable_mode\n"));
4647ff178cdSJimmy Vetayases 				apix_pci_msi_enable_mode(dip, type, inum);
4657ff178cdSJimmy Vetayases 			}
4667ff178cdSJimmy Vetayases 		} else {				/* MSI-X */
4677ff178cdSJimmy Vetayases 			apix_pci_msi_enable_vector(vecp, dip,
4687ff178cdSJimmy Vetayases 			    type, inum, 1, vecp->v_vector,
4697ff178cdSJimmy Vetayases 			    cpu_infop->aci_local_id);
4707ff178cdSJimmy Vetayases 			apix_pci_msi_enable_mode(dip, type, inum);
4717ff178cdSJimmy Vetayases 		}
4727ff178cdSJimmy Vetayases 	}
4737ff178cdSJimmy Vetayases 	vecp->v_state = APIX_STATE_ENABLED;
4747ff178cdSJimmy Vetayases 	apic_redist_cpu_skip &= ~(1 << tocpu);
4757ff178cdSJimmy Vetayases 
4767ff178cdSJimmy Vetayases 	lock_clear(&apic_ioapic_lock);
4777ff178cdSJimmy Vetayases 	intr_restore(iflag);
4787ff178cdSJimmy Vetayases }
4797ff178cdSJimmy Vetayases 
4807ff178cdSJimmy Vetayases /*
4817ff178cdSJimmy Vetayases  * Disable the interrupt
4827ff178cdSJimmy Vetayases  */
4837ff178cdSJimmy Vetayases void
apix_disable_vector(apix_vector_t * vecp)4847ff178cdSJimmy Vetayases apix_disable_vector(apix_vector_t *vecp)
4857ff178cdSJimmy Vetayases {
4867ff178cdSJimmy Vetayases 	struct autovec *avp = vecp->v_autovect;
4877ff178cdSJimmy Vetayases 	ulong_t iflag;
4887ff178cdSJimmy Vetayases 
4897ff178cdSJimmy Vetayases 	ASSERT(avp != NULL);
4907ff178cdSJimmy Vetayases 
4917ff178cdSJimmy Vetayases 	iflag = intr_clear();
4927ff178cdSJimmy Vetayases 	lock_set(&apic_ioapic_lock);
4937ff178cdSJimmy Vetayases 
4947ff178cdSJimmy Vetayases 	switch (vecp->v_type) {
4957ff178cdSJimmy Vetayases 	case APIX_TYPE_MSI:
4967ff178cdSJimmy Vetayases 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
4977ff178cdSJimmy Vetayases 		/*
4987ff178cdSJimmy Vetayases 		 * Disable the MSI vector
4997ff178cdSJimmy Vetayases 		 * Make sure we only disable on the last
5007ff178cdSJimmy Vetayases 		 * of the multi-MSI support
5017ff178cdSJimmy Vetayases 		 */
5027ff178cdSJimmy Vetayases 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
5037ff178cdSJimmy Vetayases 			apic_pci_msi_disable_mode(avp->av_dip,
5047ff178cdSJimmy Vetayases 			    DDI_INTR_TYPE_MSI);
5057ff178cdSJimmy Vetayases 		}
5067ff178cdSJimmy Vetayases 		break;
5077ff178cdSJimmy Vetayases 	case APIX_TYPE_MSIX:
5087ff178cdSJimmy Vetayases 		ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
5097ff178cdSJimmy Vetayases 		/*
5107ff178cdSJimmy Vetayases 		 * Disable the MSI-X vector
5117ff178cdSJimmy Vetayases 		 * needs to clear its mask and addr/data for each MSI-X
5127ff178cdSJimmy Vetayases 		 */
5137ff178cdSJimmy Vetayases 		apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX,
5147ff178cdSJimmy Vetayases 		    vecp->v_inum);
5157ff178cdSJimmy Vetayases 		/*
5167ff178cdSJimmy Vetayases 		 * Make sure we only disable on the last MSI-X
5177ff178cdSJimmy Vetayases 		 */
5187ff178cdSJimmy Vetayases 		if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
5197ff178cdSJimmy Vetayases 			apic_pci_msi_disable_mode(avp->av_dip,
5207ff178cdSJimmy Vetayases 			    DDI_INTR_TYPE_MSIX);
5217ff178cdSJimmy Vetayases 		}
5227ff178cdSJimmy Vetayases 		break;
5237ff178cdSJimmy Vetayases 	default:
5247ff178cdSJimmy Vetayases 		apix_intx_disable(vecp->v_inum);
5257ff178cdSJimmy Vetayases 		break;
5267ff178cdSJimmy Vetayases 	}
5277ff178cdSJimmy Vetayases 
5287ff178cdSJimmy Vetayases 	if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND))
5297ff178cdSJimmy Vetayases 		vecp->v_state = APIX_STATE_DISABLED;
5307ff178cdSJimmy Vetayases 	apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private);
5317ff178cdSJimmy Vetayases 	vecp->v_intrmap_private = NULL;
5327ff178cdSJimmy Vetayases 
5337ff178cdSJimmy Vetayases 	lock_clear(&apic_ioapic_lock);
5347ff178cdSJimmy Vetayases 	intr_restore(iflag);
5357ff178cdSJimmy Vetayases }
5367ff178cdSJimmy Vetayases 
5377ff178cdSJimmy Vetayases /*
5387ff178cdSJimmy Vetayases  * Mark vector as obsoleted or freed. The vector is marked
5397ff178cdSJimmy Vetayases  * obsoleted if there are pending requests on it. Otherwise,
5407ff178cdSJimmy Vetayases  * free the vector. The obsoleted vectors get freed after
5417ff178cdSJimmy Vetayases  * being serviced.
5427ff178cdSJimmy Vetayases  *
5437ff178cdSJimmy Vetayases  * Return 1 on being obosoleted and 0 on being freed.
5447ff178cdSJimmy Vetayases  */
5457ff178cdSJimmy Vetayases #define	INTR_BUSY(_avp)\
5467ff178cdSJimmy Vetayases 	((((volatile ushort_t)(_avp)->av_flags) &\
5477ff178cdSJimmy Vetayases 	(AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0)
5487ff178cdSJimmy Vetayases #define	LOCAL_WITH_INTR_DISABLED(_cpuid)\
5497ff178cdSJimmy Vetayases 	((_cpuid) == psm_get_cpu_id() && !interrupts_enabled())
5507ff178cdSJimmy Vetayases static uint64_t dummy_tick;
5517ff178cdSJimmy Vetayases 
5527ff178cdSJimmy Vetayases int
apix_obsolete_vector(apix_vector_t * vecp)5537ff178cdSJimmy Vetayases apix_obsolete_vector(apix_vector_t *vecp)
5547ff178cdSJimmy Vetayases {
5557ff178cdSJimmy Vetayases 	struct autovec *avp = vecp->v_autovect;
5567ff178cdSJimmy Vetayases 	int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid;
5577ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpuid];
5587ff178cdSJimmy Vetayases 
5597ff178cdSJimmy Vetayases 	ASSERT(APIX_CPU_LOCK_HELD(cpuid));
5607ff178cdSJimmy Vetayases 
5617ff178cdSJimmy Vetayases 	for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) {
5627ff178cdSJimmy Vetayases 		if (avp->av_vector == NULL)
5637ff178cdSJimmy Vetayases 			continue;
5647ff178cdSJimmy Vetayases 
5657ff178cdSJimmy Vetayases 		if (LOCAL_WITH_INTR_DISABLED(cpuid)) {
5667ff178cdSJimmy Vetayases 			int bit, index, irr;
5677ff178cdSJimmy Vetayases 
5687ff178cdSJimmy Vetayases 			if (INTR_BUSY(avp)) {
5697ff178cdSJimmy Vetayases 				busy++;
5707ff178cdSJimmy Vetayases 				continue;
5717ff178cdSJimmy Vetayases 			}
5727ff178cdSJimmy Vetayases 
5737ff178cdSJimmy Vetayases 			/* check IRR for pending interrupts */
5747ff178cdSJimmy Vetayases 			index = vecp->v_vector / 32;
5757ff178cdSJimmy Vetayases 			bit = vecp->v_vector % 32;
5767ff178cdSJimmy Vetayases 			irr = apic_reg_ops->apic_read(APIC_IRR_REG + index);
5777ff178cdSJimmy Vetayases 			if ((irr & (1 << bit)) != 0)
5787ff178cdSJimmy Vetayases 				busy++;
5797ff178cdSJimmy Vetayases 
5807ff178cdSJimmy Vetayases 			if (!busy)
5817ff178cdSJimmy Vetayases 				apix_remove_av(vecp, avp);
5827ff178cdSJimmy Vetayases 
5837ff178cdSJimmy Vetayases 			continue;
5847ff178cdSJimmy Vetayases 		}
5857ff178cdSJimmy Vetayases 
5867ff178cdSJimmy Vetayases 		repeats = 0;
5877ff178cdSJimmy Vetayases 		do {
5887ff178cdSJimmy Vetayases 			repeats++;
5897ff178cdSJimmy Vetayases 			for (tries = 0; tries < apic_max_reps_clear_pending;
5907ff178cdSJimmy Vetayases 			    tries++)
5917ff178cdSJimmy Vetayases 				if (!INTR_BUSY(avp))
5927ff178cdSJimmy Vetayases 					break;
5937ff178cdSJimmy Vetayases 		} while (INTR_BUSY(avp) &&
5947ff178cdSJimmy Vetayases 		    (repeats < apic_max_reps_clear_pending));
5957ff178cdSJimmy Vetayases 
5967ff178cdSJimmy Vetayases 		if (INTR_BUSY(avp))
5977ff178cdSJimmy Vetayases 			busy++;
5987ff178cdSJimmy Vetayases 		else {
5997ff178cdSJimmy Vetayases 			/*
6007ff178cdSJimmy Vetayases 			 * Interrupt is not in pending list or being serviced.
6017ff178cdSJimmy Vetayases 			 * However it might be cached in Local APIC's IRR
6027ff178cdSJimmy Vetayases 			 * register. It's impossible to check another CPU's
6037ff178cdSJimmy Vetayases 			 * IRR register. Then wait till lower levels finish
6047ff178cdSJimmy Vetayases 			 * running.
6057ff178cdSJimmy Vetayases 			 */
6067ff178cdSJimmy Vetayases 			for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++)
6077ff178cdSJimmy Vetayases 				apix_wait_till_seen(cpuid, ipl);
6087ff178cdSJimmy Vetayases 			if (INTR_BUSY(avp))
6097ff178cdSJimmy Vetayases 				busy++;
6107ff178cdSJimmy Vetayases 		}
6117ff178cdSJimmy Vetayases 
6127ff178cdSJimmy Vetayases 		if (!busy)
6137ff178cdSJimmy Vetayases 			apix_remove_av(vecp, avp);
6147ff178cdSJimmy Vetayases 	}
6157ff178cdSJimmy Vetayases 
6167ff178cdSJimmy Vetayases 	if (busy) {
6177ff178cdSJimmy Vetayases 		apix_vector_t *tp = apixp->x_obsoletes;
6187ff178cdSJimmy Vetayases 
6197ff178cdSJimmy Vetayases 		if (vecp->v_state == APIX_STATE_OBSOLETED)
6207ff178cdSJimmy Vetayases 			return (1);
6217ff178cdSJimmy Vetayases 
6227ff178cdSJimmy Vetayases 		vecp->v_state = APIX_STATE_OBSOLETED;
6237ff178cdSJimmy Vetayases 		vecp->v_next = NULL;
6247ff178cdSJimmy Vetayases 		if (tp == NULL)
6257ff178cdSJimmy Vetayases 			apixp->x_obsoletes = vecp;
6267ff178cdSJimmy Vetayases 		else {
6277ff178cdSJimmy Vetayases 			while (tp->v_next != NULL)
6287ff178cdSJimmy Vetayases 				tp = tp->v_next;
6297ff178cdSJimmy Vetayases 			tp->v_next = vecp;
6307ff178cdSJimmy Vetayases 		}
6317ff178cdSJimmy Vetayases 		return (1);
6327ff178cdSJimmy Vetayases 	}
6337ff178cdSJimmy Vetayases 
6347ff178cdSJimmy Vetayases 	/* interrupt is not busy */
6357ff178cdSJimmy Vetayases 	if (vecp->v_state == APIX_STATE_OBSOLETED) {
6367ff178cdSJimmy Vetayases 		/* remove from obsoleted list */
6377ff178cdSJimmy Vetayases 		apixp->x_obsoletes = vecp->v_next;
6387ff178cdSJimmy Vetayases 		vecp->v_next = NULL;
6397ff178cdSJimmy Vetayases 	}
6407ff178cdSJimmy Vetayases 	apix_cleanup_vector(vecp);
6417ff178cdSJimmy Vetayases 	return (0);
6427ff178cdSJimmy Vetayases }
6437ff178cdSJimmy Vetayases 
6447ff178cdSJimmy Vetayases /*
6457ff178cdSJimmy Vetayases  * Duplicate number of continuous vectors to specified target vectors.
6467ff178cdSJimmy Vetayases  */
6477ff178cdSJimmy Vetayases static void
apix_dup_vectors(apix_vector_t * oldp,apix_vector_t * newp,int count)6487ff178cdSJimmy Vetayases apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count)
6497ff178cdSJimmy Vetayases {
6507ff178cdSJimmy Vetayases 	struct autovec *avp;
6517ff178cdSJimmy Vetayases 	apix_vector_t *fromp, *top;
6527ff178cdSJimmy Vetayases 	processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid;
6537ff178cdSJimmy Vetayases 	uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector;
6547ff178cdSJimmy Vetayases 	int i, inum;
6557ff178cdSJimmy Vetayases 
6567ff178cdSJimmy Vetayases 	ASSERT(oldp->v_type != APIX_TYPE_IPI);
6577ff178cdSJimmy Vetayases 
6587ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++) {
6597ff178cdSJimmy Vetayases 		fromp = xv_vector(oldcpu, oldvec + i);
6607ff178cdSJimmy Vetayases 		top = xv_vector(newcpu, newvec + i);
6617ff178cdSJimmy Vetayases 		ASSERT(fromp != NULL && top != NULL);
6627ff178cdSJimmy Vetayases 
6637ff178cdSJimmy Vetayases 		/* copy over original one */
6647ff178cdSJimmy Vetayases 		top->v_state = fromp->v_state;
6657ff178cdSJimmy Vetayases 		top->v_type = fromp->v_type;
6667ff178cdSJimmy Vetayases 		top->v_bound_cpuid = fromp->v_bound_cpuid;
6677ff178cdSJimmy Vetayases 		top->v_inum = fromp->v_inum;
6687ff178cdSJimmy Vetayases 		top->v_flags = fromp->v_flags;
6697ff178cdSJimmy Vetayases 		top->v_intrmap_private = fromp->v_intrmap_private;
6707ff178cdSJimmy Vetayases 
6717ff178cdSJimmy Vetayases 		for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) {
6727ff178cdSJimmy Vetayases 			if (avp->av_vector == NULL)
6737ff178cdSJimmy Vetayases 				continue;
6747ff178cdSJimmy Vetayases 
6757ff178cdSJimmy Vetayases 			apix_insert_av(top, avp->av_intr_id, avp->av_vector,
6767ff178cdSJimmy Vetayases 			    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
6777ff178cdSJimmy Vetayases 			    avp->av_prilevel, avp->av_dip);
6787ff178cdSJimmy Vetayases 
6797ff178cdSJimmy Vetayases 			if (fromp->v_type == APIX_TYPE_FIXED &&
6807ff178cdSJimmy Vetayases 			    avp->av_dip != NULL) {
6817ff178cdSJimmy Vetayases 				inum = GET_INTR_INUM(avp->av_intr_id);
6827ff178cdSJimmy Vetayases 				apix_set_dev_map(top, avp->av_dip, inum);
6837ff178cdSJimmy Vetayases 			}
6847ff178cdSJimmy Vetayases 		}
6857ff178cdSJimmy Vetayases 
6867ff178cdSJimmy Vetayases 		if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) &&
6877ff178cdSJimmy Vetayases 		    fromp->v_devp != NULL)
6887ff178cdSJimmy Vetayases 			apix_set_dev_map(top, fromp->v_devp->dv_dip,
6897ff178cdSJimmy Vetayases 			    fromp->v_devp->dv_inum);
6907ff178cdSJimmy Vetayases 	}
6917ff178cdSJimmy Vetayases }
6927ff178cdSJimmy Vetayases 
6937ff178cdSJimmy Vetayases static apix_vector_t *
apix_init_vector(processorid_t cpuid,uchar_t vector)6947ff178cdSJimmy Vetayases apix_init_vector(processorid_t cpuid, uchar_t vector)
6957ff178cdSJimmy Vetayases {
6967ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpuid];
6977ff178cdSJimmy Vetayases 	apix_vector_t *vecp = apixp->x_vectbl[vector];
6987ff178cdSJimmy Vetayases 
6997ff178cdSJimmy Vetayases 	ASSERT(IS_VECT_FREE(vecp));
7007ff178cdSJimmy Vetayases 
7017ff178cdSJimmy Vetayases 	if (vecp == NULL) {
7027ff178cdSJimmy Vetayases 		vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
7037ff178cdSJimmy Vetayases 		if (vecp == NULL) {
7047ff178cdSJimmy Vetayases 			cmn_err(CE_WARN, "apix: no memory to allocate vector");
7057ff178cdSJimmy Vetayases 			return (NULL);
7067ff178cdSJimmy Vetayases 		}
7077ff178cdSJimmy Vetayases 		apixp->x_vectbl[vector] = vecp;
7087ff178cdSJimmy Vetayases 	}
7097ff178cdSJimmy Vetayases 	vecp->v_state = APIX_STATE_ALLOCED;
7107ff178cdSJimmy Vetayases 	vecp->v_cpuid = vecp->v_bound_cpuid = cpuid;
7117ff178cdSJimmy Vetayases 	vecp->v_vector = vector;
7127ff178cdSJimmy Vetayases 
7137ff178cdSJimmy Vetayases 	return (vecp);
7147ff178cdSJimmy Vetayases }
7157ff178cdSJimmy Vetayases 
7167ff178cdSJimmy Vetayases static void
apix_cleanup_vector(apix_vector_t * vecp)7177ff178cdSJimmy Vetayases apix_cleanup_vector(apix_vector_t *vecp)
7187ff178cdSJimmy Vetayases {
7197ff178cdSJimmy Vetayases 	ASSERT(vecp->v_share == 0);
7207ff178cdSJimmy Vetayases 	vecp->v_bound_cpuid = IRQ_UNINIT;
7217ff178cdSJimmy Vetayases 	vecp->v_state = APIX_STATE_FREED;
7227ff178cdSJimmy Vetayases 	vecp->v_type = 0;
7237ff178cdSJimmy Vetayases 	vecp->v_flags = 0;
7247ff178cdSJimmy Vetayases 	vecp->v_busy = 0;
7251053f4b7SPrasad Singamsetty 	vecp->v_intrmap_private = NULL;
7267ff178cdSJimmy Vetayases }
7277ff178cdSJimmy Vetayases 
7287ff178cdSJimmy Vetayases static void
apix_dprint_vector(apix_vector_t * vecp,dev_info_t * dip,int count)7297ff178cdSJimmy Vetayases apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count)
7307ff178cdSJimmy Vetayases {
7317ff178cdSJimmy Vetayases #ifdef DEBUG
7327ff178cdSJimmy Vetayases 	major_t major;
7337ff178cdSJimmy Vetayases 	char *name, *drv_name;
7347ff178cdSJimmy Vetayases 	int instance, len, t_len;
7357ff178cdSJimmy Vetayases 	char mesg[1024] = "apix: ";
7367ff178cdSJimmy Vetayases 
7377ff178cdSJimmy Vetayases 	t_len = sizeof (mesg);
7387ff178cdSJimmy Vetayases 	len = strlen(mesg);
7397ff178cdSJimmy Vetayases 	if (dip != NULL) {
7407ff178cdSJimmy Vetayases 		name = ddi_get_name(dip);
7417ff178cdSJimmy Vetayases 		major = ddi_name_to_major(name);
7427ff178cdSJimmy Vetayases 		drv_name = ddi_major_to_name(major);
7437ff178cdSJimmy Vetayases 		instance = ddi_get_instance(dip);
7447ff178cdSJimmy Vetayases 		(void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ",
7457ff178cdSJimmy Vetayases 		    name, drv_name, instance);
7467ff178cdSJimmy Vetayases 	}
7477ff178cdSJimmy Vetayases 	len = strlen(mesg);
7487ff178cdSJimmy Vetayases 
7497ff178cdSJimmy Vetayases 	switch (vecp->v_type) {
7507ff178cdSJimmy Vetayases 	case APIX_TYPE_FIXED:
7517ff178cdSJimmy Vetayases 		(void) snprintf(mesg + len, t_len - len, "irqno %d",
7527ff178cdSJimmy Vetayases 		    vecp->v_inum);
7537ff178cdSJimmy Vetayases 		break;
7547ff178cdSJimmy Vetayases 	case APIX_TYPE_MSI:
7557ff178cdSJimmy Vetayases 		(void) snprintf(mesg + len, t_len - len,
7567ff178cdSJimmy Vetayases 		    "msi inum %d (count %d)", vecp->v_inum, count);
7577ff178cdSJimmy Vetayases 		break;
7587ff178cdSJimmy Vetayases 	case APIX_TYPE_MSIX:
7597ff178cdSJimmy Vetayases 		(void) snprintf(mesg + len, t_len - len, "msi-x inum %d",
7607ff178cdSJimmy Vetayases 		    vecp->v_inum);
7617ff178cdSJimmy Vetayases 		break;
7627ff178cdSJimmy Vetayases 	default:
7637ff178cdSJimmy Vetayases 		break;
7647ff178cdSJimmy Vetayases 
7657ff178cdSJimmy Vetayases 	}
7667ff178cdSJimmy Vetayases 
7677ff178cdSJimmy Vetayases 	APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on "
7687ff178cdSJimmy Vetayases 	    "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid));
7697ff178cdSJimmy Vetayases #endif	/* DEBUG */
7707ff178cdSJimmy Vetayases }
7717ff178cdSJimmy Vetayases 
7727ff178cdSJimmy Vetayases /*
7737ff178cdSJimmy Vetayases  * Operations on avintr
7747ff178cdSJimmy Vetayases  */
7757ff178cdSJimmy Vetayases 
7767ff178cdSJimmy Vetayases #define	INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip)	\
7777ff178cdSJimmy Vetayases do { \
7787ff178cdSJimmy Vetayases 	(p)->av_intr_id = intr_id;	\
7797ff178cdSJimmy Vetayases 	(p)->av_vector = f;		\
7807ff178cdSJimmy Vetayases 	(p)->av_intarg1 = arg1;		\
7817ff178cdSJimmy Vetayases 	(p)->av_intarg2 = arg2;		\
7827ff178cdSJimmy Vetayases 	(p)->av_ticksp = ticksp;	\
7837ff178cdSJimmy Vetayases 	(p)->av_prilevel = ipl;		\
7847ff178cdSJimmy Vetayases 	(p)->av_dip = dip;		\
7857ff178cdSJimmy Vetayases 	(p)->av_flags = 0;		\
7867ff178cdSJimmy Vetayases _NOTE(CONSTCOND)} while (0)
7877ff178cdSJimmy Vetayases 
7887ff178cdSJimmy Vetayases /*
7897ff178cdSJimmy Vetayases  * Insert an interrupt service routine into chain by its priority from
7907ff178cdSJimmy Vetayases  * high to low
7917ff178cdSJimmy Vetayases  */
7927ff178cdSJimmy Vetayases 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)7937ff178cdSJimmy Vetayases apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1,
7947ff178cdSJimmy Vetayases     caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip)
7957ff178cdSJimmy Vetayases {
7967ff178cdSJimmy Vetayases 	struct autovec *p, *prep, *mem;
7977ff178cdSJimmy Vetayases 
7987ff178cdSJimmy Vetayases 	APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, "
7997ff178cdSJimmy Vetayases 	    "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid));
8007ff178cdSJimmy Vetayases 
8017ff178cdSJimmy Vetayases 	mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP);
8027ff178cdSJimmy Vetayases 	INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip);
8037ff178cdSJimmy Vetayases 	if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum])
8047ff178cdSJimmy Vetayases 		mem->av_flags |= AV_PENTRY_LEVEL;
8057ff178cdSJimmy Vetayases 
8067ff178cdSJimmy Vetayases 	vecp->v_share++;
8077ff178cdSJimmy Vetayases 	vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri;
808455e370cSJohn Levon 
809c3377ee9SJohn Levon 	smt_intr_alloc_pil(vecp->v_pri);
810455e370cSJohn Levon 
8117ff178cdSJimmy Vetayases 	if (vecp->v_autovect == NULL) {	/* Nothing on list - put it at head */
8127ff178cdSJimmy Vetayases 		vecp->v_autovect = mem;
8137ff178cdSJimmy Vetayases 		return;
8147ff178cdSJimmy Vetayases 	}
8157ff178cdSJimmy Vetayases 
8167ff178cdSJimmy Vetayases 	if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {	/* MSI/X */
8177ff178cdSJimmy Vetayases 		ASSERT(vecp->v_share == 1);	/* No sharing for MSI/X */
8187ff178cdSJimmy Vetayases 
8197ff178cdSJimmy Vetayases 		INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp,
8207ff178cdSJimmy Vetayases 		    ipl, dip);
8217ff178cdSJimmy Vetayases 		prep = vecp->v_autovect->av_link;
8227ff178cdSJimmy Vetayases 		vecp->v_autovect->av_link = NULL;
8237ff178cdSJimmy Vetayases 
8247ff178cdSJimmy Vetayases 		/* Free the following autovect chain */
8257ff178cdSJimmy Vetayases 		while (prep != NULL) {
8267ff178cdSJimmy Vetayases 			ASSERT(prep->av_vector == NULL);
8277ff178cdSJimmy Vetayases 
8287ff178cdSJimmy Vetayases 			p = prep;
8297ff178cdSJimmy Vetayases 			prep = prep->av_link;
8307ff178cdSJimmy Vetayases 			kmem_free(p, sizeof (struct autovec));
8317ff178cdSJimmy Vetayases 		}
8327ff178cdSJimmy Vetayases 
8337ff178cdSJimmy Vetayases 		kmem_free(mem, sizeof (struct autovec));
8347ff178cdSJimmy Vetayases 		return;
8357ff178cdSJimmy Vetayases 	}
8367ff178cdSJimmy Vetayases 
8377ff178cdSJimmy Vetayases 	/* find where it goes in list */
8387ff178cdSJimmy Vetayases 	prep = NULL;
8397ff178cdSJimmy Vetayases 	for (p = vecp->v_autovect; p != NULL; p = p->av_link) {
8407ff178cdSJimmy Vetayases 		if (p->av_vector && p->av_prilevel <= ipl)
8417ff178cdSJimmy Vetayases 			break;
8427ff178cdSJimmy Vetayases 		prep = p;
8437ff178cdSJimmy Vetayases 	}
8447ff178cdSJimmy Vetayases 	if (prep != NULL) {
8457ff178cdSJimmy Vetayases 		if (prep->av_vector == NULL) {	/* freed struct available */
8467ff178cdSJimmy Vetayases 			INIT_AUTOVEC(prep, intr_id, f, arg1, arg2,
8477ff178cdSJimmy Vetayases 			    ticksp, ipl, dip);
8487ff178cdSJimmy Vetayases 			prep->av_flags = mem->av_flags;
8497ff178cdSJimmy Vetayases 			kmem_free(mem, sizeof (struct autovec));
8507ff178cdSJimmy Vetayases 			return;
8517ff178cdSJimmy Vetayases 		}
8527ff178cdSJimmy Vetayases 
8537ff178cdSJimmy Vetayases 		mem->av_link = prep->av_link;
8547ff178cdSJimmy Vetayases 		prep->av_link = mem;
8557ff178cdSJimmy Vetayases 	} else {
8567ff178cdSJimmy Vetayases 		/* insert new intpt at beginning of chain */
8577ff178cdSJimmy Vetayases 		mem->av_link = vecp->v_autovect;
8587ff178cdSJimmy Vetayases 		vecp->v_autovect = mem;
8597ff178cdSJimmy Vetayases 	}
8607ff178cdSJimmy Vetayases }
8617ff178cdSJimmy Vetayases 
8627ff178cdSJimmy Vetayases /*
8637ff178cdSJimmy Vetayases  * After having made a change to an autovector list, wait until we have
8647ff178cdSJimmy Vetayases  * seen specified cpu not executing an interrupt at that level--so we
8657ff178cdSJimmy Vetayases  * know our change has taken effect completely (no old state in registers,
8667ff178cdSJimmy Vetayases  * etc).
8677ff178cdSJimmy Vetayases  */
8687ff178cdSJimmy Vetayases #define	APIX_CPU_ENABLED(_cp) \
8697ff178cdSJimmy Vetayases 	(quiesce_active == 0 && \
8707ff178cdSJimmy Vetayases 	(((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0))
8717ff178cdSJimmy Vetayases 
8727ff178cdSJimmy Vetayases static void
apix_wait_till_seen(processorid_t cpuid,int ipl)8737ff178cdSJimmy Vetayases apix_wait_till_seen(processorid_t cpuid, int ipl)
8747ff178cdSJimmy Vetayases {
8757ff178cdSJimmy Vetayases 	struct cpu *cp = cpu[cpuid];
8767ff178cdSJimmy Vetayases 
8777ff178cdSJimmy Vetayases 	if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid))
8787ff178cdSJimmy Vetayases 		return;
8797ff178cdSJimmy Vetayases 
8807ff178cdSJimmy Vetayases 	/*
8817ff178cdSJimmy Vetayases 	 * Don't wait if the CPU is quiesced or offlined. This can happen
8827ff178cdSJimmy Vetayases 	 * when a CPU is running pause thread but hardware triggered an
8837ff178cdSJimmy Vetayases 	 * interrupt and the interrupt gets queued.
8847ff178cdSJimmy Vetayases 	 */
8857ff178cdSJimmy Vetayases 	for (;;) {
8867ff178cdSJimmy Vetayases 		if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) &&
8877ff178cdSJimmy Vetayases 		    (!APIX_CPU_ENABLED(cp) ||
8887ff178cdSJimmy Vetayases 		    !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl)))
8897ff178cdSJimmy Vetayases 			return;
8907ff178cdSJimmy Vetayases 	}
8917ff178cdSJimmy Vetayases }
8927ff178cdSJimmy Vetayases 
8937ff178cdSJimmy Vetayases static void
apix_remove_av(apix_vector_t * vecp,struct autovec * target)8947ff178cdSJimmy Vetayases apix_remove_av(apix_vector_t *vecp, struct autovec *target)
8957ff178cdSJimmy Vetayases {
8967ff178cdSJimmy Vetayases 	int hi_pri = 0;
8977ff178cdSJimmy Vetayases 	struct autovec *p;
8987ff178cdSJimmy Vetayases 
8997ff178cdSJimmy Vetayases 	if (target == NULL)
9007ff178cdSJimmy Vetayases 		return;
9017ff178cdSJimmy Vetayases 
9027ff178cdSJimmy Vetayases 	APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, "
9037ff178cdSJimmy Vetayases 	    "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid));
9047ff178cdSJimmy Vetayases 
9057ff178cdSJimmy Vetayases 	for (p = vecp->v_autovect; p; p = p->av_link) {
9067ff178cdSJimmy Vetayases 		if (p == target || p->av_vector == NULL)
9077ff178cdSJimmy Vetayases 			continue;
9087ff178cdSJimmy Vetayases 		hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri;
9097ff178cdSJimmy Vetayases 	}
9107ff178cdSJimmy Vetayases 
9117ff178cdSJimmy Vetayases 	vecp->v_share--;
9127ff178cdSJimmy Vetayases 	vecp->v_pri = hi_pri;
9137ff178cdSJimmy Vetayases 
9147ff178cdSJimmy Vetayases 	/*
9157ff178cdSJimmy Vetayases 	 * This drops the handler from the chain, it can no longer be called.
9167ff178cdSJimmy Vetayases 	 * However, there is no guarantee that the handler is not currently
9177ff178cdSJimmy Vetayases 	 * still executing.
9187ff178cdSJimmy Vetayases 	 */
9197ff178cdSJimmy Vetayases 	target->av_vector = NULL;
9207ff178cdSJimmy Vetayases 	/*
9217ff178cdSJimmy Vetayases 	 * There is a race where we could be just about to pick up the ticksp
9227ff178cdSJimmy Vetayases 	 * pointer to increment it after returning from the service routine
9237ff178cdSJimmy Vetayases 	 * in av_dispatch_autovect.  Rather than NULL it out let's just point
9247ff178cdSJimmy Vetayases 	 * it off to something safe so that any final tick update attempt
9257ff178cdSJimmy Vetayases 	 * won't fault.
9267ff178cdSJimmy Vetayases 	 */
9277ff178cdSJimmy Vetayases 	target->av_ticksp = &dummy_tick;
9287ff178cdSJimmy Vetayases 	apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel);
9297ff178cdSJimmy Vetayases }
9307ff178cdSJimmy Vetayases 
9317ff178cdSJimmy Vetayases static struct autovec *
apix_find_av(apix_vector_t * vecp,void * intr_id,avfunc f)9327ff178cdSJimmy Vetayases apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f)
9337ff178cdSJimmy Vetayases {
9347ff178cdSJimmy Vetayases 	struct autovec *p;
9357ff178cdSJimmy Vetayases 
9367ff178cdSJimmy Vetayases 	for (p = vecp->v_autovect; p; p = p->av_link) {
9377ff178cdSJimmy Vetayases 		if ((p->av_vector == f) && (p->av_intr_id == intr_id)) {
9387ff178cdSJimmy Vetayases 			/* found the handler */
9397ff178cdSJimmy Vetayases 			return (p);
9407ff178cdSJimmy Vetayases 		}
9417ff178cdSJimmy Vetayases 	}
9427ff178cdSJimmy Vetayases 
9437ff178cdSJimmy Vetayases 	return (NULL);
9447ff178cdSJimmy Vetayases }
9457ff178cdSJimmy Vetayases 
9467ff178cdSJimmy Vetayases static apix_vector_t *
apix_find_vector_by_avintr(void * intr_id,avfunc f)9477ff178cdSJimmy Vetayases apix_find_vector_by_avintr(void *intr_id, avfunc f)
9487ff178cdSJimmy Vetayases {
9497ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
9507ff178cdSJimmy Vetayases 	processorid_t n;
9517ff178cdSJimmy Vetayases 	uchar_t v;
9527ff178cdSJimmy Vetayases 
9537ff178cdSJimmy Vetayases 	for (n = 0; n < apic_nproc; n++) {
9547ff178cdSJimmy Vetayases 		if (!apix_is_cpu_enabled(n))
9557ff178cdSJimmy Vetayases 			continue;
9567ff178cdSJimmy Vetayases 
957*d5026a94SKeith M Wesolowski 		for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MAX; v++) {
9587ff178cdSJimmy Vetayases 			vecp = xv_vector(n, v);
9597ff178cdSJimmy Vetayases 			if (vecp == NULL ||
9607ff178cdSJimmy Vetayases 			    vecp->v_state <= APIX_STATE_OBSOLETED)
9617ff178cdSJimmy Vetayases 				continue;
9627ff178cdSJimmy Vetayases 
9637ff178cdSJimmy Vetayases 			if (apix_find_av(vecp, intr_id, f) != NULL)
9647ff178cdSJimmy Vetayases 				return (vecp);
9657ff178cdSJimmy Vetayases 		}
9667ff178cdSJimmy Vetayases 	}
9677ff178cdSJimmy Vetayases 
9687ff178cdSJimmy Vetayases 	return (NULL);
9697ff178cdSJimmy Vetayases }
9707ff178cdSJimmy Vetayases 
9717ff178cdSJimmy Vetayases /*
9727ff178cdSJimmy Vetayases  * Add interrupt service routine.
9737ff178cdSJimmy Vetayases  *
9747ff178cdSJimmy Vetayases  * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually
9757ff178cdSJimmy Vetayases  * IRQ no. A vector is then allocated. Otherwise, the vector is already
9767ff178cdSJimmy Vetayases  * allocated. The input argument virt_vect is virtual vector of format
9777ff178cdSJimmy Vetayases  * APIX_VIRTVEC_VECTOR(cpuid, vector).
9787ff178cdSJimmy Vetayases  *
9797ff178cdSJimmy Vetayases  * Return 1 on success, 0 on failure.
9807ff178cdSJimmy Vetayases  */
9817ff178cdSJimmy Vetayases 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)9827ff178cdSJimmy Vetayases apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name,
9837ff178cdSJimmy Vetayases     int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp,
9847ff178cdSJimmy Vetayases     dev_info_t *dip)
9857ff178cdSJimmy Vetayases {
9867ff178cdSJimmy Vetayases 	int cpuid;
9877ff178cdSJimmy Vetayases 	uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect);
9887ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
9897ff178cdSJimmy Vetayases 
9907ff178cdSJimmy Vetayases 	if (xxintr == NULL) {
9917ff178cdSJimmy Vetayases 		cmn_err(CE_WARN, "Attempt to add null for %s "
9927ff178cdSJimmy Vetayases 		    "on vector 0x%x,0x%x", name,
9937ff178cdSJimmy Vetayases 		    APIX_VIRTVEC_CPU(virt_vect),
9947ff178cdSJimmy Vetayases 		    APIX_VIRTVEC_VECTOR(virt_vect));
9957ff178cdSJimmy Vetayases 		return (0);
9967ff178cdSJimmy Vetayases 	}
9977ff178cdSJimmy Vetayases 
9987ff178cdSJimmy Vetayases 	if (v >= APIX_IPI_MIN)	/* IPIs */
9997ff178cdSJimmy Vetayases 		return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2));
10007ff178cdSJimmy Vetayases 
10017ff178cdSJimmy Vetayases 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
10027ff178cdSJimmy Vetayases 		int irqno = virt_vect;
10037ff178cdSJimmy Vetayases 		int inum = GET_INTR_INUM(intr_id);
10047ff178cdSJimmy Vetayases 
10057ff178cdSJimmy Vetayases 		/*
10067ff178cdSJimmy Vetayases 		 * Senarios include:
10077ff178cdSJimmy Vetayases 		 * a. add_avintr() is called before irqp initialized (legacy)
10087ff178cdSJimmy Vetayases 		 * b. irqp is initialized, vector is not allocated (fixed)
10097ff178cdSJimmy Vetayases 		 * c. irqp is initialized, vector is allocated (fixed & shared)
10107ff178cdSJimmy Vetayases 		 */
10117ff178cdSJimmy Vetayases 		if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL)
10127ff178cdSJimmy Vetayases 			return (0);
10137ff178cdSJimmy Vetayases 
10147ff178cdSJimmy Vetayases 		cpuid = vecp->v_cpuid;
10157ff178cdSJimmy Vetayases 		v = vecp->v_vector;
10167ff178cdSJimmy Vetayases 		virt_vect = APIX_VIRTVECTOR(cpuid, v);
10177ff178cdSJimmy Vetayases 	} else {	/* got virtual vector */
10187ff178cdSJimmy Vetayases 		cpuid = APIX_VIRTVEC_CPU(virt_vect);
10197ff178cdSJimmy Vetayases 		vecp = xv_vector(cpuid, v);
10207ff178cdSJimmy Vetayases 		ASSERT(vecp != NULL);
10217ff178cdSJimmy Vetayases 	}
10227ff178cdSJimmy Vetayases 
10237ff178cdSJimmy Vetayases 	lock_set(&apix_lock);
10247ff178cdSJimmy Vetayases 	if (vecp->v_state <= APIX_STATE_OBSOLETED) {
10257ff178cdSJimmy Vetayases 		vecp = NULL;
10267ff178cdSJimmy Vetayases 
10277ff178cdSJimmy Vetayases 		/*
10287ff178cdSJimmy Vetayases 		 * Basically the allocated but not enabled interrupts
10297ff178cdSJimmy Vetayases 		 * will not get re-targeted. But MSIs in allocated state
10307ff178cdSJimmy Vetayases 		 * could be re-targeted due to group re-targeting.
10317ff178cdSJimmy Vetayases 		 */
10327ff178cdSJimmy Vetayases 		if (intr_id != NULL && dip != NULL) {
10337ff178cdSJimmy Vetayases 			ddi_intr_handle_impl_t *hdlp = intr_id;
10347ff178cdSJimmy Vetayases 			vecp = apix_get_dev_map(dip, hdlp->ih_inum,
10357ff178cdSJimmy Vetayases 			    hdlp->ih_type);
10367ff178cdSJimmy Vetayases 			ASSERT(vecp->v_state == APIX_STATE_ALLOCED);
10377ff178cdSJimmy Vetayases 		}
10387ff178cdSJimmy Vetayases 		if (vecp == NULL) {
10397ff178cdSJimmy Vetayases 			lock_clear(&apix_lock);
10407ff178cdSJimmy Vetayases 			cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x "
10417ff178cdSJimmy Vetayases 			    " for %p to add", cpuid, v, intr_id);
10427ff178cdSJimmy Vetayases 			return (0);
10437ff178cdSJimmy Vetayases 		}
10447ff178cdSJimmy Vetayases 		cpuid = vecp->v_cpuid;
10457ff178cdSJimmy Vetayases 		virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector);
10467ff178cdSJimmy Vetayases 	}
10477ff178cdSJimmy Vetayases 
10487ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(cpuid);
10497ff178cdSJimmy Vetayases 	apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip);
10507ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(cpuid);
10517ff178cdSJimmy Vetayases 
10527ff178cdSJimmy Vetayases 	(void) apix_addspl(virt_vect, ipl, 0, 0);
10537ff178cdSJimmy Vetayases 
10547ff178cdSJimmy Vetayases 	lock_clear(&apix_lock);
10557ff178cdSJimmy Vetayases 
10567ff178cdSJimmy Vetayases 	return (1);
10577ff178cdSJimmy Vetayases }
10587ff178cdSJimmy Vetayases 
10597ff178cdSJimmy Vetayases /*
10607ff178cdSJimmy Vetayases  * Remove avintr
10617ff178cdSJimmy Vetayases  *
10627ff178cdSJimmy Vetayases  * For fixed, if it's the last one of shared interrupts, free the vector.
10637ff178cdSJimmy Vetayases  * For msi/x, only disable the interrupt but not free the vector, which
10647ff178cdSJimmy Vetayases  * is freed by PSM_XXX_FREE_XXX.
10657ff178cdSJimmy Vetayases  */
10667ff178cdSJimmy Vetayases void
apix_rem_avintr(void * intr_id,int ipl,avfunc xxintr,int virt_vect)10677ff178cdSJimmy Vetayases apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect)
10687ff178cdSJimmy Vetayases {
10697ff178cdSJimmy Vetayases 	avfunc f;
10707ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
10717ff178cdSJimmy Vetayases 	struct autovec *avp;
10727ff178cdSJimmy Vetayases 	processorid_t cpuid;
10737ff178cdSJimmy Vetayases 
10747ff178cdSJimmy Vetayases 	if ((f = xxintr) == NULL)
10757ff178cdSJimmy Vetayases 		return;
10767ff178cdSJimmy Vetayases 
10777ff178cdSJimmy Vetayases 	lock_set(&apix_lock);
10787ff178cdSJimmy Vetayases 
10797ff178cdSJimmy Vetayases 	if (!APIX_IS_VIRTVEC(virt_vect)) {	/* got irq */
10807ff178cdSJimmy Vetayases 		vecp = apix_intx_get_vector(virt_vect);
10817ff178cdSJimmy Vetayases 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
10827ff178cdSJimmy Vetayases 	} else	/* got virtual vector */
10837ff178cdSJimmy Vetayases 		vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect),
10847ff178cdSJimmy Vetayases 		    APIX_VIRTVEC_VECTOR(virt_vect));
10857ff178cdSJimmy Vetayases 
10867ff178cdSJimmy Vetayases 	if (vecp == NULL) {
10877ff178cdSJimmy Vetayases 		lock_clear(&apix_lock);
10887ff178cdSJimmy Vetayases 		cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove",
10897ff178cdSJimmy Vetayases 		    APIX_VIRTVEC_CPU(virt_vect),
10907ff178cdSJimmy Vetayases 		    APIX_VIRTVEC_VECTOR(virt_vect));
10917ff178cdSJimmy Vetayases 		return;
10927ff178cdSJimmy Vetayases 	}
10937ff178cdSJimmy Vetayases 
10947ff178cdSJimmy Vetayases 	if (vecp->v_state <= APIX_STATE_OBSOLETED ||
10957ff178cdSJimmy Vetayases 	    ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) {
10967ff178cdSJimmy Vetayases 		/*
10977ff178cdSJimmy Vetayases 		 * It's possible that the interrupt is rebound to a
10987ff178cdSJimmy Vetayases 		 * different cpu before rem_avintr() is called. Search
10997ff178cdSJimmy Vetayases 		 * through all vectors once it happens.
11007ff178cdSJimmy Vetayases 		 */
11017ff178cdSJimmy Vetayases 		if ((vecp = apix_find_vector_by_avintr(intr_id, f))
11027ff178cdSJimmy Vetayases 		    == NULL) {
11037ff178cdSJimmy Vetayases 			lock_clear(&apix_lock);
11047ff178cdSJimmy Vetayases 			cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x "
11057ff178cdSJimmy Vetayases 			    "for %p to remove", APIX_VIRTVEC_CPU(virt_vect),
11067ff178cdSJimmy Vetayases 			    APIX_VIRTVEC_VECTOR(virt_vect), intr_id);
11077ff178cdSJimmy Vetayases 			return;
11087ff178cdSJimmy Vetayases 		}
11097ff178cdSJimmy Vetayases 		virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
11107ff178cdSJimmy Vetayases 		avp = apix_find_av(vecp, intr_id, f);
11117ff178cdSJimmy Vetayases 	}
11127ff178cdSJimmy Vetayases 	cpuid = vecp->v_cpuid;
11137ff178cdSJimmy Vetayases 
11147ff178cdSJimmy Vetayases 	/* disable interrupt */
11157ff178cdSJimmy Vetayases 	(void) apix_delspl(virt_vect, ipl, 0, 0);
11167ff178cdSJimmy Vetayases 
11177ff178cdSJimmy Vetayases 	/* remove ISR entry */
11187ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(cpuid);
11197ff178cdSJimmy Vetayases 	apix_remove_av(vecp, avp);
11207ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(cpuid);
11217ff178cdSJimmy Vetayases 
11227ff178cdSJimmy Vetayases 	lock_clear(&apix_lock);
11237ff178cdSJimmy Vetayases }
11247ff178cdSJimmy Vetayases 
11257ff178cdSJimmy Vetayases /*
11267ff178cdSJimmy Vetayases  * Device to vector mapping table
11277ff178cdSJimmy Vetayases  */
11287ff178cdSJimmy Vetayases 
11297ff178cdSJimmy Vetayases static void
apix_clear_dev_map(dev_info_t * dip,int inum,int type)11307ff178cdSJimmy Vetayases apix_clear_dev_map(dev_info_t *dip, int inum, int type)
11317ff178cdSJimmy Vetayases {
11327ff178cdSJimmy Vetayases 	char *name;
11337ff178cdSJimmy Vetayases 	major_t major;
11347ff178cdSJimmy Vetayases 	apix_dev_vector_t *dvp, *prev = NULL;
11357ff178cdSJimmy Vetayases 	int found = 0;
11367ff178cdSJimmy Vetayases 
11377ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
11387ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
11397ff178cdSJimmy Vetayases 
11407ff178cdSJimmy Vetayases 	mutex_enter(&apix_mutex);
11417ff178cdSJimmy Vetayases 
11427ff178cdSJimmy Vetayases 	for (dvp = apix_dev_vector[major]; dvp != NULL;
11437ff178cdSJimmy Vetayases 	    prev = dvp, dvp = dvp->dv_next) {
11447ff178cdSJimmy Vetayases 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
11457ff178cdSJimmy Vetayases 		    dvp->dv_type == type) {
11467ff178cdSJimmy Vetayases 			found++;
11477ff178cdSJimmy Vetayases 			break;
11487ff178cdSJimmy Vetayases 		}
11497ff178cdSJimmy Vetayases 	}
11507ff178cdSJimmy Vetayases 
11517ff178cdSJimmy Vetayases 	if (!found) {
11527ff178cdSJimmy Vetayases 		mutex_exit(&apix_mutex);
11537ff178cdSJimmy Vetayases 		return;
11547ff178cdSJimmy Vetayases 	}
11557ff178cdSJimmy Vetayases 
11567ff178cdSJimmy Vetayases 	if (prev != NULL)
11577ff178cdSJimmy Vetayases 		prev->dv_next = dvp->dv_next;
11587ff178cdSJimmy Vetayases 
11597ff178cdSJimmy Vetayases 	if (apix_dev_vector[major] == dvp)
11607ff178cdSJimmy Vetayases 		apix_dev_vector[major] = dvp->dv_next;
11617ff178cdSJimmy Vetayases 
11627ff178cdSJimmy Vetayases 	dvp->dv_vector->v_devp = NULL;
11637ff178cdSJimmy Vetayases 
11647ff178cdSJimmy Vetayases 	mutex_exit(&apix_mutex);
11657ff178cdSJimmy Vetayases 
11667ff178cdSJimmy Vetayases 	kmem_free(dvp, sizeof (apix_dev_vector_t));
11677ff178cdSJimmy Vetayases }
11687ff178cdSJimmy Vetayases 
11697ff178cdSJimmy Vetayases void
apix_set_dev_map(apix_vector_t * vecp,dev_info_t * dip,int inum)11707ff178cdSJimmy Vetayases apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum)
11717ff178cdSJimmy Vetayases {
11727ff178cdSJimmy Vetayases 	apix_dev_vector_t *dvp;
11737ff178cdSJimmy Vetayases 	char *name;
11747ff178cdSJimmy Vetayases 	major_t major;
11757ff178cdSJimmy Vetayases 	uint32_t found = 0;
11767ff178cdSJimmy Vetayases 
11777ff178cdSJimmy Vetayases 	ASSERT(dip != NULL);
11787ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
11797ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
11807ff178cdSJimmy Vetayases 
11817ff178cdSJimmy Vetayases 	mutex_enter(&apix_mutex);
11827ff178cdSJimmy Vetayases 
11837ff178cdSJimmy Vetayases 	for (dvp = apix_dev_vector[major]; dvp != NULL;
11847ff178cdSJimmy Vetayases 	    dvp = dvp->dv_next) {
11857ff178cdSJimmy Vetayases 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
11867ff178cdSJimmy Vetayases 		    dvp->dv_type == vecp->v_type) {
11877ff178cdSJimmy Vetayases 			found++;
11887ff178cdSJimmy Vetayases 			break;
11897ff178cdSJimmy Vetayases 		}
11907ff178cdSJimmy Vetayases 	}
11917ff178cdSJimmy Vetayases 
11927ff178cdSJimmy Vetayases 	if (found == 0) {	/* not found */
11937ff178cdSJimmy Vetayases 		dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP);
11947ff178cdSJimmy Vetayases 		dvp->dv_dip = dip;
11957ff178cdSJimmy Vetayases 		dvp->dv_inum = inum;
11967ff178cdSJimmy Vetayases 		dvp->dv_type = vecp->v_type;
11977ff178cdSJimmy Vetayases 
11987ff178cdSJimmy Vetayases 		dvp->dv_next = apix_dev_vector[major];
11997ff178cdSJimmy Vetayases 		apix_dev_vector[major] = dvp;
12007ff178cdSJimmy Vetayases 	}
12017ff178cdSJimmy Vetayases 	dvp->dv_vector = vecp;
12027ff178cdSJimmy Vetayases 	vecp->v_devp = dvp;
12037ff178cdSJimmy Vetayases 
12047ff178cdSJimmy Vetayases 	mutex_exit(&apix_mutex);
12057ff178cdSJimmy Vetayases 
12067ff178cdSJimmy Vetayases 	DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p "
12077ff178cdSJimmy Vetayases 	    "inum=0x%x  vector=0x%x/0x%x\n",
12087ff178cdSJimmy Vetayases 	    (void *)dip, inum, vecp->v_cpuid, vecp->v_vector));
12097ff178cdSJimmy Vetayases }
12107ff178cdSJimmy Vetayases 
12117ff178cdSJimmy Vetayases apix_vector_t *
apix_get_dev_map(dev_info_t * dip,int inum,int type)12127ff178cdSJimmy Vetayases apix_get_dev_map(dev_info_t *dip, int inum, int type)
12137ff178cdSJimmy Vetayases {
12147ff178cdSJimmy Vetayases 	char *name;
12157ff178cdSJimmy Vetayases 	major_t major;
12167ff178cdSJimmy Vetayases 	apix_dev_vector_t *dvp;
12177ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
12187ff178cdSJimmy Vetayases 
12197ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
12207ff178cdSJimmy Vetayases 	if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE)
12217ff178cdSJimmy Vetayases 		return (NULL);
12227ff178cdSJimmy Vetayases 
12237ff178cdSJimmy Vetayases 	mutex_enter(&apix_mutex);
12247ff178cdSJimmy Vetayases 	for (dvp = apix_dev_vector[major]; dvp != NULL;
12257ff178cdSJimmy Vetayases 	    dvp = dvp->dv_next) {
12267ff178cdSJimmy Vetayases 		if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
12277ff178cdSJimmy Vetayases 		    dvp->dv_type == type) {
12287ff178cdSJimmy Vetayases 			vecp = dvp->dv_vector;
12297ff178cdSJimmy Vetayases 			mutex_exit(&apix_mutex);
12307ff178cdSJimmy Vetayases 			return (vecp);
12317ff178cdSJimmy Vetayases 		}
12327ff178cdSJimmy Vetayases 	}
12337ff178cdSJimmy Vetayases 	mutex_exit(&apix_mutex);
12347ff178cdSJimmy Vetayases 
12357ff178cdSJimmy Vetayases 	return (NULL);
12367ff178cdSJimmy Vetayases }
12377ff178cdSJimmy Vetayases 
12387ff178cdSJimmy Vetayases /*
12397ff178cdSJimmy Vetayases  * Get minimum inum for specified device, used for MSI
12407ff178cdSJimmy Vetayases  */
12417ff178cdSJimmy Vetayases int
apix_get_min_dev_inum(dev_info_t * dip,int type)12427ff178cdSJimmy Vetayases apix_get_min_dev_inum(dev_info_t *dip, int type)
12437ff178cdSJimmy Vetayases {
12447ff178cdSJimmy Vetayases 	char *name;
12457ff178cdSJimmy Vetayases 	major_t major;
12467ff178cdSJimmy Vetayases 	apix_dev_vector_t *dvp;
12477ff178cdSJimmy Vetayases 	int inum = -1;
12487ff178cdSJimmy Vetayases 
12497ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
12507ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
12517ff178cdSJimmy Vetayases 
12527ff178cdSJimmy Vetayases 	mutex_enter(&apix_mutex);
12537ff178cdSJimmy Vetayases 	for (dvp = apix_dev_vector[major]; dvp != NULL;
12547ff178cdSJimmy Vetayases 	    dvp = dvp->dv_next) {
12557ff178cdSJimmy Vetayases 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
12567ff178cdSJimmy Vetayases 			if (inum == -1)
12577ff178cdSJimmy Vetayases 				inum = dvp->dv_inum;
12587ff178cdSJimmy Vetayases 			else
12597ff178cdSJimmy Vetayases 				inum = (dvp->dv_inum < inum) ?
12607ff178cdSJimmy Vetayases 				    dvp->dv_inum : inum;
12617ff178cdSJimmy Vetayases 		}
12627ff178cdSJimmy Vetayases 	}
12637ff178cdSJimmy Vetayases 	mutex_exit(&apix_mutex);
12647ff178cdSJimmy Vetayases 
12657ff178cdSJimmy Vetayases 	return (inum);
12667ff178cdSJimmy Vetayases }
12677ff178cdSJimmy Vetayases 
12687ff178cdSJimmy Vetayases int
apix_get_max_dev_inum(dev_info_t * dip,int type)12697ff178cdSJimmy Vetayases apix_get_max_dev_inum(dev_info_t *dip, int type)
12707ff178cdSJimmy Vetayases {
12717ff178cdSJimmy Vetayases 	char *name;
12727ff178cdSJimmy Vetayases 	major_t major;
12737ff178cdSJimmy Vetayases 	apix_dev_vector_t *dvp;
12747ff178cdSJimmy Vetayases 	int inum = -1;
12757ff178cdSJimmy Vetayases 
12767ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
12777ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
12787ff178cdSJimmy Vetayases 
12797ff178cdSJimmy Vetayases 	mutex_enter(&apix_mutex);
12807ff178cdSJimmy Vetayases 	for (dvp = apix_dev_vector[major]; dvp != NULL;
12817ff178cdSJimmy Vetayases 	    dvp = dvp->dv_next) {
12827ff178cdSJimmy Vetayases 		if (dvp->dv_dip == dip && dvp->dv_type == type) {
12837ff178cdSJimmy Vetayases 			if (inum == -1)
12847ff178cdSJimmy Vetayases 				inum = dvp->dv_inum;
12857ff178cdSJimmy Vetayases 			else
12867ff178cdSJimmy Vetayases 				inum = (dvp->dv_inum > inum) ?
12877ff178cdSJimmy Vetayases 				    dvp->dv_inum : inum;
12887ff178cdSJimmy Vetayases 		}
12897ff178cdSJimmy Vetayases 	}
12907ff178cdSJimmy Vetayases 	mutex_exit(&apix_mutex);
12917ff178cdSJimmy Vetayases 
12927ff178cdSJimmy Vetayases 	return (inum);
12937ff178cdSJimmy Vetayases }
12947ff178cdSJimmy Vetayases 
12957ff178cdSJimmy Vetayases /*
12967ff178cdSJimmy Vetayases  * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu
12977ff178cdSJimmy Vetayases  * binding policy
12987ff178cdSJimmy Vetayases  */
12997ff178cdSJimmy Vetayases 
13007ff178cdSJimmy Vetayases static uint32_t
apix_get_dev_binding(dev_info_t * dip)13017ff178cdSJimmy Vetayases apix_get_dev_binding(dev_info_t *dip)
13027ff178cdSJimmy Vetayases {
13037ff178cdSJimmy Vetayases 	major_t major;
13047ff178cdSJimmy Vetayases 	char *name;
13057ff178cdSJimmy Vetayases 	uint32_t cpu = IRQ_UNINIT;
13067ff178cdSJimmy Vetayases 
13077ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
13087ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
13097ff178cdSJimmy Vetayases 	if (major < devcnt) {
13107ff178cdSJimmy Vetayases 		mutex_enter(&apix_mutex);
13117ff178cdSJimmy Vetayases 		cpu = apix_major_to_cpu[major];
13127ff178cdSJimmy Vetayases 		mutex_exit(&apix_mutex);
13137ff178cdSJimmy Vetayases 	}
13147ff178cdSJimmy Vetayases 
13157ff178cdSJimmy Vetayases 	return (cpu);
13167ff178cdSJimmy Vetayases }
13177ff178cdSJimmy Vetayases 
13187ff178cdSJimmy Vetayases static void
apix_set_dev_binding(dev_info_t * dip,uint32_t cpu)13197ff178cdSJimmy Vetayases apix_set_dev_binding(dev_info_t *dip, uint32_t cpu)
13207ff178cdSJimmy Vetayases {
13217ff178cdSJimmy Vetayases 	major_t major;
13227ff178cdSJimmy Vetayases 	char *name;
13237ff178cdSJimmy Vetayases 
13247ff178cdSJimmy Vetayases 	/* setup major to cpu mapping */
13257ff178cdSJimmy Vetayases 	name = ddi_get_name(dip);
13267ff178cdSJimmy Vetayases 	major = ddi_name_to_major(name);
13277ff178cdSJimmy Vetayases 	if (apix_major_to_cpu[major] == IRQ_UNINIT) {
13287ff178cdSJimmy Vetayases 		mutex_enter(&apix_mutex);
13297ff178cdSJimmy Vetayases 		apix_major_to_cpu[major] = cpu;
13307ff178cdSJimmy Vetayases 		mutex_exit(&apix_mutex);
13317ff178cdSJimmy Vetayases 	}
13327ff178cdSJimmy Vetayases }
13337ff178cdSJimmy Vetayases 
13347ff178cdSJimmy Vetayases /*
13357ff178cdSJimmy Vetayases  * return the cpu to which this intr should be bound.
13367ff178cdSJimmy Vetayases  * Check properties or any other mechanism to see if user wants it
13377ff178cdSJimmy Vetayases  * bound to a specific CPU. If so, return the cpu id with high bit set.
13387ff178cdSJimmy Vetayases  * If not, use the policy to choose a cpu and return the id.
13397ff178cdSJimmy Vetayases  */
13407ff178cdSJimmy Vetayases uint32_t
apix_bind_cpu(dev_info_t * dip)13417ff178cdSJimmy Vetayases apix_bind_cpu(dev_info_t *dip)
13427ff178cdSJimmy Vetayases {
13437ff178cdSJimmy Vetayases 	int	instance, instno, prop_len, bind_cpu, count;
13447ff178cdSJimmy Vetayases 	uint_t	i, rc;
13457ff178cdSJimmy Vetayases 	major_t	major;
13467ff178cdSJimmy Vetayases 	char	*name, *drv_name, *prop_val, *cptr;
13477ff178cdSJimmy Vetayases 	char	prop_name[32];
13487ff178cdSJimmy Vetayases 
13497ff178cdSJimmy Vetayases 	lock_set(&apix_lock);
13507ff178cdSJimmy Vetayases 
13517ff178cdSJimmy Vetayases 	if (apic_intr_policy == INTR_LOWEST_PRIORITY) {
13527ff178cdSJimmy Vetayases 		cmn_err(CE_WARN, "apix: unsupported interrupt binding policy "
13537ff178cdSJimmy Vetayases 		    "LOWEST PRIORITY, use ROUND ROBIN instead");
13547ff178cdSJimmy Vetayases 		apic_intr_policy = INTR_ROUND_ROBIN;
13557ff178cdSJimmy Vetayases 	}
13567ff178cdSJimmy Vetayases 
13577ff178cdSJimmy Vetayases 	if (apic_nproc == 1) {
13587ff178cdSJimmy Vetayases 		lock_clear(&apix_lock);
13597ff178cdSJimmy Vetayases 		return (0);
13607ff178cdSJimmy Vetayases 	}
13617ff178cdSJimmy Vetayases 
13627ff178cdSJimmy Vetayases 	drv_name = NULL;
13637ff178cdSJimmy Vetayases 	rc = DDI_PROP_NOT_FOUND;
13647ff178cdSJimmy Vetayases 	major = (major_t)-1;
13657ff178cdSJimmy Vetayases 	if (dip != NULL) {
13667ff178cdSJimmy Vetayases 		name = ddi_get_name(dip);
13677ff178cdSJimmy Vetayases 		major = ddi_name_to_major(name);
13687ff178cdSJimmy Vetayases 		drv_name = ddi_major_to_name(major);
13697ff178cdSJimmy Vetayases 		instance = ddi_get_instance(dip);
13707ff178cdSJimmy Vetayases 		if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
13717ff178cdSJimmy Vetayases 			bind_cpu = apix_get_dev_binding(dip);
13727ff178cdSJimmy Vetayases 			if (bind_cpu != IRQ_UNINIT) {
13737ff178cdSJimmy Vetayases 				lock_clear(&apix_lock);
13747ff178cdSJimmy Vetayases 				return (bind_cpu);
13757ff178cdSJimmy Vetayases 			}
13767ff178cdSJimmy Vetayases 		}
13777ff178cdSJimmy Vetayases 		/*
13787ff178cdSJimmy Vetayases 		 * search for "drvname"_intpt_bind_cpus property first, the
13797ff178cdSJimmy Vetayases 		 * syntax of the property should be "a[,b,c,...]" where
13807ff178cdSJimmy Vetayases 		 * instance 0 binds to cpu a, instance 1 binds to cpu b,
13817ff178cdSJimmy Vetayases 		 * instance 3 binds to cpu c...
13827ff178cdSJimmy Vetayases 		 * ddi_getlongprop() will search /option first, then /
13837ff178cdSJimmy Vetayases 		 * if "drvname"_intpt_bind_cpus doesn't exist, then find
13847ff178cdSJimmy Vetayases 		 * intpt_bind_cpus property.  The syntax is the same, and
13857ff178cdSJimmy Vetayases 		 * it applies to all the devices if its "drvname" specific
13867ff178cdSJimmy Vetayases 		 * property doesn't exist
13877ff178cdSJimmy Vetayases 		 */
13887ff178cdSJimmy Vetayases 		(void) strcpy(prop_name, drv_name);
13897ff178cdSJimmy Vetayases 		(void) strcat(prop_name, "_intpt_bind_cpus");
13907ff178cdSJimmy Vetayases 		rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
13917ff178cdSJimmy Vetayases 		    (caddr_t)&prop_val, &prop_len);
13927ff178cdSJimmy Vetayases 		if (rc != DDI_PROP_SUCCESS) {
13937ff178cdSJimmy Vetayases 			rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
13947ff178cdSJimmy Vetayases 			    "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
13957ff178cdSJimmy Vetayases 		}
13967ff178cdSJimmy Vetayases 	}
13977ff178cdSJimmy Vetayases 	if (rc == DDI_PROP_SUCCESS) {
13987ff178cdSJimmy Vetayases 		for (i = count = 0; i < (prop_len - 1); i++)
13997ff178cdSJimmy Vetayases 			if (prop_val[i] == ',')
14007ff178cdSJimmy Vetayases 				count++;
14017ff178cdSJimmy Vetayases 		if (prop_val[i-1] != ',')
14027ff178cdSJimmy Vetayases 			count++;
14037ff178cdSJimmy Vetayases 		/*
14047ff178cdSJimmy Vetayases 		 * if somehow the binding instances defined in the
14057ff178cdSJimmy Vetayases 		 * property are not enough for this instno., then
14067ff178cdSJimmy Vetayases 		 * reuse the pattern for the next instance until
14077ff178cdSJimmy Vetayases 		 * it reaches the requested instno
14087ff178cdSJimmy Vetayases 		 */
14097ff178cdSJimmy Vetayases 		instno = instance % count;
14107ff178cdSJimmy Vetayases 		i = 0;
14117ff178cdSJimmy Vetayases 		cptr = prop_val;
14127ff178cdSJimmy Vetayases 		while (i < instno)
14137ff178cdSJimmy Vetayases 			if (*cptr++ == ',')
14147ff178cdSJimmy Vetayases 				i++;
14157ff178cdSJimmy Vetayases 		bind_cpu = stoi(&cptr);
14167ff178cdSJimmy Vetayases 		kmem_free(prop_val, prop_len);
14177ff178cdSJimmy Vetayases 		/* if specific cpu is bogus, then default to cpu 0 */
14187ff178cdSJimmy Vetayases 		if (bind_cpu >= apic_nproc) {
14197ff178cdSJimmy Vetayases 			cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present",
14207ff178cdSJimmy Vetayases 			    prop_name, prop_val, bind_cpu);
14217ff178cdSJimmy Vetayases 			bind_cpu = 0;
14227ff178cdSJimmy Vetayases 		} else {
14237ff178cdSJimmy Vetayases 			/* indicate that we are bound at user request */
14247ff178cdSJimmy Vetayases 			bind_cpu |= IRQ_USER_BOUND;
14257ff178cdSJimmy Vetayases 		}
14267ff178cdSJimmy Vetayases 		/*
14277ff178cdSJimmy Vetayases 		 * no need to check apic_cpus[].aci_status, if specific cpu is
14287ff178cdSJimmy Vetayases 		 * not up, then post_cpu_start will handle it.
14297ff178cdSJimmy Vetayases 		 */
14307ff178cdSJimmy Vetayases 	} else {
14317ff178cdSJimmy Vetayases 		bind_cpu = apic_get_next_bind_cpu();
14327ff178cdSJimmy Vetayases 	}
14337ff178cdSJimmy Vetayases 
14347ff178cdSJimmy Vetayases 	lock_clear(&apix_lock);
14357ff178cdSJimmy Vetayases 
14367ff178cdSJimmy Vetayases 	return ((uint32_t)bind_cpu);
14377ff178cdSJimmy Vetayases }
14387ff178cdSJimmy Vetayases 
14397ff178cdSJimmy Vetayases static boolean_t
apix_is_cpu_enabled(processorid_t cpuid)14407ff178cdSJimmy Vetayases apix_is_cpu_enabled(processorid_t cpuid)
14417ff178cdSJimmy Vetayases {
14427ff178cdSJimmy Vetayases 	apic_cpus_info_t *cpu_infop;
14437ff178cdSJimmy Vetayases 
14447ff178cdSJimmy Vetayases 	cpu_infop = &apic_cpus[cpuid];
14457ff178cdSJimmy Vetayases 
14467ff178cdSJimmy Vetayases 	if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0)
14477ff178cdSJimmy Vetayases 		return (B_FALSE);
14487ff178cdSJimmy Vetayases 
14497ff178cdSJimmy Vetayases 	return (B_TRUE);
14507ff178cdSJimmy Vetayases }
14517ff178cdSJimmy Vetayases 
14527ff178cdSJimmy Vetayases /*
14537ff178cdSJimmy Vetayases  * Must be called with apix_lock held. This function can be
14547ff178cdSJimmy Vetayases  * called from above lock level by apix_intr_redistribute().
14557ff178cdSJimmy Vetayases  *
14567ff178cdSJimmy Vetayases  * Arguments:
14577ff178cdSJimmy Vetayases  *    vecp  : Vector to be rebound
14587ff178cdSJimmy Vetayases  *    tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid.
14597ff178cdSJimmy Vetayases  *    count : Number of continuous vectors
14607ff178cdSJimmy Vetayases  *
14617ff178cdSJimmy Vetayases  * Return new vector being bound to
14627ff178cdSJimmy Vetayases  */
14637ff178cdSJimmy Vetayases apix_vector_t *
apix_rebind(apix_vector_t * vecp,processorid_t newcpu,int count)14647ff178cdSJimmy Vetayases apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count)
14657ff178cdSJimmy Vetayases {
14667ff178cdSJimmy Vetayases 	apix_vector_t *newp, *oldp;
14677ff178cdSJimmy Vetayases 	processorid_t oldcpu = vecp->v_cpuid;
14687ff178cdSJimmy Vetayases 	uchar_t newvec, oldvec = vecp->v_vector;
14697ff178cdSJimmy Vetayases 	int i;
14707ff178cdSJimmy Vetayases 
14717ff178cdSJimmy Vetayases 	ASSERT(LOCK_HELD(&apix_lock) && count > 0);
14727ff178cdSJimmy Vetayases 
14737ff178cdSJimmy Vetayases 	if (!apix_is_cpu_enabled(newcpu))
14747ff178cdSJimmy Vetayases 		return (NULL);
14757ff178cdSJimmy Vetayases 
1476455e370cSJohn Levon 	if (vecp->v_cpuid == newcpu)	/* rebind to the same cpu */
14777ff178cdSJimmy Vetayases 		return (vecp);
14787ff178cdSJimmy Vetayases 
14797ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(oldcpu);
14807ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(newcpu);
14817ff178cdSJimmy Vetayases 
14827ff178cdSJimmy Vetayases 	/* allocate vector */
14837ff178cdSJimmy Vetayases 	if (count == 1)
14847ff178cdSJimmy Vetayases 		newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type);
14857ff178cdSJimmy Vetayases 	else {
14867ff178cdSJimmy Vetayases 		ASSERT(vecp->v_type == APIX_TYPE_MSI);
14877ff178cdSJimmy Vetayases 		newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count,
14887ff178cdSJimmy Vetayases 		    vecp->v_type);
14897ff178cdSJimmy Vetayases 	}
14907ff178cdSJimmy Vetayases 	if (newp == NULL) {
14917ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(newcpu);
14927ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(oldcpu);
14937ff178cdSJimmy Vetayases 		return (NULL);
14947ff178cdSJimmy Vetayases 	}
14957ff178cdSJimmy Vetayases 
14967ff178cdSJimmy Vetayases 	newvec = newp->v_vector;
14977ff178cdSJimmy Vetayases 	apix_dup_vectors(vecp, newp, count);
14987ff178cdSJimmy Vetayases 
14997ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(newcpu);
15007ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(oldcpu);
15017ff178cdSJimmy Vetayases 
15027ff178cdSJimmy Vetayases 	if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {
15037ff178cdSJimmy Vetayases 		ASSERT(count == 1);
15047ff178cdSJimmy Vetayases 		if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) {
15057ff178cdSJimmy Vetayases 			struct autovec *avp;
15067ff178cdSJimmy Vetayases 			int inum;
15077ff178cdSJimmy Vetayases 
15087ff178cdSJimmy Vetayases 			/* undo duplication */
15097ff178cdSJimmy Vetayases 			APIX_ENTER_CPU_LOCK(oldcpu);
15107ff178cdSJimmy Vetayases 			APIX_ENTER_CPU_LOCK(newcpu);
15117ff178cdSJimmy Vetayases 			for (avp = newp->v_autovect; avp != NULL;
15127ff178cdSJimmy Vetayases 			    avp = avp->av_link) {
15137ff178cdSJimmy Vetayases 				if (avp->av_dip != NULL) {
15147ff178cdSJimmy Vetayases 					inum = GET_INTR_INUM(avp->av_intr_id);
15157ff178cdSJimmy Vetayases 					apix_set_dev_map(vecp, avp->av_dip,
15167ff178cdSJimmy Vetayases 					    inum);
15177ff178cdSJimmy Vetayases 				}
15187ff178cdSJimmy Vetayases 				apix_remove_av(newp, avp);
15197ff178cdSJimmy Vetayases 			}
15207ff178cdSJimmy Vetayases 			apix_cleanup_vector(newp);
15217ff178cdSJimmy Vetayases 			APIX_LEAVE_CPU_LOCK(newcpu);
15227ff178cdSJimmy Vetayases 			APIX_LEAVE_CPU_LOCK(oldcpu);
15237ff178cdSJimmy Vetayases 			APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed "
15247ff178cdSJimmy Vetayases 			    "interrupt 0x%x to cpu %d failed\n",
15257ff178cdSJimmy Vetayases 			    vecp->v_inum, newcpu));
15267ff178cdSJimmy Vetayases 			return (NULL);
15277ff178cdSJimmy Vetayases 		}
15287ff178cdSJimmy Vetayases 
15297ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(oldcpu);
15307ff178cdSJimmy Vetayases 		(void) apix_obsolete_vector(vecp);
15317ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(oldcpu);
15327ff178cdSJimmy Vetayases 		APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt"
15337ff178cdSJimmy Vetayases 		    " 0x%x/0x%x to 0x%x/0x%x\n",
15347ff178cdSJimmy Vetayases 		    oldcpu, oldvec, newcpu, newvec));
15357ff178cdSJimmy Vetayases 		return (newp);
15367ff178cdSJimmy Vetayases 	}
15377ff178cdSJimmy Vetayases 
15387ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++) {
15397ff178cdSJimmy Vetayases 		oldp = xv_vector(oldcpu, oldvec + i);
15407ff178cdSJimmy Vetayases 		newp = xv_vector(newcpu, newvec + i);
15417ff178cdSJimmy Vetayases 
15427ff178cdSJimmy Vetayases 		if (newp->v_share > 0) {
15437ff178cdSJimmy Vetayases 			APIX_SET_REBIND_INFO(oldp, newp);
15447ff178cdSJimmy Vetayases 
15457ff178cdSJimmy Vetayases 			apix_enable_vector(newp);
15467ff178cdSJimmy Vetayases 
15477ff178cdSJimmy Vetayases 			APIX_CLR_REBIND_INFO();
15487ff178cdSJimmy Vetayases 		}
15497ff178cdSJimmy Vetayases 
15507ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(oldcpu);
15517ff178cdSJimmy Vetayases 		(void) apix_obsolete_vector(oldp);
15527ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(oldcpu);
15537ff178cdSJimmy Vetayases 	}
15547ff178cdSJimmy Vetayases 	APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x "
15557ff178cdSJimmy Vetayases 	    "to 0x%x/0x%x, count=%d\n",
15567ff178cdSJimmy Vetayases 	    oldcpu, oldvec, newcpu, newvec, count));
15577ff178cdSJimmy Vetayases 
15587ff178cdSJimmy Vetayases 	return (xv_vector(newcpu, newvec));
15597ff178cdSJimmy Vetayases }
15607ff178cdSJimmy Vetayases 
15617ff178cdSJimmy Vetayases /*
15627ff178cdSJimmy Vetayases  * Senarios include:
15637ff178cdSJimmy Vetayases  * a. add_avintr() is called before irqp initialized (legacy)
15647ff178cdSJimmy Vetayases  * b. irqp is initialized, vector is not allocated (fixed interrupts)
15657ff178cdSJimmy Vetayases  * c. irqp is initialized, vector is allocated (shared interrupts)
15667ff178cdSJimmy Vetayases  */
15677ff178cdSJimmy Vetayases apix_vector_t *
apix_alloc_intx(dev_info_t * dip,int inum,int irqno)15687ff178cdSJimmy Vetayases apix_alloc_intx(dev_info_t *dip, int inum, int irqno)
15697ff178cdSJimmy Vetayases {
15707ff178cdSJimmy Vetayases 	apic_irq_t *irqp;
15717ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
15727ff178cdSJimmy Vetayases 
15737ff178cdSJimmy Vetayases 	/*
15747ff178cdSJimmy Vetayases 	 * Allocate IRQ. Caller is later responsible for the
15757ff178cdSJimmy Vetayases 	 * initialization
15767ff178cdSJimmy Vetayases 	 */
15777ff178cdSJimmy Vetayases 	mutex_enter(&airq_mutex);
15787ff178cdSJimmy Vetayases 	if ((irqp = apic_irq_table[irqno]) == NULL) {
15797ff178cdSJimmy Vetayases 		/* allocate irq */
15807ff178cdSJimmy Vetayases 		irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
15817ff178cdSJimmy Vetayases 		irqp->airq_mps_intr_index = FREE_INDEX;
15827ff178cdSJimmy Vetayases 		apic_irq_table[irqno] = irqp;
15837ff178cdSJimmy Vetayases 	}
15847ff178cdSJimmy Vetayases 	if (irqp->airq_mps_intr_index == FREE_INDEX) {
15857ff178cdSJimmy Vetayases 		irqp->airq_mps_intr_index = DEFAULT_INDEX;
15867ff178cdSJimmy Vetayases 		irqp->airq_cpu = IRQ_UNINIT;
15877ff178cdSJimmy Vetayases 		irqp->airq_origirq = (uchar_t)irqno;
15887ff178cdSJimmy Vetayases 	}
15897ff178cdSJimmy Vetayases 
15907ff178cdSJimmy Vetayases 	mutex_exit(&airq_mutex);
15917ff178cdSJimmy Vetayases 
15927ff178cdSJimmy Vetayases 	/*
15937ff178cdSJimmy Vetayases 	 * allocate vector
15947ff178cdSJimmy Vetayases 	 */
15957ff178cdSJimmy Vetayases 	if (irqp->airq_cpu == IRQ_UNINIT) {
15967ff178cdSJimmy Vetayases 		uint32_t bindcpu, cpuid;
15977ff178cdSJimmy Vetayases 
15987ff178cdSJimmy Vetayases 		/* select cpu by system policy */
15997ff178cdSJimmy Vetayases 		bindcpu = apix_bind_cpu(dip);
16007ff178cdSJimmy Vetayases 		cpuid = bindcpu & ~IRQ_USER_BOUND;
16017ff178cdSJimmy Vetayases 
16027ff178cdSJimmy Vetayases 		/* allocate vector */
16037ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(cpuid);
16047ff178cdSJimmy Vetayases 
16057ff178cdSJimmy Vetayases 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum,
16067ff178cdSJimmy Vetayases 		    APIX_TYPE_FIXED)) == NULL) {
16077ff178cdSJimmy Vetayases 			cmn_err(CE_WARN, "No interrupt vector for irq %x",
16087ff178cdSJimmy Vetayases 			    irqno);
16097ff178cdSJimmy Vetayases 			APIX_LEAVE_CPU_LOCK(cpuid);
16107ff178cdSJimmy Vetayases 			return (NULL);
16117ff178cdSJimmy Vetayases 		}
16127ff178cdSJimmy Vetayases 		vecp->v_inum = irqno;
16137ff178cdSJimmy Vetayases 		vecp->v_flags |= APIX_VECT_MASKABLE;
16147ff178cdSJimmy Vetayases 
16157ff178cdSJimmy Vetayases 		apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector);
16167ff178cdSJimmy Vetayases 
16177ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(cpuid);
16187ff178cdSJimmy Vetayases 	} else {
16197ff178cdSJimmy Vetayases 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
16207ff178cdSJimmy Vetayases 		ASSERT(!IS_VECT_FREE(vecp));
16217ff178cdSJimmy Vetayases 
16227ff178cdSJimmy Vetayases 		if (dip != NULL)
16237ff178cdSJimmy Vetayases 			apix_set_dev_map(vecp, dip, inum);
16247ff178cdSJimmy Vetayases 	}
16257ff178cdSJimmy Vetayases 
16267ff178cdSJimmy Vetayases 	if ((dip != NULL) &&
16277ff178cdSJimmy Vetayases 	    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
16287ff178cdSJimmy Vetayases 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
16297ff178cdSJimmy Vetayases 		apix_set_dev_binding(dip, vecp->v_cpuid);
16307ff178cdSJimmy Vetayases 
16317ff178cdSJimmy Vetayases 	apix_dprint_vector(vecp, dip, 1);
16327ff178cdSJimmy Vetayases 
16337ff178cdSJimmy Vetayases 	return (vecp);
16347ff178cdSJimmy Vetayases }
16357ff178cdSJimmy Vetayases 
16367ff178cdSJimmy Vetayases int
apix_alloc_msi(dev_info_t * dip,int inum,int count,int behavior)16377ff178cdSJimmy Vetayases apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior)
16387ff178cdSJimmy Vetayases {
16397ff178cdSJimmy Vetayases 	int i, cap_ptr, rcount = count;
16407ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
16417ff178cdSJimmy Vetayases 	processorid_t bindcpu, cpuid;
16427ff178cdSJimmy Vetayases 	ushort_t msi_ctrl;
16437ff178cdSJimmy Vetayases 	ddi_acc_handle_t handle;
16447ff178cdSJimmy Vetayases 
16457ff178cdSJimmy Vetayases 	DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p "
16467ff178cdSJimmy Vetayases 	    "inum=0x%x  count=0x%x behavior=%d\n",
16477ff178cdSJimmy Vetayases 	    (void *)dip, inum, count, behavior));
16487ff178cdSJimmy Vetayases 
16497ff178cdSJimmy Vetayases 	if (count > 1) {
16507ff178cdSJimmy Vetayases 		if (behavior == DDI_INTR_ALLOC_STRICT &&
16517ff178cdSJimmy Vetayases 		    apic_multi_msi_enable == 0)
16527ff178cdSJimmy Vetayases 			return (0);
16537ff178cdSJimmy Vetayases 		if (apic_multi_msi_enable == 0)
16547ff178cdSJimmy Vetayases 			count = 1;
16557ff178cdSJimmy Vetayases 	}
16567ff178cdSJimmy Vetayases 
16577ff178cdSJimmy Vetayases 	/* Check whether it supports per-vector masking */
16587ff178cdSJimmy Vetayases 	cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
16597ff178cdSJimmy Vetayases 	handle = i_ddi_get_pci_config_handle(dip);
16607ff178cdSJimmy Vetayases 	msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
16617ff178cdSJimmy Vetayases 
16627ff178cdSJimmy Vetayases 	/* bind to cpu */
16637ff178cdSJimmy Vetayases 	bindcpu = apix_bind_cpu(dip);
16647ff178cdSJimmy Vetayases 	cpuid = bindcpu & ~IRQ_USER_BOUND;
16657ff178cdSJimmy Vetayases 
16667ff178cdSJimmy Vetayases 	/* if not ISP2, then round it down */
16677ff178cdSJimmy Vetayases 	if (!ISP2(rcount))
16687ff178cdSJimmy Vetayases 		rcount = 1 << (highbit(rcount) - 1);
16697ff178cdSJimmy Vetayases 
16707ff178cdSJimmy Vetayases 	APIX_ENTER_CPU_LOCK(cpuid);
16717ff178cdSJimmy Vetayases 	for (vecp = NULL; rcount > 0; rcount >>= 1) {
16727ff178cdSJimmy Vetayases 		vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount,
16737ff178cdSJimmy Vetayases 		    APIX_TYPE_MSI);
16747ff178cdSJimmy Vetayases 		if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT)
16757ff178cdSJimmy Vetayases 			break;
16767ff178cdSJimmy Vetayases 	}
16777ff178cdSJimmy Vetayases 	for (i = 0; vecp && i < rcount; i++)
16787ff178cdSJimmy Vetayases 		xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |=
16797ff178cdSJimmy Vetayases 		    (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0;
16807ff178cdSJimmy Vetayases 	APIX_LEAVE_CPU_LOCK(cpuid);
16817ff178cdSJimmy Vetayases 	if (vecp == NULL) {
16827ff178cdSJimmy Vetayases 		APIC_VERBOSE(INTR, (CE_CONT,
16837ff178cdSJimmy Vetayases 		    "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n",
16847ff178cdSJimmy Vetayases 		    count, bindcpu));
16857ff178cdSJimmy Vetayases 		return (0);
16867ff178cdSJimmy Vetayases 	}
16877ff178cdSJimmy Vetayases 
16887ff178cdSJimmy Vetayases 	/* major to cpu binding */
16897ff178cdSJimmy Vetayases 	if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
16907ff178cdSJimmy Vetayases 	    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
16917ff178cdSJimmy Vetayases 		apix_set_dev_binding(dip, vecp->v_cpuid);
16927ff178cdSJimmy Vetayases 
16937ff178cdSJimmy Vetayases 	apix_dprint_vector(vecp, dip, rcount);
16947ff178cdSJimmy Vetayases 
16957ff178cdSJimmy Vetayases 	return (rcount);
16967ff178cdSJimmy Vetayases }
16977ff178cdSJimmy Vetayases 
16987ff178cdSJimmy Vetayases int
apix_alloc_msix(dev_info_t * dip,int inum,int count,int behavior)16997ff178cdSJimmy Vetayases apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior)
17007ff178cdSJimmy Vetayases {
17017ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
17027ff178cdSJimmy Vetayases 	processorid_t bindcpu, cpuid;
17037ff178cdSJimmy Vetayases 	int i;
17047ff178cdSJimmy Vetayases 
17057ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++) {
17067ff178cdSJimmy Vetayases 		/* select cpu by system policy */
17077ff178cdSJimmy Vetayases 		bindcpu = apix_bind_cpu(dip);
17087ff178cdSJimmy Vetayases 		cpuid = bindcpu & ~IRQ_USER_BOUND;
17097ff178cdSJimmy Vetayases 
17107ff178cdSJimmy Vetayases 		/* allocate vector */
17117ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(cpuid);
17127ff178cdSJimmy Vetayases 		if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i,
17137ff178cdSJimmy Vetayases 		    APIX_TYPE_MSIX)) == NULL) {
17147ff178cdSJimmy Vetayases 			APIX_LEAVE_CPU_LOCK(cpuid);
17157ff178cdSJimmy Vetayases 			APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: "
17167ff178cdSJimmy Vetayases 			    "allocate msix for device dip=%p, inum=%d on"
17177ff178cdSJimmy Vetayases 			    " cpu %d failed", (void *)dip, inum + i, bindcpu));
17187ff178cdSJimmy Vetayases 			break;
17197ff178cdSJimmy Vetayases 		}
17207ff178cdSJimmy Vetayases 		vecp->v_flags |= APIX_VECT_MASKABLE;
17217ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(cpuid);
17227ff178cdSJimmy Vetayases 
17237ff178cdSJimmy Vetayases 		/* major to cpu mapping */
17247ff178cdSJimmy Vetayases 		if ((i == 0) &&
17257ff178cdSJimmy Vetayases 		    (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
17267ff178cdSJimmy Vetayases 		    ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
17277ff178cdSJimmy Vetayases 			apix_set_dev_binding(dip, vecp->v_cpuid);
17287ff178cdSJimmy Vetayases 
17297ff178cdSJimmy Vetayases 		apix_dprint_vector(vecp, dip, 1);
17307ff178cdSJimmy Vetayases 	}
17317ff178cdSJimmy Vetayases 
17327ff178cdSJimmy Vetayases 	if (i < count && behavior == DDI_INTR_ALLOC_STRICT) {
17337ff178cdSJimmy Vetayases 		APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: "
17347ff178cdSJimmy Vetayases 		    "strictly allocate %d vectors failed, got %d\n",
17357ff178cdSJimmy Vetayases 		    count, i));
17367ff178cdSJimmy Vetayases 		apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX);
17377ff178cdSJimmy Vetayases 		i = 0;
17387ff178cdSJimmy Vetayases 	}
17397ff178cdSJimmy Vetayases 
17407ff178cdSJimmy Vetayases 	return (i);
17417ff178cdSJimmy Vetayases }
17427ff178cdSJimmy Vetayases 
17437ff178cdSJimmy Vetayases /*
17447ff178cdSJimmy Vetayases  * A rollback free for vectors allocated by apix_alloc_xxx().
17457ff178cdSJimmy Vetayases  */
17467ff178cdSJimmy Vetayases void
apix_free_vectors(dev_info_t * dip,int inum,int count,int type)17477ff178cdSJimmy Vetayases apix_free_vectors(dev_info_t *dip, int inum, int count, int type)
17487ff178cdSJimmy Vetayases {
17497ff178cdSJimmy Vetayases 	int i, cpuid;
17507ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
17517ff178cdSJimmy Vetayases 
17527ff178cdSJimmy Vetayases 	DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x "
17537ff178cdSJimmy Vetayases 	    "count: %x type: %x\n",
17547ff178cdSJimmy Vetayases 	    (void *)dip, inum, count, type));
17557ff178cdSJimmy Vetayases 
17567ff178cdSJimmy Vetayases 	lock_set(&apix_lock);
17577ff178cdSJimmy Vetayases 
17587ff178cdSJimmy Vetayases 	for (i = 0; i < count; i++, inum++) {
17597ff178cdSJimmy Vetayases 		if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) {
17607ff178cdSJimmy Vetayases 			lock_clear(&apix_lock);
17617ff178cdSJimmy Vetayases 			DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
17627ff178cdSJimmy Vetayases 			    "dip=0x%p inum=0x%x type=0x%x apix_find_intr() "
17637ff178cdSJimmy Vetayases 			    "failed\n", (void *)dip, inum, type));
17647ff178cdSJimmy Vetayases 			continue;
17657ff178cdSJimmy Vetayases 		}
17667ff178cdSJimmy Vetayases 
17677ff178cdSJimmy Vetayases 		APIX_ENTER_CPU_LOCK(vecp->v_cpuid);
17687ff178cdSJimmy Vetayases 		cpuid = vecp->v_cpuid;
17697ff178cdSJimmy Vetayases 
17707ff178cdSJimmy Vetayases 		DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
17717ff178cdSJimmy Vetayases 		    "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n",
17727ff178cdSJimmy Vetayases 		    (void *)dip, inum, type, vecp->v_vector, vecp->v_share));
17737ff178cdSJimmy Vetayases 
17747ff178cdSJimmy Vetayases 		/* tear down device interrupt to vector mapping */
17757ff178cdSJimmy Vetayases 		apix_clear_dev_map(dip, inum, type);
17767ff178cdSJimmy Vetayases 
17777ff178cdSJimmy Vetayases 		if (vecp->v_type == APIX_TYPE_FIXED) {
17787ff178cdSJimmy Vetayases 			if (vecp->v_share > 0) {	/* share IRQ line */
17797ff178cdSJimmy Vetayases 				APIX_LEAVE_CPU_LOCK(cpuid);
17807ff178cdSJimmy Vetayases 				continue;
17817ff178cdSJimmy Vetayases 			}
17827ff178cdSJimmy Vetayases 
17837ff178cdSJimmy Vetayases 			/* Free apic_irq_table entry */
17847ff178cdSJimmy Vetayases 			apix_intx_free(vecp->v_inum);
17857ff178cdSJimmy Vetayases 		}
17867ff178cdSJimmy Vetayases 
17877ff178cdSJimmy Vetayases 		/* free vector */
17887ff178cdSJimmy Vetayases 		apix_cleanup_vector(vecp);
17897ff178cdSJimmy Vetayases 
17907ff178cdSJimmy Vetayases 		APIX_LEAVE_CPU_LOCK(cpuid);
17917ff178cdSJimmy Vetayases 	}
17927ff178cdSJimmy Vetayases 
17937ff178cdSJimmy Vetayases 	lock_clear(&apix_lock);
17947ff178cdSJimmy Vetayases }
17957ff178cdSJimmy Vetayases 
17967ff178cdSJimmy Vetayases /*
17977ff178cdSJimmy Vetayases  * Must be called with apix_lock held
17987ff178cdSJimmy Vetayases  */
17997ff178cdSJimmy Vetayases apix_vector_t *
apix_setup_io_intr(apix_vector_t * vecp)18007ff178cdSJimmy Vetayases apix_setup_io_intr(apix_vector_t *vecp)
18017ff178cdSJimmy Vetayases {
18027ff178cdSJimmy Vetayases 	processorid_t bindcpu;
18037ff178cdSJimmy Vetayases 	int ret;
18047ff178cdSJimmy Vetayases 
18057ff178cdSJimmy Vetayases 	ASSERT(LOCK_HELD(&apix_lock));
18067ff178cdSJimmy Vetayases 
18077ff178cdSJimmy Vetayases 	/*
18087ff178cdSJimmy Vetayases 	 * Interrupts are enabled on the CPU, programme IOAPIC RDT
18097ff178cdSJimmy Vetayases 	 * entry or MSI/X address/data to enable the interrupt.
18107ff178cdSJimmy Vetayases 	 */
18117ff178cdSJimmy Vetayases 	if (apix_is_cpu_enabled(vecp->v_cpuid)) {
18127ff178cdSJimmy Vetayases 		apix_enable_vector(vecp);
18137ff178cdSJimmy Vetayases 		return (vecp);
18147ff178cdSJimmy Vetayases 	}
18157ff178cdSJimmy Vetayases 
18167ff178cdSJimmy Vetayases 	/*
18177ff178cdSJimmy Vetayases 	 * CPU is not up or interrupts are disabled. Fall back to the
18187ff178cdSJimmy Vetayases 	 * first avialable CPU.
18197ff178cdSJimmy Vetayases 	 */
18207ff178cdSJimmy Vetayases 	bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE);
18217ff178cdSJimmy Vetayases 
18227ff178cdSJimmy Vetayases 	if (vecp->v_type == APIX_TYPE_MSI)
18237ff178cdSJimmy Vetayases 		return (apix_grp_set_cpu(vecp, bindcpu, &ret));
18247ff178cdSJimmy Vetayases 
18257ff178cdSJimmy Vetayases 	return (apix_set_cpu(vecp, bindcpu, &ret));
18267ff178cdSJimmy Vetayases }
18277ff178cdSJimmy Vetayases 
18287ff178cdSJimmy Vetayases /*
18297ff178cdSJimmy Vetayases  * For interrupts which call add_avintr() before apic is initialized.
18307ff178cdSJimmy Vetayases  * ioapix_setup_intr() will
18317ff178cdSJimmy Vetayases  *   - allocate vector
18327ff178cdSJimmy Vetayases  *   - copy over ISR
18337ff178cdSJimmy Vetayases  */
18347ff178cdSJimmy Vetayases static void
ioapix_setup_intr(int irqno,iflag_t * flagp)18357ff178cdSJimmy Vetayases ioapix_setup_intr(int irqno, iflag_t *flagp)
18367ff178cdSJimmy Vetayases {
18377ff178cdSJimmy Vetayases 	extern struct av_head autovect[];
18387ff178cdSJimmy Vetayases 	apix_vector_t *vecp;
18397ff178cdSJimmy Vetayases 	apic_irq_t *irqp;
18407ff178cdSJimmy Vetayases 	uchar_t ioapicindex, ipin;
18417ff178cdSJimmy Vetayases 	ulong_t iflag;
18427ff178cdSJimmy Vetayases 	struct autovec *avp;
18437ff178cdSJimmy Vetayases 
18447ff178cdSJimmy Vetayases 	ioapicindex = acpi_find_ioapic(irqno);
18457ff178cdSJimmy Vetayases 	ASSERT(ioapicindex != 0xFF);
18467ff178cdSJimmy Vetayases 	ipin = irqno - apic_io_vectbase[ioapicindex];
18477ff178cdSJimmy Vetayases 
1848584d084aSHans Rosenfeld 	mutex_enter(&airq_mutex);
1849584d084aSHans Rosenfeld 	irqp = apic_irq_table[irqno];
1850584d084aSHans Rosenfeld 
1851584d084aSHans Rosenfeld 	/*
1852584d084aSHans Rosenfeld 	 * The irq table entry shouldn't exist unless the interrupts are shared.
1853584d084aSHans Rosenfeld 	 * In that case, make sure it matches what we would initialize it to.
1854584d084aSHans Rosenfeld 	 */
1855584d084aSHans Rosenfeld 	if (irqp != NULL) {
1856584d084aSHans Rosenfeld 		ASSERT(irqp->airq_mps_intr_index == ACPI_INDEX);
18577ff178cdSJimmy Vetayases 		ASSERT(irqp->airq_intin_no == ipin &&
18587ff178cdSJimmy Vetayases 		    irqp->airq_ioapicindex == ioapicindex);
18597ff178cdSJimmy Vetayases 		vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
18607ff178cdSJimmy Vetayases 		ASSERT(!IS_VECT_FREE(vecp));
1861584d084aSHans Rosenfeld 		mutex_exit(&airq_mutex);
18627ff178cdSJimmy Vetayases 	} else {
1863584d084aSHans Rosenfeld 		irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
18647ff178cdSJimmy Vetayases 
1865584d084aSHans Rosenfeld 		irqp->airq_cpu = IRQ_UNINIT;
1866584d084aSHans Rosenfeld 		irqp->airq_origirq = (uchar_t)irqno;
18677ff178cdSJimmy Vetayases 		irqp->airq_mps_intr_index = ACPI_INDEX;
18687ff178cdSJimmy Vetayases 		irqp->airq_ioapicindex = ioapicindex;
18697ff178cdSJimmy Vetayases 		irqp->airq_intin_no = ipin;
18707ff178cdSJimmy Vetayases 		irqp->airq_iflag = *flagp;
18717ff178cdSJimmy Vetayases 		irqp->airq_share++;
1872584d084aSHans Rosenfeld 
1873584d084aSHans Rosenfeld 		apic_irq_table[irqno] = irqp;
1874584d084aSHans Rosenfeld 		mutex_exit(&airq_mutex);
1875584d084aSHans Rosenfeld 
1876584d084aSHans Rosenfeld 		vecp = apix_alloc_intx(NULL, 0, irqno);
18777ff178cdSJimmy Vetayases 	}
18787ff178cdSJimmy Vetayases 
18797ff178cdSJimmy Vetayases 	/* copy over autovect */
18807ff178cdSJimmy Vetayases 	for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link)
18817ff178cdSJimmy Vetayases 		apix_insert_av(vecp, avp->av_intr_id, avp->av_vector,
18827ff178cdSJimmy Vetayases 		    avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
18837ff178cdSJimmy Vetayases 		    avp->av_prilevel, avp->av_dip);
18847ff178cdSJimmy Vetayases 
18857ff178cdSJimmy Vetayases 	/* Program I/O APIC */
18867ff178cdSJimmy Vetayases 	iflag = intr_clear();
18877ff178cdSJimmy Vetayases 	lock_set(&apix_lock);
18887ff178cdSJimmy Vetayases 
18897ff178cdSJimmy Vetayases 	(void) apix_setup_io_intr(vecp);
18907ff178cdSJimmy Vetayases 
18917ff178cdSJimmy Vetayases 	lock_clear(&apix_lock);
18927ff178cdSJimmy Vetayases 	intr_restore(iflag);
18937ff178cdSJimmy Vetayases 
18947ff178cdSJimmy Vetayases 	APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x "
18957ff178cdSJimmy Vetayases 	    "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n",
18967ff178cdSJimmy Vetayases 	    irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector));
18977ff178cdSJimmy Vetayases }
18987ff178cdSJimmy Vetayases 
18997ff178cdSJimmy Vetayases void
ioapix_init_intr(int mask_apic)19007ff178cdSJimmy Vetayases ioapix_init_intr(int mask_apic)
19017ff178cdSJimmy Vetayases {
19027ff178cdSJimmy Vetayases 	int ioapicindex;
19037ff178cdSJimmy Vetayases 	int i, j;
19047ff178cdSJimmy Vetayases 
19057ff178cdSJimmy Vetayases 	/* mask interrupt vectors */
19067ff178cdSJimmy Vetayases 	for (j = 0; j < apic_io_max && mask_apic; j++) {
19077ff178cdSJimmy Vetayases 		int intin_max;
19087ff178cdSJimmy Vetayases 
19097ff178cdSJimmy Vetayases 		ioapicindex = j;
19107ff178cdSJimmy Vetayases 		/* Bits 23-16 define the maximum redirection entries */
19117ff178cdSJimmy Vetayases 		intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16)
19127ff178cdSJimmy Vetayases 		    & 0xff;
19137ff178cdSJimmy Vetayases 		for (i = 0; i <= intin_max; i++)
19147ff178cdSJimmy Vetayases 			ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i,
19157ff178cdSJimmy Vetayases 			    AV_MASK);
19167ff178cdSJimmy Vetayases 	}
19177ff178cdSJimmy Vetayases 
19187ff178cdSJimmy Vetayases 	/*
19197ff178cdSJimmy Vetayases 	 * Hack alert: deal with ACPI SCI interrupt chicken/egg here
19207ff178cdSJimmy Vetayases 	 */
19217ff178cdSJimmy Vetayases 	if (apic_sci_vect > 0)
19227ff178cdSJimmy Vetayases 		ioapix_setup_intr(apic_sci_vect, &apic_sci_flags);
19237ff178cdSJimmy Vetayases 
19247ff178cdSJimmy Vetayases 	/*
19257ff178cdSJimmy Vetayases 	 * Hack alert: deal with ACPI HPET interrupt chicken/egg here.
19267ff178cdSJimmy Vetayases 	 */
19277ff178cdSJimmy Vetayases 	if (apic_hpet_vect > 0)
19287ff178cdSJimmy Vetayases 		ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags);
19297ff178cdSJimmy Vetayases }
1930