xref: /illumos-gate/usr/src/uts/sun4/io/ivintr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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