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