6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / uts / sun4 / io / ivintr.c
blobd62a2fa7869c3203b002feb1fe36a9f33e0baea5
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Interrupt Vector Table Configuration
32 #include <sys/types.h>
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>
41 * Allocate an Interrupt Vector Table and some interrupt vector data structures
42 * for the reserved pool as part of the startup code. First try to allocate an
43 * interrupt vector data structure from the reserved pool, otherwise allocate it
44 * using kmem cache method.
46 static kmutex_t intr_vec_mutex; /* Protect interrupt vector table */
49 * Global softint linked list - used by softint mdb dcmd.
51 static kmutex_t softint_mutex; /* Protect global softint linked list */
52 intr_vec_t *softint_list = NULL;
54 /* Reserved pool for interrupt allocation */
55 intr_vec_t *intr_vec_pool = NULL; /* For HW and single target SW intrs */
56 intr_vecx_t *intr_vecx_pool = NULL; /* For multi target SW intrs */
57 static kmutex_t intr_vec_pool_mutex; /* Protect interrupt vector pool */
59 /* Kmem cache handle for interrupt allocation */
60 kmem_cache_t *intr_vec_cache = NULL; /* For HW and single target SW intrs */
63 * init_ivintr() - Initialize an Interrupt Vector Table.
65 void
66 init_ivintr()
68 mutex_init(&intr_vec_mutex, NULL, MUTEX_DRIVER, NULL);
69 mutex_init(&softint_mutex, NULL, MUTEX_DRIVER, NULL);
70 mutex_init(&intr_vec_pool_mutex, NULL, MUTEX_DRIVER, NULL);
73 * Initialize the reserved interrupt vector data structure pools
74 * used for hardware and software interrupts.
76 intr_vec_pool = (intr_vec_t *)((caddr_t)intr_vec_table +
77 (MAXIVNUM * sizeof (intr_vec_t *)));
78 intr_vecx_pool = (intr_vecx_t *)((caddr_t)intr_vec_pool +
79 (MAX_RSVD_IV * sizeof (intr_vec_t)));
81 bzero(intr_vec_table, MAXIVNUM * sizeof (intr_vec_t *));
82 bzero(intr_vec_pool, MAX_RSVD_IV * sizeof (intr_vec_t));
83 bzero(intr_vecx_pool, MAX_RSVD_IVX * sizeof (intr_vecx_t));
87 * fini_ivintr() - Uninitialize an Interrupt Vector Table.
89 void
90 fini_ivintr()
92 if (intr_vec_cache)
93 kmem_cache_destroy(intr_vec_cache);
95 mutex_destroy(&intr_vec_pool_mutex);
96 mutex_destroy(&softint_mutex);
97 mutex_destroy(&intr_vec_mutex);
101 * iv_alloc() - Allocate an interrupt vector data structure.
103 * This function allocates an interrupt vector data structure for hardware
104 * and single or multi target software interrupts either from the reserved
105 * pool or using kmem cache method.
107 static intr_vec_t *
108 iv_alloc(softint_type_t type)
110 intr_vec_t *iv_p;
111 int i, count;
113 count = (type == SOFTINT_MT) ? MAX_RSVD_IVX : MAX_RSVD_IV;
116 * First try to allocate an interrupt vector data structure from the
117 * reserved pool, otherwise allocate it using kmem_cache_alloc().
119 mutex_enter(&intr_vec_pool_mutex);
120 for (i = 0; i < count; i++) {
121 iv_p = (type == SOFTINT_MT) ?
122 (intr_vec_t *)&intr_vecx_pool[i] : &intr_vec_pool[i];
124 if (iv_p->iv_pil == 0) {
125 iv_p->iv_pil = 1; /* Default PIL */
126 break;
129 mutex_exit(&intr_vec_pool_mutex);
131 if (i < count)
132 return (iv_p);
134 if (type == SOFTINT_MT)
135 cmn_err(CE_PANIC, "iv_alloc: exceeded number of multi "
136 "target software interrupts, %d", MAX_RSVD_IVX);
139 * If the interrupt vector data structure reserved pool is already
140 * exhausted, then allocate an interrupt vector data structure using
141 * kmem_cache_alloc(), but only for the hardware and single software
142 * interrupts. Create a kmem cache for the interrupt allocation,
143 * if it is not already available.
145 if (intr_vec_cache == NULL)
146 intr_vec_cache = kmem_cache_create("intr_vec_cache",
147 sizeof (intr_vec_t), 64, NULL, NULL, NULL, NULL, NULL, 0);
149 iv_p = kmem_cache_alloc(intr_vec_cache, KM_SLEEP);
150 bzero(iv_p, sizeof (intr_vec_t));
151 iv_p->iv_flags = IV_CACHE_ALLOC;
153 return (iv_p);
157 * iv_free() - Free an interrupt vector data structure.
159 static void
160 iv_free(intr_vec_t *iv_p)
162 if (iv_p->iv_flags & IV_CACHE_ALLOC) {
163 ASSERT(!(iv_p->iv_flags & IV_SOFTINT_MT));
164 kmem_cache_free(intr_vec_cache, iv_p);
165 } else {
166 mutex_enter(&intr_vec_pool_mutex);
167 bzero(iv_p, (iv_p->iv_flags & IV_SOFTINT_MT) ?
168 sizeof (intr_vecx_t) : sizeof (intr_vec_t));
169 mutex_exit(&intr_vec_pool_mutex);
174 * add_ivintr() - Add an interrupt handler to the system
177 add_ivintr(uint_t inum, uint_t pil, intrfunc intr_handler,
178 caddr_t intr_arg1, caddr_t intr_arg2, caddr_t intr_payload)
180 intr_vec_t *iv_p, *new_iv_p;
182 if (inum >= MAXIVNUM || pil > PIL_MAX)
183 return (EINVAL);
185 ASSERT((uintptr_t)intr_handler > KERNELBASE);
187 /* Make sure the payload buffer address is 64 bit aligned */
188 VERIFY(((uint64_t)intr_payload & 0x7) == 0);
190 new_iv_p = iv_alloc(SOFTINT_ST);
191 mutex_enter(&intr_vec_mutex);
193 for (iv_p = (intr_vec_t *)intr_vec_table[inum];
194 iv_p; iv_p = iv_p->iv_vec_next) {
195 if (iv_p->iv_pil == pil) {
196 mutex_exit(&intr_vec_mutex);
197 iv_free(new_iv_p);
198 return (EINVAL);
202 ASSERT(iv_p == NULL);
204 new_iv_p->iv_handler = intr_handler;
205 new_iv_p->iv_arg1 = intr_arg1;
206 new_iv_p->iv_arg2 = intr_arg2;
207 new_iv_p->iv_payload_buf = intr_payload;
208 new_iv_p->iv_pil = (ushort_t)pil;
209 new_iv_p->iv_inum = inum;
211 new_iv_p->iv_vec_next = (intr_vec_t *)intr_vec_table[inum];
212 intr_vec_table[inum] = (uint64_t)new_iv_p;
214 mutex_exit(&intr_vec_mutex);
215 return (0);
219 * rem_ivintr() - Remove an interrupt handler from the system
222 rem_ivintr(uint_t inum, uint_t pil)
224 intr_vec_t *iv_p, *prev_iv_p;
226 if (inum >= MAXIVNUM || pil > PIL_MAX)
227 return (EINVAL);
229 mutex_enter(&intr_vec_mutex);
231 for (iv_p = prev_iv_p = (intr_vec_t *)intr_vec_table[inum];
232 iv_p; prev_iv_p = iv_p, iv_p = iv_p->iv_vec_next)
233 if (iv_p->iv_pil == pil)
234 break;
236 if (iv_p == NULL) {
237 mutex_exit(&intr_vec_mutex);
238 return (EIO);
241 ASSERT(iv_p->iv_pil_next == NULL);
243 if (prev_iv_p == iv_p)
244 intr_vec_table[inum] = (uint64_t)iv_p->iv_vec_next;
245 else
246 prev_iv_p->iv_vec_next = iv_p->iv_vec_next;
248 mutex_exit(&intr_vec_mutex);
250 iv_free(iv_p);
251 return (0);
255 * add_softintr() - add a software interrupt handler to the system
257 uint64_t
258 add_softintr(uint_t pil, softintrfunc intr_handler, caddr_t intr_arg1,
259 softint_type_t type)
261 intr_vec_t *iv_p;
263 if (pil > PIL_MAX)
264 return (NULL);
266 iv_p = iv_alloc(type);
268 iv_p->iv_handler = (intrfunc)intr_handler;
269 iv_p->iv_arg1 = intr_arg1;
270 iv_p->iv_pil = (ushort_t)pil;
271 if (type == SOFTINT_MT)
272 iv_p->iv_flags |= IV_SOFTINT_MT;
274 mutex_enter(&softint_mutex);
275 if (softint_list)
276 iv_p->iv_vec_next = softint_list;
277 softint_list = iv_p;
278 mutex_exit(&softint_mutex);
280 return ((uint64_t)iv_p);
284 * rem_softintr() - remove a software interrupt handler from the system
287 rem_softintr(uint64_t softint_id)
289 intr_vec_t *iv_p = (intr_vec_t *)softint_id;
291 ASSERT(iv_p != NULL);
293 if (iv_p->iv_flags & IV_SOFTINT_PEND)
294 return (EIO);
296 ASSERT(iv_p->iv_pil_next == NULL);
298 mutex_enter(&softint_mutex);
299 if (softint_list == iv_p) {
300 softint_list = iv_p->iv_vec_next;
301 } else {
302 intr_vec_t *list = softint_list;
304 while (list && (list->iv_vec_next != iv_p))
305 list = list->iv_vec_next;
307 list->iv_vec_next = iv_p->iv_vec_next;
309 mutex_exit(&softint_mutex);
311 iv_free(iv_p);
312 return (0);
316 * update_softint_arg2() - Update softint arg2.
318 * NOTE: Do not grab any mutex in this function since it may get called
319 * from the high-level interrupt context.
322 update_softint_arg2(uint64_t softint_id, caddr_t intr_arg2)
324 intr_vec_t *iv_p = (intr_vec_t *)softint_id;
326 ASSERT(iv_p != NULL);
328 if (iv_p->iv_flags & IV_SOFTINT_PEND)
329 return (EIO);
331 iv_p->iv_arg2 = intr_arg2;
332 return (0);
336 * update_softint_pri() - Update softint priority.
339 update_softint_pri(uint64_t softint_id, uint_t pil)
341 intr_vec_t *iv_p = (intr_vec_t *)softint_id;
343 ASSERT(iv_p != NULL);
345 if (pil > PIL_MAX)
346 return (EINVAL);
348 iv_p->iv_pil = pil;
349 return (0);