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