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