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