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