xref: /titanic_44/usr/src/uts/i86pc/io/apix/apix_intr.c (revision 636dfb4b6ac0749387c883053011a3afb4b4893b)
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 #include <sys/cpuvar.h>
277ff178cdSJimmy Vetayases #include <sys/cpu_event.h>
287ff178cdSJimmy Vetayases #include <sys/param.h>
297ff178cdSJimmy Vetayases #include <sys/cmn_err.h>
307ff178cdSJimmy Vetayases #include <sys/t_lock.h>
317ff178cdSJimmy Vetayases #include <sys/kmem.h>
327ff178cdSJimmy Vetayases #include <sys/machlock.h>
337ff178cdSJimmy Vetayases #include <sys/systm.h>
347ff178cdSJimmy Vetayases #include <sys/archsystm.h>
357ff178cdSJimmy Vetayases #include <sys/atomic.h>
367ff178cdSJimmy Vetayases #include <sys/sdt.h>
377ff178cdSJimmy Vetayases #include <sys/processor.h>
387ff178cdSJimmy Vetayases #include <sys/time.h>
397ff178cdSJimmy Vetayases #include <sys/psm.h>
407ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h>
417ff178cdSJimmy Vetayases #include <sys/cram.h>
427ff178cdSJimmy Vetayases #include <sys/apic.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/trap.h>
557ff178cdSJimmy Vetayases #include <sys/machsystm.h>
567ff178cdSJimmy Vetayases #include <sys/sysmacros.h>
577ff178cdSJimmy Vetayases #include <sys/rm_platter.h>
587ff178cdSJimmy Vetayases #include <sys/privregs.h>
597ff178cdSJimmy Vetayases #include <sys/note.h>
607ff178cdSJimmy Vetayases #include <sys/pci_intr_lib.h>
617ff178cdSJimmy Vetayases #include <sys/spl.h>
627ff178cdSJimmy Vetayases #include <sys/clock.h>
637ff178cdSJimmy Vetayases #include <sys/dditypes.h>
647ff178cdSJimmy Vetayases #include <sys/sunddi.h>
657ff178cdSJimmy Vetayases #include <sys/x_call.h>
667ff178cdSJimmy Vetayases #include <sys/reboot.h>
677ff178cdSJimmy Vetayases #include <vm/hat_i86.h>
687ff178cdSJimmy Vetayases #include <sys/stack.h>
697ff178cdSJimmy Vetayases #include <sys/apix.h>
707ff178cdSJimmy Vetayases 
717ff178cdSJimmy Vetayases static void apix_post_hardint(int);
727ff178cdSJimmy Vetayases 
737ff178cdSJimmy Vetayases /*
747ff178cdSJimmy Vetayases  * Insert an vector into the tail of the interrupt pending list
757ff178cdSJimmy Vetayases  */
767ff178cdSJimmy Vetayases static __inline__ void
apix_insert_pending_av(apix_impl_t * apixp,struct autovec * avp,int ipl)777ff178cdSJimmy Vetayases apix_insert_pending_av(apix_impl_t *apixp, struct autovec *avp, int ipl)
787ff178cdSJimmy Vetayases {
797ff178cdSJimmy Vetayases 	struct autovec **head = apixp->x_intr_head;
807ff178cdSJimmy Vetayases 	struct autovec **tail = apixp->x_intr_tail;
817ff178cdSJimmy Vetayases 
827ff178cdSJimmy Vetayases 	avp->av_ipl_link = NULL;
837ff178cdSJimmy Vetayases 	if (tail[ipl] == NULL) {
847ff178cdSJimmy Vetayases 		head[ipl] = tail[ipl] = avp;
857ff178cdSJimmy Vetayases 		return;
867ff178cdSJimmy Vetayases 	}
877ff178cdSJimmy Vetayases 
887ff178cdSJimmy Vetayases 	tail[ipl]->av_ipl_link = avp;
897ff178cdSJimmy Vetayases 	tail[ipl] = avp;
907ff178cdSJimmy Vetayases }
917ff178cdSJimmy Vetayases 
927ff178cdSJimmy Vetayases /*
937ff178cdSJimmy Vetayases  * Remove and return an vector from the head of hardware interrupt
947ff178cdSJimmy Vetayases  * pending list.
957ff178cdSJimmy Vetayases  */
967ff178cdSJimmy Vetayases static __inline__ struct autovec *
apix_remove_pending_av(apix_impl_t * apixp,int ipl)977ff178cdSJimmy Vetayases apix_remove_pending_av(apix_impl_t *apixp, int ipl)
987ff178cdSJimmy Vetayases {
997ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
1007ff178cdSJimmy Vetayases 	struct autovec **head = apixp->x_intr_head;
1017ff178cdSJimmy Vetayases 	struct autovec **tail = apixp->x_intr_tail;
1027ff178cdSJimmy Vetayases 	struct autovec *avp = head[ipl];
1037ff178cdSJimmy Vetayases 
1047ff178cdSJimmy Vetayases 	if (avp == NULL)
1057ff178cdSJimmy Vetayases 		return (NULL);
1067ff178cdSJimmy Vetayases 
1077ff178cdSJimmy Vetayases 	if (avp->av_vector != NULL && avp->av_prilevel < cpu->cpu_base_spl) {
1087ff178cdSJimmy Vetayases 		/*
1097ff178cdSJimmy Vetayases 		 * If there is blocked higher level interrupts, return
1107ff178cdSJimmy Vetayases 		 * NULL to quit handling of current IPL level.
1117ff178cdSJimmy Vetayases 		 */
1127ff178cdSJimmy Vetayases 		apixp->x_intr_pending |= (1 << avp->av_prilevel);
1137ff178cdSJimmy Vetayases 		return (NULL);
1147ff178cdSJimmy Vetayases 	}
1157ff178cdSJimmy Vetayases 
1167ff178cdSJimmy Vetayases 	avp->av_flags &= ~AV_PENTRY_PEND;
1177ff178cdSJimmy Vetayases 	avp->av_flags |= AV_PENTRY_ONPROC;
1187ff178cdSJimmy Vetayases 	head[ipl] = avp->av_ipl_link;
1197ff178cdSJimmy Vetayases 	avp->av_ipl_link = NULL;
1207ff178cdSJimmy Vetayases 
1217ff178cdSJimmy Vetayases 	if (head[ipl] == NULL)
1227ff178cdSJimmy Vetayases 		tail[ipl] = NULL;
1237ff178cdSJimmy Vetayases 
1247ff178cdSJimmy Vetayases 	return (avp);
1257ff178cdSJimmy Vetayases }
1267ff178cdSJimmy Vetayases 
1277ff178cdSJimmy Vetayases /*
1287ff178cdSJimmy Vetayases  * add_pending_hardint:
1297ff178cdSJimmy Vetayases  *
1307ff178cdSJimmy Vetayases  * Add hardware interrupts to the interrupt pending list.
1317ff178cdSJimmy Vetayases  */
1327ff178cdSJimmy Vetayases static void
apix_add_pending_hardint(int vector)1337ff178cdSJimmy Vetayases apix_add_pending_hardint(int vector)
1347ff178cdSJimmy Vetayases {
1357ff178cdSJimmy Vetayases 	uint32_t cpuid = psm_get_cpu_id();
1367ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpuid];
1377ff178cdSJimmy Vetayases 	apix_vector_t *vecp = apixp->x_vectbl[vector];
1387ff178cdSJimmy Vetayases 	struct autovec *p, *prevp = NULL;
1397ff178cdSJimmy Vetayases 	int ipl;
1407ff178cdSJimmy Vetayases 
1417ff178cdSJimmy Vetayases 	/*
1427ff178cdSJimmy Vetayases 	 * The MSI interrupt not supporting per-vector masking could
1437ff178cdSJimmy Vetayases 	 * be triggered on a false vector as a result of rebinding
1447ff178cdSJimmy Vetayases 	 * operation cannot programme MSI address & data atomically.
1457ff178cdSJimmy Vetayases 	 * Add ISR of this interrupt to the pending list for such
1467ff178cdSJimmy Vetayases 	 * suspicious interrupt.
1477ff178cdSJimmy Vetayases 	 */
1487ff178cdSJimmy Vetayases 	APIX_DO_FAKE_INTR(cpuid, vector);
1497ff178cdSJimmy Vetayases 	if (vecp == NULL)
1507ff178cdSJimmy Vetayases 		return;
1517ff178cdSJimmy Vetayases 
1527ff178cdSJimmy Vetayases 	for (p = vecp->v_autovect; p != NULL; p = p->av_link) {
1537ff178cdSJimmy Vetayases 		if (p->av_vector == NULL)
1547ff178cdSJimmy Vetayases 			continue;	/* skip freed entry */
1557ff178cdSJimmy Vetayases 
1567ff178cdSJimmy Vetayases 		ipl = p->av_prilevel;
1577ff178cdSJimmy Vetayases 		prevp = p;
1587ff178cdSJimmy Vetayases 
1597ff178cdSJimmy Vetayases 		/* set pending at specified priority level */
1607ff178cdSJimmy Vetayases 		apixp->x_intr_pending |= (1 << ipl);
1617ff178cdSJimmy Vetayases 
1627ff178cdSJimmy Vetayases 		if (p->av_flags & AV_PENTRY_PEND)
1637ff178cdSJimmy Vetayases 			continue;	/* already in the pending list */
1647ff178cdSJimmy Vetayases 		p->av_flags |= AV_PENTRY_PEND;
1657ff178cdSJimmy Vetayases 
1667ff178cdSJimmy Vetayases 		/* insert into pending list by it original IPL */
1677ff178cdSJimmy Vetayases 		apix_insert_pending_av(apixp, p, ipl);
1687ff178cdSJimmy Vetayases 	}
1697ff178cdSJimmy Vetayases 
1707ff178cdSJimmy Vetayases 	/* last one of the linked list */
1717ff178cdSJimmy Vetayases 	if (prevp && ((prevp->av_flags & AV_PENTRY_LEVEL) != 0))
1727ff178cdSJimmy Vetayases 		prevp->av_flags |= (vector & AV_PENTRY_VECTMASK);
1737ff178cdSJimmy Vetayases }
1747ff178cdSJimmy Vetayases 
1757ff178cdSJimmy Vetayases /*
1767ff178cdSJimmy Vetayases  * Walk pending hardware interrupts at given priority level, invoking
1777ff178cdSJimmy Vetayases  * each interrupt handler as we go.
1787ff178cdSJimmy Vetayases  */
1797ff178cdSJimmy Vetayases extern uint64_t intr_get_time(void);
1807ff178cdSJimmy Vetayases 
1817ff178cdSJimmy Vetayases static void
apix_dispatch_pending_autovect(uint_t ipl)1827ff178cdSJimmy Vetayases apix_dispatch_pending_autovect(uint_t ipl)
1837ff178cdSJimmy Vetayases {
1847ff178cdSJimmy Vetayases 	uint32_t cpuid = psm_get_cpu_id();
1857ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpuid];
1867ff178cdSJimmy Vetayases 	struct autovec *av;
1877ff178cdSJimmy Vetayases 
1887ff178cdSJimmy Vetayases 	while ((av = apix_remove_pending_av(apixp, ipl)) != NULL) {
1897ff178cdSJimmy Vetayases 		uint_t r;
1907ff178cdSJimmy Vetayases 		uint_t (*intr)() = av->av_vector;
1917ff178cdSJimmy Vetayases 		caddr_t arg1 = av->av_intarg1;
1927ff178cdSJimmy Vetayases 		caddr_t arg2 = av->av_intarg2;
1937ff178cdSJimmy Vetayases 		dev_info_t *dip = av->av_dip;
1947ff178cdSJimmy Vetayases 		uchar_t vector = av->av_flags & AV_PENTRY_VECTMASK;
1957ff178cdSJimmy Vetayases 
1967ff178cdSJimmy Vetayases 		if (intr == NULL)
1977ff178cdSJimmy Vetayases 			continue;
1987ff178cdSJimmy Vetayases 
1997ff178cdSJimmy Vetayases 		/* Don't enable interrupts during x-calls */
2007ff178cdSJimmy Vetayases 		if (ipl != XC_HI_PIL)
2017ff178cdSJimmy Vetayases 			sti();
2027ff178cdSJimmy Vetayases 
2037ff178cdSJimmy Vetayases 		DTRACE_PROBE4(interrupt__start, dev_info_t *, dip,
2047ff178cdSJimmy Vetayases 		    void *, intr, caddr_t, arg1, caddr_t, arg2);
2057ff178cdSJimmy Vetayases 		r = (*intr)(arg1, arg2);
2067ff178cdSJimmy Vetayases 		DTRACE_PROBE4(interrupt__complete, dev_info_t *, dip,
2077ff178cdSJimmy Vetayases 		    void *, intr, caddr_t, arg1, uint_t, r);
2087ff178cdSJimmy Vetayases 
2097ff178cdSJimmy Vetayases 		if (av->av_ticksp && av->av_prilevel <= LOCK_LEVEL)
2107ff178cdSJimmy Vetayases 			atomic_add_64(av->av_ticksp, intr_get_time());
2117ff178cdSJimmy Vetayases 
2127ff178cdSJimmy Vetayases 		cli();
2137ff178cdSJimmy Vetayases 
2147ff178cdSJimmy Vetayases 		if (vector) {
2157ff178cdSJimmy Vetayases 			if ((av->av_flags & AV_PENTRY_PEND) == 0)
2167ff178cdSJimmy Vetayases 				av->av_flags &= ~AV_PENTRY_VECTMASK;
2177ff178cdSJimmy Vetayases 
2187ff178cdSJimmy Vetayases 			apix_post_hardint(vector);
2197ff178cdSJimmy Vetayases 		}
2207ff178cdSJimmy Vetayases 
2217ff178cdSJimmy Vetayases 		/* mark it as idle */
2227ff178cdSJimmy Vetayases 		av->av_flags &= ~AV_PENTRY_ONPROC;
2237ff178cdSJimmy Vetayases 	}
2247ff178cdSJimmy Vetayases }
2257ff178cdSJimmy Vetayases 
2267ff178cdSJimmy Vetayases static caddr_t
apix_do_softint_prolog(struct cpu * cpu,uint_t pil,uint_t oldpil,caddr_t stackptr)2277ff178cdSJimmy Vetayases apix_do_softint_prolog(struct cpu *cpu, uint_t pil, uint_t oldpil,
2287ff178cdSJimmy Vetayases     caddr_t stackptr)
2297ff178cdSJimmy Vetayases {
2307ff178cdSJimmy Vetayases 	kthread_t *t, *volatile it;
2317ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
2327ff178cdSJimmy Vetayases 	hrtime_t now;
2337ff178cdSJimmy Vetayases 
2347ff178cdSJimmy Vetayases 	UNREFERENCED_1PARAMETER(oldpil);
2357ff178cdSJimmy Vetayases 	ASSERT(pil > mcpu->mcpu_pri && pil > cpu->cpu_base_spl);
2367ff178cdSJimmy Vetayases 
2377ff178cdSJimmy Vetayases 	atomic_and_32((uint32_t *)&mcpu->mcpu_softinfo.st_pending, ~(1 << pil));
2387ff178cdSJimmy Vetayases 
2397ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = pil;
2407ff178cdSJimmy Vetayases 
2417ff178cdSJimmy Vetayases 	now = tsc_read();
2427ff178cdSJimmy Vetayases 
2437ff178cdSJimmy Vetayases 	/*
2447ff178cdSJimmy Vetayases 	 * Get set to run interrupt thread.
2457ff178cdSJimmy Vetayases 	 * There should always be an interrupt thread since we
2467ff178cdSJimmy Vetayases 	 * allocate one for each level on the CPU.
2477ff178cdSJimmy Vetayases 	 */
2487ff178cdSJimmy Vetayases 	it = cpu->cpu_intr_thread;
2497ff178cdSJimmy Vetayases 	ASSERT(it != NULL);
2507ff178cdSJimmy Vetayases 	cpu->cpu_intr_thread = it->t_link;
2517ff178cdSJimmy Vetayases 
2527ff178cdSJimmy Vetayases 	/* t_intr_start could be zero due to cpu_intr_swtch_enter. */
2537ff178cdSJimmy Vetayases 	t = cpu->cpu_thread;
2547ff178cdSJimmy Vetayases 	if ((t->t_flag & T_INTR_THREAD) && t->t_intr_start != 0) {
2557ff178cdSJimmy Vetayases 		hrtime_t intrtime = now - t->t_intr_start;
2567ff178cdSJimmy Vetayases 		mcpu->intrstat[pil][0] += intrtime;
2577ff178cdSJimmy Vetayases 		cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
2587ff178cdSJimmy Vetayases 		t->t_intr_start = 0;
2597ff178cdSJimmy Vetayases 	}
2607ff178cdSJimmy Vetayases 
2617ff178cdSJimmy Vetayases 	/*
2627ff178cdSJimmy Vetayases 	 * Note that the code in kcpc_overflow_intr -relies- on the
2637ff178cdSJimmy Vetayases 	 * ordering of events here - in particular that t->t_lwp of
2647ff178cdSJimmy Vetayases 	 * the interrupt thread is set to the pinned thread *before*
2657ff178cdSJimmy Vetayases 	 * curthread is changed.
2667ff178cdSJimmy Vetayases 	 */
2677ff178cdSJimmy Vetayases 	it->t_lwp = t->t_lwp;
2687ff178cdSJimmy Vetayases 	it->t_state = TS_ONPROC;
2697ff178cdSJimmy Vetayases 
2707ff178cdSJimmy Vetayases 	/*
2717ff178cdSJimmy Vetayases 	 * Push interrupted thread onto list from new thread.
2727ff178cdSJimmy Vetayases 	 * Set the new thread as the current one.
2737ff178cdSJimmy Vetayases 	 * Set interrupted thread's T_SP because if it is the idle thread,
2747ff178cdSJimmy Vetayases 	 * resume() may use that stack between threads.
2757ff178cdSJimmy Vetayases 	 */
2767ff178cdSJimmy Vetayases 
2777ff178cdSJimmy Vetayases 	ASSERT(SA((uintptr_t)stackptr) == (uintptr_t)stackptr);
2787ff178cdSJimmy Vetayases 	t->t_sp = (uintptr_t)stackptr;
2797ff178cdSJimmy Vetayases 
2807ff178cdSJimmy Vetayases 	it->t_intr = t;
2817ff178cdSJimmy Vetayases 	cpu->cpu_thread = it;
2827ff178cdSJimmy Vetayases 
2837ff178cdSJimmy Vetayases 	/*
2847ff178cdSJimmy Vetayases 	 * Set bit for this pil in CPU's interrupt active bitmask.
2857ff178cdSJimmy Vetayases 	 */
2867ff178cdSJimmy Vetayases 	ASSERT((cpu->cpu_intr_actv & (1 << pil)) == 0);
2877ff178cdSJimmy Vetayases 	cpu->cpu_intr_actv |= (1 << pil);
2887ff178cdSJimmy Vetayases 
2897ff178cdSJimmy Vetayases 	/*
2907ff178cdSJimmy Vetayases 	 * Initialize thread priority level from intr_pri
2917ff178cdSJimmy Vetayases 	 */
2927ff178cdSJimmy Vetayases 	it->t_pil = (uchar_t)pil;
2937ff178cdSJimmy Vetayases 	it->t_pri = (pri_t)pil + intr_pri;
2947ff178cdSJimmy Vetayases 	it->t_intr_start = now;
2957ff178cdSJimmy Vetayases 
2967ff178cdSJimmy Vetayases 	return (it->t_stk);
2977ff178cdSJimmy Vetayases }
2987ff178cdSJimmy Vetayases 
2997ff178cdSJimmy Vetayases static void
apix_do_softint_epilog(struct cpu * cpu,uint_t oldpil)3007ff178cdSJimmy Vetayases apix_do_softint_epilog(struct cpu *cpu, uint_t oldpil)
3017ff178cdSJimmy Vetayases {
3027ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
3037ff178cdSJimmy Vetayases 	kthread_t *t, *it;
3047ff178cdSJimmy Vetayases 	uint_t pil, basespl;
3057ff178cdSJimmy Vetayases 	hrtime_t intrtime;
3067ff178cdSJimmy Vetayases 	hrtime_t now = tsc_read();
3077ff178cdSJimmy Vetayases 
3087ff178cdSJimmy Vetayases 	it = cpu->cpu_thread;
3097ff178cdSJimmy Vetayases 	pil = it->t_pil;
3107ff178cdSJimmy Vetayases 
3117ff178cdSJimmy Vetayases 	cpu->cpu_stats.sys.intr[pil - 1]++;
3127ff178cdSJimmy Vetayases 
3137ff178cdSJimmy Vetayases 	ASSERT(cpu->cpu_intr_actv & (1 << pil));
3147ff178cdSJimmy Vetayases 	cpu->cpu_intr_actv &= ~(1 << pil);
3157ff178cdSJimmy Vetayases 
3167ff178cdSJimmy Vetayases 	intrtime = now - it->t_intr_start;
3177ff178cdSJimmy Vetayases 	mcpu->intrstat[pil][0] += intrtime;
3187ff178cdSJimmy Vetayases 	cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
3197ff178cdSJimmy Vetayases 
3207ff178cdSJimmy Vetayases 	/*
3217ff178cdSJimmy Vetayases 	 * If there is still an interrupted thread underneath this one
3227ff178cdSJimmy Vetayases 	 * then the interrupt was never blocked and the return is
3237ff178cdSJimmy Vetayases 	 * fairly simple.  Otherwise it isn't.
3247ff178cdSJimmy Vetayases 	 */
3257ff178cdSJimmy Vetayases 	if ((t = it->t_intr) == NULL) {
3267ff178cdSJimmy Vetayases 		/*
3277ff178cdSJimmy Vetayases 		 * Put thread back on the interrupt thread list.
3287ff178cdSJimmy Vetayases 		 * This was an interrupt thread, so set CPU's base SPL.
3297ff178cdSJimmy Vetayases 		 */
3307ff178cdSJimmy Vetayases 		set_base_spl();
3317ff178cdSJimmy Vetayases 		/* mcpu->mcpu_pri = cpu->cpu_base_spl; */
3327ff178cdSJimmy Vetayases 
3337ff178cdSJimmy Vetayases 		it->t_state = TS_FREE;
3347ff178cdSJimmy Vetayases 		it->t_link = cpu->cpu_intr_thread;
3357ff178cdSJimmy Vetayases 		cpu->cpu_intr_thread = it;
3367ff178cdSJimmy Vetayases 		(void) splhigh();
3377ff178cdSJimmy Vetayases 		sti();
3387ff178cdSJimmy Vetayases 		swtch();
3397ff178cdSJimmy Vetayases 		/*NOTREACHED*/
3407ff178cdSJimmy Vetayases 		panic("dosoftint_epilog: swtch returned");
3417ff178cdSJimmy Vetayases 	}
3427ff178cdSJimmy Vetayases 	it->t_link = cpu->cpu_intr_thread;
3437ff178cdSJimmy Vetayases 	cpu->cpu_intr_thread = it;
3447ff178cdSJimmy Vetayases 	it->t_state = TS_FREE;
3457ff178cdSJimmy Vetayases 	cpu->cpu_thread = t;
3467ff178cdSJimmy Vetayases 	if (t->t_flag & T_INTR_THREAD)
3477ff178cdSJimmy Vetayases 		t->t_intr_start = now;
3487ff178cdSJimmy Vetayases 	basespl = cpu->cpu_base_spl;
3497ff178cdSJimmy Vetayases 	pil = MAX(oldpil, basespl);
3507ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = pil;
3517ff178cdSJimmy Vetayases }
3527ff178cdSJimmy Vetayases 
3537ff178cdSJimmy Vetayases /*
3547ff178cdSJimmy Vetayases  * Dispatch a soft interrupt
3557ff178cdSJimmy Vetayases  */
3567ff178cdSJimmy Vetayases static void
apix_dispatch_softint(uint_t oldpil,uint_t arg2)3577ff178cdSJimmy Vetayases apix_dispatch_softint(uint_t oldpil, uint_t arg2)
3587ff178cdSJimmy Vetayases {
3597ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
3607ff178cdSJimmy Vetayases 
3617ff178cdSJimmy Vetayases 	UNREFERENCED_1PARAMETER(arg2);
3627ff178cdSJimmy Vetayases 
3637ff178cdSJimmy Vetayases 	sti();
3647ff178cdSJimmy Vetayases 	av_dispatch_softvect((int)cpu->cpu_thread->t_pil);
3657ff178cdSJimmy Vetayases 	cli();
3667ff178cdSJimmy Vetayases 
3677ff178cdSJimmy Vetayases 	/*
3687ff178cdSJimmy Vetayases 	 * Must run softint_epilog() on the interrupt thread stack, since
3697ff178cdSJimmy Vetayases 	 * there may not be a return from it if the interrupt thread blocked.
3707ff178cdSJimmy Vetayases 	 */
3717ff178cdSJimmy Vetayases 	apix_do_softint_epilog(cpu, oldpil);
3727ff178cdSJimmy Vetayases }
3737ff178cdSJimmy Vetayases 
3747ff178cdSJimmy Vetayases /*
3757ff178cdSJimmy Vetayases  * Deliver any softints the current interrupt priority allows.
3767ff178cdSJimmy Vetayases  * Called with interrupts disabled.
3777ff178cdSJimmy Vetayases  */
3787ff178cdSJimmy Vetayases int
apix_do_softint(struct regs * regs)3797ff178cdSJimmy Vetayases apix_do_softint(struct regs *regs)
3807ff178cdSJimmy Vetayases {
3817ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
3827ff178cdSJimmy Vetayases 	int oldipl;
3837ff178cdSJimmy Vetayases 	int newipl;
3847ff178cdSJimmy Vetayases 	volatile uint16_t pending;
3857ff178cdSJimmy Vetayases 	caddr_t newsp;
3867ff178cdSJimmy Vetayases 
3877ff178cdSJimmy Vetayases 	while ((pending = cpu->cpu_softinfo.st_pending) != 0) {
3887ff178cdSJimmy Vetayases 		newipl = bsrw_insn(pending);
3897ff178cdSJimmy Vetayases 		oldipl = cpu->cpu_pri;
3907ff178cdSJimmy Vetayases 		if (newipl <= oldipl || newipl <= cpu->cpu_base_spl)
3917ff178cdSJimmy Vetayases 			return (-1);
3927ff178cdSJimmy Vetayases 
3937ff178cdSJimmy Vetayases 		newsp = apix_do_softint_prolog(cpu, newipl, oldipl,
3947ff178cdSJimmy Vetayases 		    (caddr_t)regs);
3957ff178cdSJimmy Vetayases 		ASSERT(newsp != NULL);
3967ff178cdSJimmy Vetayases 		switch_sp_and_call(newsp, apix_dispatch_softint, oldipl, 0);
3977ff178cdSJimmy Vetayases 	}
3987ff178cdSJimmy Vetayases 
3997ff178cdSJimmy Vetayases 	return (0);
4007ff178cdSJimmy Vetayases }
4017ff178cdSJimmy Vetayases 
4027ff178cdSJimmy Vetayases static int
apix_hilevel_intr_prolog(struct cpu * cpu,uint_t pil,uint_t oldpil,struct regs * rp)4037ff178cdSJimmy Vetayases apix_hilevel_intr_prolog(struct cpu *cpu, uint_t pil, uint_t oldpil,
4047ff178cdSJimmy Vetayases     struct regs *rp)
4057ff178cdSJimmy Vetayases {
4067ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
4077ff178cdSJimmy Vetayases 	hrtime_t intrtime;
4087ff178cdSJimmy Vetayases 	hrtime_t now = tsc_read();
4097ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpu->cpu_id];
4107ff178cdSJimmy Vetayases 	uint_t mask;
4117ff178cdSJimmy Vetayases 
4127ff178cdSJimmy Vetayases 	ASSERT(pil > mcpu->mcpu_pri && pil > cpu->cpu_base_spl);
4137ff178cdSJimmy Vetayases 
4147ff178cdSJimmy Vetayases 	if (pil == CBE_HIGH_PIL) {	/* 14 */
4157ff178cdSJimmy Vetayases 		cpu->cpu_profile_pil = oldpil;
4167ff178cdSJimmy Vetayases 		if (USERMODE(rp->r_cs)) {
4177ff178cdSJimmy Vetayases 			cpu->cpu_profile_pc = 0;
4187ff178cdSJimmy Vetayases 			cpu->cpu_profile_upc = rp->r_pc;
4197ff178cdSJimmy Vetayases 			cpu->cpu_cpcprofile_pc = 0;
4207ff178cdSJimmy Vetayases 			cpu->cpu_cpcprofile_upc = rp->r_pc;
4217ff178cdSJimmy Vetayases 		} else {
4227ff178cdSJimmy Vetayases 			cpu->cpu_profile_pc = rp->r_pc;
4237ff178cdSJimmy Vetayases 			cpu->cpu_profile_upc = 0;
4247ff178cdSJimmy Vetayases 			cpu->cpu_cpcprofile_pc = rp->r_pc;
4257ff178cdSJimmy Vetayases 			cpu->cpu_cpcprofile_upc = 0;
4267ff178cdSJimmy Vetayases 		}
4277ff178cdSJimmy Vetayases 	}
4287ff178cdSJimmy Vetayases 
4297ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = pil;
4307ff178cdSJimmy Vetayases 
4317ff178cdSJimmy Vetayases 	mask = cpu->cpu_intr_actv & CPU_INTR_ACTV_HIGH_LEVEL_MASK;
4327ff178cdSJimmy Vetayases 	if (mask != 0) {
4337ff178cdSJimmy Vetayases 		int nestpil;
4347ff178cdSJimmy Vetayases 
4357ff178cdSJimmy Vetayases 		/*
4367ff178cdSJimmy Vetayases 		 * We have interrupted another high-level interrupt.
4377ff178cdSJimmy Vetayases 		 * Load starting timestamp, compute interval, update
4387ff178cdSJimmy Vetayases 		 * cumulative counter.
4397ff178cdSJimmy Vetayases 		 */
4407ff178cdSJimmy Vetayases 		nestpil = bsrw_insn((uint16_t)mask);
4417ff178cdSJimmy Vetayases 		intrtime = now -
4427ff178cdSJimmy Vetayases 		    mcpu->pil_high_start[nestpil - (LOCK_LEVEL + 1)];
4437ff178cdSJimmy Vetayases 		mcpu->intrstat[nestpil][0] += intrtime;
4447ff178cdSJimmy Vetayases 		cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
4457ff178cdSJimmy Vetayases 	} else {
4467ff178cdSJimmy Vetayases 		kthread_t *t = cpu->cpu_thread;
4477ff178cdSJimmy Vetayases 
4487ff178cdSJimmy Vetayases 		/*
4497ff178cdSJimmy Vetayases 		 * See if we are interrupting a low-level interrupt thread.
4507ff178cdSJimmy Vetayases 		 * If so, account for its time slice only if its time stamp
4517ff178cdSJimmy Vetayases 		 * is non-zero.
4527ff178cdSJimmy Vetayases 		 */
4537ff178cdSJimmy Vetayases 		if ((t->t_flag & T_INTR_THREAD) != 0 && t->t_intr_start != 0) {
4547ff178cdSJimmy Vetayases 			intrtime = now - t->t_intr_start;
4557ff178cdSJimmy Vetayases 			mcpu->intrstat[t->t_pil][0] += intrtime;
4567ff178cdSJimmy Vetayases 			cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
4577ff178cdSJimmy Vetayases 			t->t_intr_start = 0;
4587ff178cdSJimmy Vetayases 		}
4597ff178cdSJimmy Vetayases 	}
4607ff178cdSJimmy Vetayases 
4617ff178cdSJimmy Vetayases 	/* store starting timestamp in CPu structure for this IPL */
4627ff178cdSJimmy Vetayases 	mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)] = now;
4637ff178cdSJimmy Vetayases 
4647ff178cdSJimmy Vetayases 	if (pil == 15) {
4657ff178cdSJimmy Vetayases 		/*
4667ff178cdSJimmy Vetayases 		 * To support reentrant level 15 interrupts, we maintain a
4677ff178cdSJimmy Vetayases 		 * recursion count in the top half of cpu_intr_actv.  Only
4687ff178cdSJimmy Vetayases 		 * when this count hits zero do we clear the PIL 15 bit from
4697ff178cdSJimmy Vetayases 		 * the lower half of cpu_intr_actv.
4707ff178cdSJimmy Vetayases 		 */
4717ff178cdSJimmy Vetayases 		uint16_t *refcntp = (uint16_t *)&cpu->cpu_intr_actv + 1;
4727ff178cdSJimmy Vetayases 		(*refcntp)++;
4737ff178cdSJimmy Vetayases 	}
4747ff178cdSJimmy Vetayases 
4757ff178cdSJimmy Vetayases 	cpu->cpu_intr_actv |= (1 << pil);
4767ff178cdSJimmy Vetayases 	/* clear pending ipl level bit */
4777ff178cdSJimmy Vetayases 	apixp->x_intr_pending &= ~(1 << pil);
4787ff178cdSJimmy Vetayases 
4797ff178cdSJimmy Vetayases 	return (mask);
4807ff178cdSJimmy Vetayases }
4817ff178cdSJimmy Vetayases 
4827ff178cdSJimmy Vetayases static int
apix_hilevel_intr_epilog(struct cpu * cpu,uint_t oldpil)4837ff178cdSJimmy Vetayases apix_hilevel_intr_epilog(struct cpu *cpu, uint_t oldpil)
4847ff178cdSJimmy Vetayases {
4857ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
4867ff178cdSJimmy Vetayases 	uint_t mask, pil;
4877ff178cdSJimmy Vetayases 	hrtime_t intrtime;
4887ff178cdSJimmy Vetayases 	hrtime_t now = tsc_read();
4897ff178cdSJimmy Vetayases 
4907ff178cdSJimmy Vetayases 	pil = mcpu->mcpu_pri;
4917ff178cdSJimmy Vetayases 	cpu->cpu_stats.sys.intr[pil - 1]++;
4927ff178cdSJimmy Vetayases 
4937ff178cdSJimmy Vetayases 	ASSERT(cpu->cpu_intr_actv & (1 << pil));
4947ff178cdSJimmy Vetayases 
4957ff178cdSJimmy Vetayases 	if (pil == 15) {
4967ff178cdSJimmy Vetayases 		/*
4977ff178cdSJimmy Vetayases 		 * To support reentrant level 15 interrupts, we maintain a
4987ff178cdSJimmy Vetayases 		 * recursion count in the top half of cpu_intr_actv.  Only
4997ff178cdSJimmy Vetayases 		 * when this count hits zero do we clear the PIL 15 bit from
5007ff178cdSJimmy Vetayases 		 * the lower half of cpu_intr_actv.
5017ff178cdSJimmy Vetayases 		 */
5027ff178cdSJimmy Vetayases 		uint16_t *refcntp = (uint16_t *)&cpu->cpu_intr_actv + 1;
5037ff178cdSJimmy Vetayases 
5047ff178cdSJimmy Vetayases 		ASSERT(*refcntp > 0);
5057ff178cdSJimmy Vetayases 
5067ff178cdSJimmy Vetayases 		if (--(*refcntp) == 0)
5077ff178cdSJimmy Vetayases 			cpu->cpu_intr_actv &= ~(1 << pil);
5087ff178cdSJimmy Vetayases 	} else {
5097ff178cdSJimmy Vetayases 		cpu->cpu_intr_actv &= ~(1 << pil);
5107ff178cdSJimmy Vetayases 	}
5117ff178cdSJimmy Vetayases 
5127ff178cdSJimmy Vetayases 	ASSERT(mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)] != 0);
5137ff178cdSJimmy Vetayases 
5147ff178cdSJimmy Vetayases 	intrtime = now - mcpu->pil_high_start[pil - (LOCK_LEVEL + 1)];
5157ff178cdSJimmy Vetayases 	mcpu->intrstat[pil][0] += intrtime;
5167ff178cdSJimmy Vetayases 	cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
5177ff178cdSJimmy Vetayases 
5187ff178cdSJimmy Vetayases 	/*
5197ff178cdSJimmy Vetayases 	 * Check for lower-pil nested high-level interrupt beneath
5207ff178cdSJimmy Vetayases 	 * current one.  If so, place a starting timestamp in its
5217ff178cdSJimmy Vetayases 	 * pil_high_start entry.
5227ff178cdSJimmy Vetayases 	 */
5237ff178cdSJimmy Vetayases 	mask = cpu->cpu_intr_actv & CPU_INTR_ACTV_HIGH_LEVEL_MASK;
5247ff178cdSJimmy Vetayases 	if (mask != 0) {
5257ff178cdSJimmy Vetayases 		int nestpil;
5267ff178cdSJimmy Vetayases 
5277ff178cdSJimmy Vetayases 		/*
5287ff178cdSJimmy Vetayases 		 * find PIL of nested interrupt
5297ff178cdSJimmy Vetayases 		 */
5307ff178cdSJimmy Vetayases 		nestpil = bsrw_insn((uint16_t)mask);
5317ff178cdSJimmy Vetayases 		ASSERT(nestpil < pil);
5327ff178cdSJimmy Vetayases 		mcpu->pil_high_start[nestpil - (LOCK_LEVEL + 1)] = now;
5337ff178cdSJimmy Vetayases 		/*
5347ff178cdSJimmy Vetayases 		 * (Another high-level interrupt is active below this one,
5357ff178cdSJimmy Vetayases 		 * so there is no need to check for an interrupt
5367ff178cdSJimmy Vetayases 		 * thread.  That will be done by the lowest priority
5377ff178cdSJimmy Vetayases 		 * high-level interrupt active.)
5387ff178cdSJimmy Vetayases 		 */
5397ff178cdSJimmy Vetayases 	} else {
5407ff178cdSJimmy Vetayases 		/*
5417ff178cdSJimmy Vetayases 		 * Check to see if there is a low-level interrupt active.
5427ff178cdSJimmy Vetayases 		 * If so, place a starting timestamp in the thread
5437ff178cdSJimmy Vetayases 		 * structure.
5447ff178cdSJimmy Vetayases 		 */
5457ff178cdSJimmy Vetayases 		kthread_t *t = cpu->cpu_thread;
5467ff178cdSJimmy Vetayases 
5477ff178cdSJimmy Vetayases 		if (t->t_flag & T_INTR_THREAD)
5487ff178cdSJimmy Vetayases 			t->t_intr_start = now;
5497ff178cdSJimmy Vetayases 	}
5507ff178cdSJimmy Vetayases 
5517ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = oldpil;
5527ff178cdSJimmy Vetayases 	if (pil < CBE_HIGH_PIL)
5537ff178cdSJimmy Vetayases 		(void) (*setlvlx)(oldpil, 0);
5547ff178cdSJimmy Vetayases 
5557ff178cdSJimmy Vetayases 	return (mask);
5567ff178cdSJimmy Vetayases }
5577ff178cdSJimmy Vetayases 
5587ff178cdSJimmy Vetayases /*
5597ff178cdSJimmy Vetayases  * Dispatch a hilevel interrupt (one above LOCK_LEVEL)
5607ff178cdSJimmy Vetayases  */
5617ff178cdSJimmy Vetayases static void
apix_dispatch_pending_hilevel(uint_t ipl,uint_t arg2)5627ff178cdSJimmy Vetayases apix_dispatch_pending_hilevel(uint_t ipl, uint_t arg2)
5637ff178cdSJimmy Vetayases {
5647ff178cdSJimmy Vetayases 	UNREFERENCED_1PARAMETER(arg2);
5657ff178cdSJimmy Vetayases 
5667ff178cdSJimmy Vetayases 	apix_dispatch_pending_autovect(ipl);
5677ff178cdSJimmy Vetayases }
5687ff178cdSJimmy Vetayases 
5697ff178cdSJimmy Vetayases static __inline__ int
apix_do_pending_hilevel(struct cpu * cpu,struct regs * rp)5707ff178cdSJimmy Vetayases apix_do_pending_hilevel(struct cpu *cpu, struct regs *rp)
5717ff178cdSJimmy Vetayases {
5727ff178cdSJimmy Vetayases 	volatile uint16_t pending;
5737ff178cdSJimmy Vetayases 	uint_t newipl, oldipl;
5747ff178cdSJimmy Vetayases 	caddr_t newsp;
5757ff178cdSJimmy Vetayases 
5767ff178cdSJimmy Vetayases 	while ((pending = HILEVEL_PENDING(cpu)) != 0) {
5777ff178cdSJimmy Vetayases 		newipl = bsrw_insn(pending);
5787ff178cdSJimmy Vetayases 		ASSERT(newipl > LOCK_LEVEL && newipl > cpu->cpu_base_spl);
5797ff178cdSJimmy Vetayases 		oldipl = cpu->cpu_pri;
5807ff178cdSJimmy Vetayases 		if (newipl <= oldipl)
5817ff178cdSJimmy Vetayases 			return (-1);
5827ff178cdSJimmy Vetayases 
5837ff178cdSJimmy Vetayases 		/*
5847ff178cdSJimmy Vetayases 		 * High priority interrupts run on this cpu's interrupt stack.
5857ff178cdSJimmy Vetayases 		 */
5867ff178cdSJimmy Vetayases 		if (apix_hilevel_intr_prolog(cpu, newipl, oldipl, rp) == 0) {
5877ff178cdSJimmy Vetayases 			newsp = cpu->cpu_intr_stack;
5887ff178cdSJimmy Vetayases 			switch_sp_and_call(newsp, apix_dispatch_pending_hilevel,
5897ff178cdSJimmy Vetayases 			    newipl, 0);
5907ff178cdSJimmy Vetayases 		} else {	/* already on the interrupt stack */
5917ff178cdSJimmy Vetayases 			apix_dispatch_pending_hilevel(newipl, 0);
5927ff178cdSJimmy Vetayases 		}
5937ff178cdSJimmy Vetayases 		(void) apix_hilevel_intr_epilog(cpu, oldipl);
5947ff178cdSJimmy Vetayases 	}
5957ff178cdSJimmy Vetayases 
5967ff178cdSJimmy Vetayases 	return (0);
5977ff178cdSJimmy Vetayases }
5987ff178cdSJimmy Vetayases 
5997ff178cdSJimmy Vetayases /*
6007ff178cdSJimmy Vetayases  * Get an interrupt thread and swith to it. It's called from do_interrupt().
6017ff178cdSJimmy Vetayases  * The IF flag is cleared and thus all maskable interrupts are blocked at
6027ff178cdSJimmy Vetayases  * the time of calling.
6037ff178cdSJimmy Vetayases  */
6047ff178cdSJimmy Vetayases static caddr_t
apix_intr_thread_prolog(struct cpu * cpu,uint_t pil,caddr_t stackptr)6057ff178cdSJimmy Vetayases apix_intr_thread_prolog(struct cpu *cpu, uint_t pil, caddr_t stackptr)
6067ff178cdSJimmy Vetayases {
6077ff178cdSJimmy Vetayases 	apix_impl_t *apixp = apixs[cpu->cpu_id];
6087ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
6097ff178cdSJimmy Vetayases 	hrtime_t now = tsc_read();
6107ff178cdSJimmy Vetayases 	kthread_t *t, *volatile it;
6117ff178cdSJimmy Vetayases 
6127ff178cdSJimmy Vetayases 	ASSERT(pil > mcpu->mcpu_pri && pil > cpu->cpu_base_spl);
6137ff178cdSJimmy Vetayases 
6147ff178cdSJimmy Vetayases 	apixp->x_intr_pending &= ~(1 << pil);
6157ff178cdSJimmy Vetayases 	ASSERT((cpu->cpu_intr_actv & (1 << pil)) == 0);
6167ff178cdSJimmy Vetayases 	cpu->cpu_intr_actv |= (1 << pil);
6177ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = pil;
6187ff178cdSJimmy Vetayases 
6197ff178cdSJimmy Vetayases 	/*
6207ff178cdSJimmy Vetayases 	 * Get set to run interrupt thread.
6217ff178cdSJimmy Vetayases 	 * There should always be an interrupt thread since we
6227ff178cdSJimmy Vetayases 	 * allocate one for each level on the CPU.
6237ff178cdSJimmy Vetayases 	 */
6247ff178cdSJimmy Vetayases 	/* t_intr_start could be zero due to cpu_intr_swtch_enter. */
6257ff178cdSJimmy Vetayases 	t = cpu->cpu_thread;
6267ff178cdSJimmy Vetayases 	if ((t->t_flag & T_INTR_THREAD) && t->t_intr_start != 0) {
6277ff178cdSJimmy Vetayases 		hrtime_t intrtime = now - t->t_intr_start;
6287ff178cdSJimmy Vetayases 		mcpu->intrstat[pil][0] += intrtime;
6297ff178cdSJimmy Vetayases 		cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
6307ff178cdSJimmy Vetayases 		t->t_intr_start = 0;
6317ff178cdSJimmy Vetayases 	}
6327ff178cdSJimmy Vetayases 
6337ff178cdSJimmy Vetayases 	/*
6347ff178cdSJimmy Vetayases 	 * Push interrupted thread onto list from new thread.
6357ff178cdSJimmy Vetayases 	 * Set the new thread as the current one.
6367ff178cdSJimmy Vetayases 	 * Set interrupted thread's T_SP because if it is the idle thread,
6377ff178cdSJimmy Vetayases 	 * resume() may use that stack between threads.
6387ff178cdSJimmy Vetayases 	 */
6397ff178cdSJimmy Vetayases 
6407ff178cdSJimmy Vetayases 	ASSERT(SA((uintptr_t)stackptr) == (uintptr_t)stackptr);
6417ff178cdSJimmy Vetayases 
6427ff178cdSJimmy Vetayases 	t->t_sp = (uintptr_t)stackptr;	/* mark stack in curthread for resume */
6437ff178cdSJimmy Vetayases 
6447ff178cdSJimmy Vetayases 	/*
6457ff178cdSJimmy Vetayases 	 * Note that the code in kcpc_overflow_intr -relies- on the
6467ff178cdSJimmy Vetayases 	 * ordering of events here - in particular that t->t_lwp of
6477ff178cdSJimmy Vetayases 	 * the interrupt thread is set to the pinned thread *before*
6487ff178cdSJimmy Vetayases 	 * curthread is changed.
6497ff178cdSJimmy Vetayases 	 */
6507ff178cdSJimmy Vetayases 	it = cpu->cpu_intr_thread;
6517ff178cdSJimmy Vetayases 	cpu->cpu_intr_thread = it->t_link;
6527ff178cdSJimmy Vetayases 	it->t_intr = t;
6537ff178cdSJimmy Vetayases 	it->t_lwp = t->t_lwp;
6547ff178cdSJimmy Vetayases 
6557ff178cdSJimmy Vetayases 	/*
6567ff178cdSJimmy Vetayases 	 * (threads on the interrupt thread free list could have state
6577ff178cdSJimmy Vetayases 	 * preset to TS_ONPROC, but it helps in debugging if
6587ff178cdSJimmy Vetayases 	 * they're TS_FREE.)
6597ff178cdSJimmy Vetayases 	 */
6607ff178cdSJimmy Vetayases 	it->t_state = TS_ONPROC;
6617ff178cdSJimmy Vetayases 
6627ff178cdSJimmy Vetayases 	cpu->cpu_thread = it;
6637ff178cdSJimmy Vetayases 
6647ff178cdSJimmy Vetayases 	/*
6657ff178cdSJimmy Vetayases 	 * Initialize thread priority level from intr_pri
6667ff178cdSJimmy Vetayases 	 */
6677ff178cdSJimmy Vetayases 	it->t_pil = (uchar_t)pil;
6687ff178cdSJimmy Vetayases 	it->t_pri = (pri_t)pil + intr_pri;
6697ff178cdSJimmy Vetayases 	it->t_intr_start = now;
6707ff178cdSJimmy Vetayases 
6717ff178cdSJimmy Vetayases 	return (it->t_stk);
6727ff178cdSJimmy Vetayases }
6737ff178cdSJimmy Vetayases 
6747ff178cdSJimmy Vetayases static void
apix_intr_thread_epilog(struct cpu * cpu,uint_t oldpil)6757ff178cdSJimmy Vetayases apix_intr_thread_epilog(struct cpu *cpu, uint_t oldpil)
6767ff178cdSJimmy Vetayases {
6777ff178cdSJimmy Vetayases 	struct machcpu *mcpu = &cpu->cpu_m;
6787ff178cdSJimmy Vetayases 	kthread_t *t, *it = cpu->cpu_thread;
6797ff178cdSJimmy Vetayases 	uint_t pil, basespl;
6807ff178cdSJimmy Vetayases 	hrtime_t intrtime;
6817ff178cdSJimmy Vetayases 	hrtime_t now = tsc_read();
6827ff178cdSJimmy Vetayases 
6837ff178cdSJimmy Vetayases 	pil = it->t_pil;
6847ff178cdSJimmy Vetayases 	cpu->cpu_stats.sys.intr[pil - 1]++;
6857ff178cdSJimmy Vetayases 
6867ff178cdSJimmy Vetayases 	ASSERT(cpu->cpu_intr_actv & (1 << pil));
6877ff178cdSJimmy Vetayases 	cpu->cpu_intr_actv &= ~(1 << pil);
6887ff178cdSJimmy Vetayases 
6897ff178cdSJimmy Vetayases 	ASSERT(it->t_intr_start != 0);
6907ff178cdSJimmy Vetayases 	intrtime = now - it->t_intr_start;
6917ff178cdSJimmy Vetayases 	mcpu->intrstat[pil][0] += intrtime;
6927ff178cdSJimmy Vetayases 	cpu->cpu_intracct[cpu->cpu_mstate] += intrtime;
6937ff178cdSJimmy Vetayases 
6947ff178cdSJimmy Vetayases 	/*
6957ff178cdSJimmy Vetayases 	 * If there is still an interrupted thread underneath this one
6967ff178cdSJimmy Vetayases 	 * then the interrupt was never blocked and the return is
6977ff178cdSJimmy Vetayases 	 * fairly simple.  Otherwise it isn't.
6987ff178cdSJimmy Vetayases 	 */
6997ff178cdSJimmy Vetayases 	if ((t = it->t_intr) == NULL) {
7007ff178cdSJimmy Vetayases 		/*
7017ff178cdSJimmy Vetayases 		 * The interrupted thread is no longer pinned underneath
7027ff178cdSJimmy Vetayases 		 * the interrupt thread.  This means the interrupt must
7037ff178cdSJimmy Vetayases 		 * have blocked, and the interrupted thread has been
7047ff178cdSJimmy Vetayases 		 * unpinned, and has probably been running around the
7057ff178cdSJimmy Vetayases 		 * system for a while.
7067ff178cdSJimmy Vetayases 		 *
7077ff178cdSJimmy Vetayases 		 * Since there is no longer a thread under this one, put
7087ff178cdSJimmy Vetayases 		 * this interrupt thread back on the CPU's free list and
7097ff178cdSJimmy Vetayases 		 * resume the idle thread which will dispatch the next
7107ff178cdSJimmy Vetayases 		 * thread to run.
7117ff178cdSJimmy Vetayases 		 */
7127ff178cdSJimmy Vetayases 		cpu->cpu_stats.sys.intrblk++;
7137ff178cdSJimmy Vetayases 
7147ff178cdSJimmy Vetayases 		/*
7157ff178cdSJimmy Vetayases 		 * Put thread back on the interrupt thread list.
7167ff178cdSJimmy Vetayases 		 * This was an interrupt thread, so set CPU's base SPL.
7177ff178cdSJimmy Vetayases 		 */
7187ff178cdSJimmy Vetayases 		set_base_spl();
7197ff178cdSJimmy Vetayases 		basespl = cpu->cpu_base_spl;
7207ff178cdSJimmy Vetayases 		mcpu->mcpu_pri = basespl;
7217ff178cdSJimmy Vetayases 		(*setlvlx)(basespl, 0);
7227ff178cdSJimmy Vetayases 
7237ff178cdSJimmy Vetayases 		it->t_state = TS_FREE;
7247ff178cdSJimmy Vetayases 		/*
7257ff178cdSJimmy Vetayases 		 * Return interrupt thread to pool
7267ff178cdSJimmy Vetayases 		 */
7277ff178cdSJimmy Vetayases 		it->t_link = cpu->cpu_intr_thread;
7287ff178cdSJimmy Vetayases 		cpu->cpu_intr_thread = it;
7297ff178cdSJimmy Vetayases 
7307ff178cdSJimmy Vetayases 		(void) splhigh();
7317ff178cdSJimmy Vetayases 		sti();
7327ff178cdSJimmy Vetayases 		swtch();
7337ff178cdSJimmy Vetayases 		/*NOTREACHED*/
7347ff178cdSJimmy Vetayases 		panic("dosoftint_epilog: swtch returned");
7357ff178cdSJimmy Vetayases 	}
7367ff178cdSJimmy Vetayases 
7377ff178cdSJimmy Vetayases 	/*
7387ff178cdSJimmy Vetayases 	 * Return interrupt thread to the pool
7397ff178cdSJimmy Vetayases 	 */
7407ff178cdSJimmy Vetayases 	it->t_link = cpu->cpu_intr_thread;
7417ff178cdSJimmy Vetayases 	cpu->cpu_intr_thread = it;
7427ff178cdSJimmy Vetayases 	it->t_state = TS_FREE;
7437ff178cdSJimmy Vetayases 
7447ff178cdSJimmy Vetayases 	cpu->cpu_thread = t;
7457ff178cdSJimmy Vetayases 	if (t->t_flag & T_INTR_THREAD)
7467ff178cdSJimmy Vetayases 		t->t_intr_start = now;
7477ff178cdSJimmy Vetayases 	basespl = cpu->cpu_base_spl;
7487ff178cdSJimmy Vetayases 	mcpu->mcpu_pri = MAX(oldpil, basespl);
7497ff178cdSJimmy Vetayases 	(*setlvlx)(mcpu->mcpu_pri, 0);
7507ff178cdSJimmy Vetayases }
7517ff178cdSJimmy Vetayases 
7527ff178cdSJimmy Vetayases 
7537ff178cdSJimmy Vetayases static void
apix_dispatch_pending_hardint(uint_t oldpil,uint_t arg2)7547ff178cdSJimmy Vetayases apix_dispatch_pending_hardint(uint_t oldpil, uint_t arg2)
7557ff178cdSJimmy Vetayases {
7567ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
7577ff178cdSJimmy Vetayases 
7587ff178cdSJimmy Vetayases 	UNREFERENCED_1PARAMETER(arg2);
7597ff178cdSJimmy Vetayases 
7607ff178cdSJimmy Vetayases 	apix_dispatch_pending_autovect((int)cpu->cpu_thread->t_pil);
7617ff178cdSJimmy Vetayases 
7627ff178cdSJimmy Vetayases 	/*
7637ff178cdSJimmy Vetayases 	 * Must run intr_thread_epilog() on the interrupt thread stack, since
7647ff178cdSJimmy Vetayases 	 * there may not be a return from it if the interrupt thread blocked.
7657ff178cdSJimmy Vetayases 	 */
7667ff178cdSJimmy Vetayases 	apix_intr_thread_epilog(cpu, oldpil);
7677ff178cdSJimmy Vetayases }
7687ff178cdSJimmy Vetayases 
7697ff178cdSJimmy Vetayases static __inline__ int
apix_do_pending_hardint(struct cpu * cpu,struct regs * rp)7707ff178cdSJimmy Vetayases apix_do_pending_hardint(struct cpu *cpu, struct regs *rp)
7717ff178cdSJimmy Vetayases {
7727ff178cdSJimmy Vetayases 	volatile uint16_t pending;
7737ff178cdSJimmy Vetayases 	uint_t newipl, oldipl;
7747ff178cdSJimmy Vetayases 	caddr_t newsp;
7757ff178cdSJimmy Vetayases 
7767ff178cdSJimmy Vetayases 	while ((pending = LOWLEVEL_PENDING(cpu)) != 0) {
7777ff178cdSJimmy Vetayases 		newipl = bsrw_insn(pending);
7787ff178cdSJimmy Vetayases 		ASSERT(newipl <= LOCK_LEVEL);
7797ff178cdSJimmy Vetayases 		oldipl = cpu->cpu_pri;
7807ff178cdSJimmy Vetayases 		if (newipl <= oldipl || newipl <= cpu->cpu_base_spl)
7817ff178cdSJimmy Vetayases 			return (-1);
7827ff178cdSJimmy Vetayases 
7837ff178cdSJimmy Vetayases 		/*
7847ff178cdSJimmy Vetayases 		 * Run this interrupt in a separate thread.
7857ff178cdSJimmy Vetayases 		 */
7867ff178cdSJimmy Vetayases 		newsp = apix_intr_thread_prolog(cpu, newipl, (caddr_t)rp);
7877ff178cdSJimmy Vetayases 		ASSERT(newsp != NULL);
7887ff178cdSJimmy Vetayases 		switch_sp_and_call(newsp, apix_dispatch_pending_hardint,
7897ff178cdSJimmy Vetayases 		    oldipl, 0);
7907ff178cdSJimmy Vetayases 	}
7917ff178cdSJimmy Vetayases 
7927ff178cdSJimmy Vetayases 	return (0);
7937ff178cdSJimmy Vetayases }
7947ff178cdSJimmy Vetayases 
7957ff178cdSJimmy Vetayases /*
7967ff178cdSJimmy Vetayases  * Unmask level triggered interrupts
7977ff178cdSJimmy Vetayases  */
7987ff178cdSJimmy Vetayases static void
apix_post_hardint(int vector)7997ff178cdSJimmy Vetayases apix_post_hardint(int vector)
8007ff178cdSJimmy Vetayases {
8017ff178cdSJimmy Vetayases 	apix_vector_t *vecp = xv_vector(psm_get_cpu_id(), vector);
8027ff178cdSJimmy Vetayases 	int irqno = vecp->v_inum;
8037ff178cdSJimmy Vetayases 
8047ff178cdSJimmy Vetayases 	ASSERT(vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[irqno]);
8057ff178cdSJimmy Vetayases 
8067ff178cdSJimmy Vetayases 	apix_level_intr_post_dispatch(irqno);
8077ff178cdSJimmy Vetayases }
8087ff178cdSJimmy Vetayases 
8097ff178cdSJimmy Vetayases static void
apix_dispatch_by_vector(uint_t vector)8107ff178cdSJimmy Vetayases apix_dispatch_by_vector(uint_t vector)
8117ff178cdSJimmy Vetayases {
8127ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
8137ff178cdSJimmy Vetayases 	apix_vector_t *vecp = xv_vector(cpu->cpu_id, vector);
8147ff178cdSJimmy Vetayases 	struct autovec *avp;
8157ff178cdSJimmy Vetayases 	uint_t r, (*intr)();
8167ff178cdSJimmy Vetayases 	caddr_t arg1, arg2;
8177ff178cdSJimmy Vetayases 	dev_info_t *dip;
8187ff178cdSJimmy Vetayases 
8197ff178cdSJimmy Vetayases 	if (vecp == NULL ||
8207ff178cdSJimmy Vetayases 	    (avp = vecp->v_autovect) == NULL || avp->av_vector == NULL)
8217ff178cdSJimmy Vetayases 		return;
8227ff178cdSJimmy Vetayases 
8237ff178cdSJimmy Vetayases 	avp->av_flags |= AV_PENTRY_ONPROC;
8247ff178cdSJimmy Vetayases 	intr = avp->av_vector;
8257ff178cdSJimmy Vetayases 	arg1 = avp->av_intarg1;
8267ff178cdSJimmy Vetayases 	arg2 = avp->av_intarg2;
8277ff178cdSJimmy Vetayases 	dip = avp->av_dip;
8287ff178cdSJimmy Vetayases 
8297ff178cdSJimmy Vetayases 	if (avp->av_prilevel != XC_HI_PIL)
8307ff178cdSJimmy Vetayases 		sti();
8317ff178cdSJimmy Vetayases 
8327ff178cdSJimmy Vetayases 	DTRACE_PROBE4(interrupt__start, dev_info_t *, dip,
8337ff178cdSJimmy Vetayases 	    void *, intr, caddr_t, arg1, caddr_t, arg2);
8347ff178cdSJimmy Vetayases 	r = (*intr)(arg1, arg2);
8357ff178cdSJimmy Vetayases 	DTRACE_PROBE4(interrupt__complete, dev_info_t *, dip,
8367ff178cdSJimmy Vetayases 	    void *, intr, caddr_t, arg1, uint_t, r);
8377ff178cdSJimmy Vetayases 
8387ff178cdSJimmy Vetayases 	cli();
8397ff178cdSJimmy Vetayases 	avp->av_flags &= ~AV_PENTRY_ONPROC;
8407ff178cdSJimmy Vetayases }
8417ff178cdSJimmy Vetayases 
8427ff178cdSJimmy Vetayases 
8437ff178cdSJimmy Vetayases static void
apix_dispatch_hilevel(uint_t vector,uint_t arg2)8447ff178cdSJimmy Vetayases apix_dispatch_hilevel(uint_t vector, uint_t arg2)
8457ff178cdSJimmy Vetayases {
8467ff178cdSJimmy Vetayases 	UNREFERENCED_1PARAMETER(arg2);
8477ff178cdSJimmy Vetayases 
8487ff178cdSJimmy Vetayases 	apix_dispatch_by_vector(vector);
8497ff178cdSJimmy Vetayases }
8507ff178cdSJimmy Vetayases 
8517ff178cdSJimmy Vetayases static void
apix_dispatch_lowlevel(uint_t vector,uint_t oldipl)8527ff178cdSJimmy Vetayases apix_dispatch_lowlevel(uint_t vector, uint_t oldipl)
8537ff178cdSJimmy Vetayases {
8547ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
8557ff178cdSJimmy Vetayases 
8567ff178cdSJimmy Vetayases 	apix_dispatch_by_vector(vector);
8577ff178cdSJimmy Vetayases 
8587ff178cdSJimmy Vetayases 	/*
8597ff178cdSJimmy Vetayases 	 * Must run intr_thread_epilog() on the interrupt thread stack, since
8607ff178cdSJimmy Vetayases 	 * there may not be a return from it if the interrupt thread blocked.
8617ff178cdSJimmy Vetayases 	 */
8627ff178cdSJimmy Vetayases 	apix_intr_thread_epilog(cpu, oldipl);
8637ff178cdSJimmy Vetayases }
8647ff178cdSJimmy Vetayases 
865*636dfb4bSJerry Jelinek /*
866*636dfb4bSJerry Jelinek  * Interrupt service routine, called with interrupts disabled.
867*636dfb4bSJerry Jelinek  */
8687ff178cdSJimmy Vetayases void
apix_do_interrupt(struct regs * rp,trap_trace_rec_t * ttp)8697ff178cdSJimmy Vetayases apix_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp)
8707ff178cdSJimmy Vetayases {
8717ff178cdSJimmy Vetayases 	struct cpu *cpu = CPU;
8727ff178cdSJimmy Vetayases 	int vector = rp->r_trapno, newipl, oldipl = cpu->cpu_pri, ret;
8737ff178cdSJimmy Vetayases 	apix_vector_t *vecp = NULL;
8747ff178cdSJimmy Vetayases 
8757ff178cdSJimmy Vetayases #ifdef TRAPTRACE
8767ff178cdSJimmy Vetayases 	ttp->ttr_marker = TT_INTERRUPT;
8777ff178cdSJimmy Vetayases 	ttp->ttr_cpuid = cpu->cpu_id;
8787ff178cdSJimmy Vetayases 	ttp->ttr_ipl = 0xff;
8797ff178cdSJimmy Vetayases 	ttp->ttr_pri = (uchar_t)oldipl;
8807ff178cdSJimmy Vetayases 	ttp->ttr_spl = cpu->cpu_base_spl;
8817ff178cdSJimmy Vetayases 	ttp->ttr_vector = 0xff;
8827ff178cdSJimmy Vetayases #endif	/* TRAPTRACE */
8837ff178cdSJimmy Vetayases 
8847ff178cdSJimmy Vetayases 	cpu_idle_exit(CPU_IDLE_CB_FLAG_INTR);
8857ff178cdSJimmy Vetayases 
8867ff178cdSJimmy Vetayases 	++*(uint16_t *)&cpu->cpu_m.mcpu_istamp;
8877ff178cdSJimmy Vetayases 
8887ff178cdSJimmy Vetayases 	/*
8897ff178cdSJimmy Vetayases 	 * If it's a softint go do it now.
8907ff178cdSJimmy Vetayases 	 */
8917ff178cdSJimmy Vetayases 	if (rp->r_trapno == T_SOFTINT) {
8927ff178cdSJimmy Vetayases 		/*
8937ff178cdSJimmy Vetayases 		 * It might be the case that when an interrupt is triggered,
8947ff178cdSJimmy Vetayases 		 * the spl is raised to high by splhigh(). Later when do_splx()
8957ff178cdSJimmy Vetayases 		 * is called to restore the spl, both hardware and software
8967ff178cdSJimmy Vetayases 		 * interrupt pending flags are check and an SOFTINT is faked
8977ff178cdSJimmy Vetayases 		 * accordingly.
8987ff178cdSJimmy Vetayases 		 */
8997ff178cdSJimmy Vetayases 		(void) apix_do_pending_hilevel(cpu, rp);
9007ff178cdSJimmy Vetayases 		(void) apix_do_pending_hardint(cpu, rp);
9017ff178cdSJimmy Vetayases 		(void) apix_do_softint(rp);
9027ff178cdSJimmy Vetayases 		ASSERT(!interrupts_enabled());
9037ff178cdSJimmy Vetayases #ifdef TRAPTRACE
9047ff178cdSJimmy Vetayases 	ttp->ttr_vector = T_SOFTINT;
9057ff178cdSJimmy Vetayases #endif
9067ff178cdSJimmy Vetayases 		return;
9077ff178cdSJimmy Vetayases 	}
9087ff178cdSJimmy Vetayases 
9097ff178cdSJimmy Vetayases 	/*
910*636dfb4bSJerry Jelinek 	 * Send EOI to local APIC
9117ff178cdSJimmy Vetayases 	 */
9127ff178cdSJimmy Vetayases 	newipl = (*setlvl)(oldipl, (int *)&rp->r_trapno);
9137ff178cdSJimmy Vetayases #ifdef TRAPTRACE
9147ff178cdSJimmy Vetayases 	ttp->ttr_ipl = (uchar_t)newipl;
9157ff178cdSJimmy Vetayases #endif	/* TRAPTRACE */
9167ff178cdSJimmy Vetayases 
9177ff178cdSJimmy Vetayases 	/*
9187ff178cdSJimmy Vetayases 	 * Bail if it is a spurious interrupt
9197ff178cdSJimmy Vetayases 	 */
9207ff178cdSJimmy Vetayases 	if (newipl == -1)
9217ff178cdSJimmy Vetayases 		return;
9227ff178cdSJimmy Vetayases 
9237ff178cdSJimmy Vetayases 	vector = rp->r_trapno;
9247ff178cdSJimmy Vetayases 	vecp = xv_vector(cpu->cpu_id, vector);
9257ff178cdSJimmy Vetayases #ifdef TRAPTRACE
9267ff178cdSJimmy Vetayases 	ttp->ttr_vector = (short)vector;
9277ff178cdSJimmy Vetayases #endif	/* TRAPTRACE */
9287ff178cdSJimmy Vetayases 
9297ff178cdSJimmy Vetayases 	/*
9307ff178cdSJimmy Vetayases 	 * Direct dispatch for IPI, MSI, MSI-X
9317ff178cdSJimmy Vetayases 	 */
9327ff178cdSJimmy Vetayases 	if (vecp && vecp->v_type != APIX_TYPE_FIXED &&
9337ff178cdSJimmy Vetayases 	    newipl > MAX(oldipl, cpu->cpu_base_spl)) {
9347ff178cdSJimmy Vetayases 		caddr_t newsp;
9357ff178cdSJimmy Vetayases 
9367ff178cdSJimmy Vetayases 		if (newipl > LOCK_LEVEL) {
9377ff178cdSJimmy Vetayases 			if (apix_hilevel_intr_prolog(cpu, newipl, oldipl, rp)
9387ff178cdSJimmy Vetayases 			    == 0) {
9397ff178cdSJimmy Vetayases 				newsp = cpu->cpu_intr_stack;
9407ff178cdSJimmy Vetayases 				switch_sp_and_call(newsp, apix_dispatch_hilevel,
9417ff178cdSJimmy Vetayases 				    vector, 0);
9427ff178cdSJimmy Vetayases 			} else {
9437ff178cdSJimmy Vetayases 				apix_dispatch_hilevel(vector, 0);
9447ff178cdSJimmy Vetayases 			}
9457ff178cdSJimmy Vetayases 			(void) apix_hilevel_intr_epilog(cpu, oldipl);
9467ff178cdSJimmy Vetayases 		} else {
9477ff178cdSJimmy Vetayases 			newsp = apix_intr_thread_prolog(cpu, newipl,
9487ff178cdSJimmy Vetayases 			    (caddr_t)rp);
9497ff178cdSJimmy Vetayases 			switch_sp_and_call(newsp, apix_dispatch_lowlevel,
9507ff178cdSJimmy Vetayases 			    vector, oldipl);
9517ff178cdSJimmy Vetayases 		}
9527ff178cdSJimmy Vetayases 	} else {
9537ff178cdSJimmy Vetayases 		/* Add to per-pil pending queue */
9547ff178cdSJimmy Vetayases 		apix_add_pending_hardint(vector);
9557ff178cdSJimmy Vetayases 		if (newipl <= MAX(oldipl, cpu->cpu_base_spl) ||
9567ff178cdSJimmy Vetayases 		    !apixs[cpu->cpu_id]->x_intr_pending)
9577ff178cdSJimmy Vetayases 			return;
9587ff178cdSJimmy Vetayases 	}
9597ff178cdSJimmy Vetayases 
9607ff178cdSJimmy Vetayases 	if (apix_do_pending_hilevel(cpu, rp) < 0)
9617ff178cdSJimmy Vetayases 		return;
9627ff178cdSJimmy Vetayases 
9637ff178cdSJimmy Vetayases 	do {
9647ff178cdSJimmy Vetayases 		ret = apix_do_pending_hardint(cpu, rp);
9657ff178cdSJimmy Vetayases 
9667ff178cdSJimmy Vetayases 		/*
9677ff178cdSJimmy Vetayases 		 * Deliver any pending soft interrupts.
9687ff178cdSJimmy Vetayases 		 */
9697ff178cdSJimmy Vetayases 		(void) apix_do_softint(rp);
9707ff178cdSJimmy Vetayases 	} while (!ret && LOWLEVEL_PENDING(cpu));
9717ff178cdSJimmy Vetayases }
972