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