1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Interrupt Vector Table Configuration 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate /* 42*7c478bd9Sstevel@tonic-gate * fill in an interrupt vector entry 43*7c478bd9Sstevel@tonic-gate */ 44*7c478bd9Sstevel@tonic-gate #define fill_intr(a, b, c, d, e) \ 45*7c478bd9Sstevel@tonic-gate a->iv_pil = b; a->iv_pending = 0; \ 46*7c478bd9Sstevel@tonic-gate a->iv_arg = d; a->iv_handler = c; a->iv_payload_buf = e; 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * create a null interrupt handler entry used for returned values 50*7c478bd9Sstevel@tonic-gate * only - never on intr_vector[] 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate #define nullify_intr(v) fill_intr(v, 0, NULL, NULL, NULL) 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* 55*7c478bd9Sstevel@tonic-gate * replace an intr_vector[] entry with a default set of values 56*7c478bd9Sstevel@tonic-gate * this is done instead of nulling the entry, so the handler and 57*7c478bd9Sstevel@tonic-gate * pil are always valid for the assembler code 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate #define empty_intr(v) fill_intr((v), PIL_MAX, nohandler, \ 60*7c478bd9Sstevel@tonic-gate (void *)(v), NULL) 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate * test whether an intr_vector[] entry points to our default handler 64*7c478bd9Sstevel@tonic-gate */ 65*7c478bd9Sstevel@tonic-gate #define intr_is_empty(v) ((v)->iv_handler == nohandler) 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate extern uint_t swinum_base; 68*7c478bd9Sstevel@tonic-gate extern uint_t maxswinum; 69*7c478bd9Sstevel@tonic-gate extern kmutex_t soft_iv_lock; 70*7c478bd9Sstevel@tonic-gate int ignore_invalid_vecintr = 0; 71*7c478bd9Sstevel@tonic-gate uint64_t invalid_vecintr_count = 0; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * default (non-)handler for otherwise unhandled interrupts 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate uint_t 77*7c478bd9Sstevel@tonic-gate nohandler(caddr_t ivptr) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate if (!ignore_invalid_vecintr) { 80*7c478bd9Sstevel@tonic-gate ASSERT((struct intr_vector *)ivptr - intr_vector < MAXIVNUM); 81*7c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 82*7c478bd9Sstevel@tonic-gate } else { 83*7c478bd9Sstevel@tonic-gate invalid_vecintr_count++; 84*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 85*7c478bd9Sstevel@tonic-gate } 86*7c478bd9Sstevel@tonic-gate } 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * initialization - fill the entire table with default values 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate void 92*7c478bd9Sstevel@tonic-gate init_ivintr(void) 93*7c478bd9Sstevel@tonic-gate { 94*7c478bd9Sstevel@tonic-gate struct intr_vector *inump; 95*7c478bd9Sstevel@tonic-gate int i; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate for (inump = intr_vector, i = 0; i <= MAXIVNUM; ++inump, ++i) { 98*7c478bd9Sstevel@tonic-gate empty_intr(inump); 99*7c478bd9Sstevel@tonic-gate } 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * add_ivintr() - add an interrupt handler to the system 104*7c478bd9Sstevel@tonic-gate * This routine is not protected by the lock; it's the caller's 105*7c478bd9Sstevel@tonic-gate * responsibility to make sure <source>_INR.INT_EN = 0 106*7c478bd9Sstevel@tonic-gate * and <source>_ISM != PENDING before the routine is called. 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate int 109*7c478bd9Sstevel@tonic-gate add_ivintr(uint_t inum, uint_t pil, intrfunc intr_handler, 110*7c478bd9Sstevel@tonic-gate caddr_t intr_arg, caddr_t intr_payload) 111*7c478bd9Sstevel@tonic-gate { 112*7c478bd9Sstevel@tonic-gate struct intr_vector *inump; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate if (inum >= MAXIVNUM || pil > PIL_MAX) 115*7c478bd9Sstevel@tonic-gate return (EINVAL); 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)intr_handler > KERNELBASE); 118*7c478bd9Sstevel@tonic-gate /* Make sure the payload buffer address is 64 bit aligned */ 119*7c478bd9Sstevel@tonic-gate VERIFY(((uint64_t)intr_payload & 0x7) == 0); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate inump = &intr_vector[inum]; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate if (inump->iv_handler != nohandler) 124*7c478bd9Sstevel@tonic-gate return (EINVAL); 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate fill_intr(inump, (ushort_t)pil, intr_handler, intr_arg, intr_payload); 127*7c478bd9Sstevel@tonic-gate return (0); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate * rem_ivintr() - remove an interrupt handler from intr_vector[] 132*7c478bd9Sstevel@tonic-gate * This routine is not protected by the lock; it's the caller's 133*7c478bd9Sstevel@tonic-gate * responsibility to make sure <source>_INR.INT_EN = 0 134*7c478bd9Sstevel@tonic-gate * and <source>_ISM != PENDING before the routine is called. 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate void 137*7c478bd9Sstevel@tonic-gate rem_ivintr(uint_t inum, struct intr_vector *iv_return) 138*7c478bd9Sstevel@tonic-gate { 139*7c478bd9Sstevel@tonic-gate struct intr_vector *inump; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate ASSERT(inum != NULL && inum < MAXIVNUM); 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate inump = &intr_vector[inum]; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate if (iv_return) { 146*7c478bd9Sstevel@tonic-gate if (intr_is_empty(inump)) { 147*7c478bd9Sstevel@tonic-gate nullify_intr(iv_return); 148*7c478bd9Sstevel@tonic-gate } else { 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * the caller requires the current entry to be 151*7c478bd9Sstevel@tonic-gate * returned 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate fill_intr(iv_return, inump->iv_pil, 154*7c478bd9Sstevel@tonic-gate inump->iv_handler, inump->iv_arg, 155*7c478bd9Sstevel@tonic-gate inump->iv_payload_buf); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* 160*7c478bd9Sstevel@tonic-gate * empty the current entry 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate empty_intr(inump); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * add_softintr() - add a software interrupt handler to the system 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate uint_t 169*7c478bd9Sstevel@tonic-gate add_softintr(uint_t pil, softintrfunc intr_handler, caddr_t intr_arg) 170*7c478bd9Sstevel@tonic-gate { 171*7c478bd9Sstevel@tonic-gate struct intr_vector *inump; 172*7c478bd9Sstevel@tonic-gate register uint_t i; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate mutex_enter(&soft_iv_lock); 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate for (i = swinum_base; i < maxswinum; i++) { 177*7c478bd9Sstevel@tonic-gate inump = &intr_vector[i]; 178*7c478bd9Sstevel@tonic-gate if (intr_is_empty(inump)) 179*7c478bd9Sstevel@tonic-gate break; 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (!intr_is_empty(inump)) { 183*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "add_softintr: exceeded %d handlers", 184*7c478bd9Sstevel@tonic-gate maxswinum - swinum_base); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate VERIFY(add_ivintr(i, pil, (intrfunc)intr_handler, 188*7c478bd9Sstevel@tonic-gate intr_arg, NULL) == 0); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate mutex_exit(&soft_iv_lock); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate return (i); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * rem_softintr() - remove a software interrupt handler from the system 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate void 199*7c478bd9Sstevel@tonic-gate rem_softintr(uint_t inum) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate ASSERT(swinum_base <= inum && inum < MAXIVNUM); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate mutex_enter(&soft_iv_lock); 204*7c478bd9Sstevel@tonic-gate rem_ivintr(inum, NULL); 205*7c478bd9Sstevel@tonic-gate mutex_exit(&soft_iv_lock); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate int 209*7c478bd9Sstevel@tonic-gate update_softint_arg2(uint_t intr_id, caddr_t arg2) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate struct intr_vector *inump = &intr_vector[intr_id]; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate if (inump->iv_pending) 214*7c478bd9Sstevel@tonic-gate return (DDI_EPENDING); 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate inump->iv_softint_arg2 = arg2; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate int 222*7c478bd9Sstevel@tonic-gate update_softint_pri(uint_t intr_id, int pri) 223*7c478bd9Sstevel@tonic-gate { 224*7c478bd9Sstevel@tonic-gate struct intr_vector *inump = &intr_vector[intr_id]; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate mutex_enter(&soft_iv_lock); 227*7c478bd9Sstevel@tonic-gate inump->iv_pil = pri; 228*7c478bd9Sstevel@tonic-gate mutex_exit(&soft_iv_lock); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 231*7c478bd9Sstevel@tonic-gate } 232